[vulkan] Adjusting XFB configuration + StreamingByteCount adjustments

This commit is contained in:
CamilleLaVey 2026-03-13 19:17:50 -04:00
parent 46c2a81f4a
commit d835cab32d
3 changed files with 37 additions and 23 deletions

View file

@ -1064,13 +1064,23 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
if (maxwell3d->regs.transform_feedback_enabled == 0) { if (maxwell3d->regs.transform_feedback_enabled == 0) {
return; return;
} }
HostBindings<typename P::Buffer> host_bindings; Buffer& null_buffer = slot_buffers[NULL_BUFFER_ID];
bool reached_end = false;
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) { for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
const Binding& binding = channel_state->transform_feedback_buffers[index]; const auto& control = maxwell3d->regs.transform_feedback.controls[index];
if (maxwell3d->regs.transform_feedback.controls[index].varying_count == 0 && if (reached_end ||
maxwell3d->regs.transform_feedback.controls[index].stride == 0) { (control.varying_count == 0 && control.stride == 0)) {
break; reached_end = true;
runtime.BindTransformFeedbackBuffer(index, null_buffer, 0, 0);
continue;
} }
const Binding& binding = channel_state->transform_feedback_buffers[index];
if (binding.size == 0 || binding.buffer_id == NULL_BUFFER_ID) {
runtime.BindTransformFeedbackBuffer(index, null_buffer, 0, 0);
continue;
}
Buffer& buffer = slot_buffers[binding.buffer_id]; Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id); TouchBuffer(buffer, binding.buffer_id);
const u32 size = binding.size; const u32 size = binding.size;
@ -1080,12 +1090,7 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
const u32 offset = buffer.Offset(binding.device_addr); const u32 offset = buffer.Offset(binding.device_addr);
buffer.MarkUsage(offset, size); buffer.MarkUsage(offset, size);
host_bindings.buffers.push_back(&buffer); runtime.BindTransformFeedbackBuffer(index, buffer, offset, size);
host_bindings.offsets.push_back(offset);
host_bindings.sizes.push_back(size);
}
if (host_bindings.buffers.size() > 0) {
runtime.BindTransformFeedbackBuffers(host_bindings);
} }
} }

View file

@ -127,6 +127,9 @@ public:
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings); void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
void BindTransformFeedbackBuffer(u32 index, Buffer& buffer, u32 offset, u32 size) {
BindTransformFeedbackBuffer(index, buffer.Handle(), offset, size);
}
void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size); void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size);

View file

@ -717,7 +717,7 @@ public:
counter_buffers.fill(VK_NULL_HANDLE); counter_buffers.fill(VK_NULL_HANDLE);
offsets.fill(0); offsets.fill(0);
last_queries.fill(0); last_queries.fill(0);
last_queries_stride.fill(1); last_queries_stride.fill(0);
const VkBufferCreateInfo buffer_ci = { const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@ -913,14 +913,16 @@ private:
has_flushed_end_pending = true; has_flushed_end_pending = true;
// Refresh buffers state before beginning transform feedback so counters are up-to-date // Refresh buffers state before beginning transform feedback so counters are up-to-date
UpdateBuffers(); UpdateBuffers();
if (!has_started || buffers_count == 0) { active_buffers_count = has_started ? buffers_count : 0;
if (active_buffers_count == 0) {
// No counter buffers available: begin without counters // No counter buffers available: begin without counters
scheduler.Record([](vk::CommandBuffer cmdbuf) { scheduler.Record([](vk::CommandBuffer cmdbuf) {
cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr); cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr);
}); });
return; return;
} }
scheduler.Record([this, total = static_cast<u32>(buffers_count)](vk::CommandBuffer cmdbuf) { scheduler.Record(
[this, total = static_cast<u32>(active_buffers_count)](vk::CommandBuffer cmdbuf) {
cmdbuf.BeginTransformFeedbackEXT(0, total, counter_buffers.data(), offsets.data()); cmdbuf.BeginTransformFeedbackEXT(0, total, counter_buffers.data(), offsets.data());
}); });
} }
@ -931,23 +933,27 @@ private:
return; return;
} }
has_flushed_end_pending = false; has_flushed_end_pending = false;
if (buffers_count == 0) { if (active_buffers_count == 0) {
LOG_DEBUG(Render_Vulkan, "EndTransformFeedbackEXT called with no counters (buffers_count=0)"); LOG_DEBUG(Render_Vulkan,
"EndTransformFeedbackEXT called with no counters (active_buffers_count=0)");
scheduler.Record([](vk::CommandBuffer cmdbuf) { scheduler.Record([](vk::CommandBuffer cmdbuf) {
cmdbuf.EndTransformFeedbackEXT(0, 0, nullptr, nullptr); cmdbuf.EndTransformFeedbackEXT(0, 0, nullptr, nullptr);
}); });
} else { } else {
LOG_DEBUG(Render_Vulkan, "EndTransformFeedbackEXT called with counters (buffers_count={})", buffers_count); LOG_DEBUG(Render_Vulkan,
"EndTransformFeedbackEXT called with counters (active_buffers_count={})",
active_buffers_count);
scheduler.Record([this, scheduler.Record([this,
total = static_cast<u32>(buffers_count)](vk::CommandBuffer cmdbuf) { total = static_cast<u32>(active_buffers_count)](vk::CommandBuffer cmdbuf) {
cmdbuf.EndTransformFeedbackEXT(0, total, counter_buffers.data(), offsets.data()); cmdbuf.EndTransformFeedbackEXT(0, total, counter_buffers.data(), offsets.data());
}); });
} }
active_buffers_count = 0;
} }
void UpdateBuffers() { void UpdateBuffers() {
last_queries.fill(0); last_queries.fill(0);
last_queries_stride.fill(1); last_queries_stride.fill(0);
streams_mask = 0; // reset previously recorded streams streams_mask = 0; // reset previously recorded streams
runtime.View3DRegs([this](Maxwell3D& maxwell3d) { runtime.View3DRegs([this](Maxwell3D& maxwell3d) {
buffers_count = 0; buffers_count = 0;
@ -962,7 +968,7 @@ private:
LOG_WARNING(Render_Vulkan, "TransformFeedback stream {} out of range", stream); LOG_WARNING(Render_Vulkan, "TransformFeedback stream {} out of range", stream);
continue; continue;
} }
last_queries_stride[stream] = tf.controls[i].stride; last_queries_stride[stream] += tf.controls[i].stride;
streams_mask |= 1ULL << stream; streams_mask |= 1ULL << stream;
buffers_count = std::max<size_t>(buffers_count, stream + 1); buffers_count = std::max<size_t>(buffers_count, stream + 1);
} }
@ -1039,6 +1045,7 @@ private:
bool has_started{}; bool has_started{};
bool has_flushed_end_pending{}; bool has_flushed_end_pending{};
size_t buffers_count{}; size_t buffers_count{};
size_t active_buffers_count{};
std::array<VkBuffer, NUM_STREAMS> counter_buffers{}; std::array<VkBuffer, NUM_STREAMS> counter_buffers{};
std::array<VkDeviceSize, NUM_STREAMS> offsets{}; std::array<VkDeviceSize, NUM_STREAMS> offsets{};
std::array<DAddr, NUM_STREAMS> last_queries; std::array<DAddr, NUM_STREAMS> last_queries;
@ -1160,7 +1167,7 @@ public:
} }
return index; return index;
} }
new_query->stride = 1; new_query->stride = 0;
runtime.View3DRegs([new_query, subreport](Maxwell3D& maxwell3d) { runtime.View3DRegs([new_query, subreport](Maxwell3D& maxwell3d) {
for (size_t i = 0; i < Maxwell3D::Regs::NumTransformFeedbackBuffers; i++) { for (size_t i = 0; i < Maxwell3D::Regs::NumTransformFeedbackBuffers; i++) {
const auto& tf = maxwell3d.regs.transform_feedback; const auto& tf = maxwell3d.regs.transform_feedback;
@ -1170,8 +1177,7 @@ public:
if (tf.controls[i].stream != subreport) { if (tf.controls[i].stream != subreport) {
continue; continue;
} }
new_query->stride = tf.controls[i].stride; new_query->stride += tf.controls[i].stride;
break;
} }
}); });
} }