diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 014b4a318e..823ecdff6b 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1064,13 +1064,23 @@ void BufferCache
::BindHostTransformFeedbackBuffers() {
if (maxwell3d->regs.transform_feedback_enabled == 0) {
return;
}
- HostBindings host_bindings;
+ Buffer& null_buffer = slot_buffers[NULL_BUFFER_ID];
+ bool reached_end = false;
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
- const Binding& binding = channel_state->transform_feedback_buffers[index];
- if (maxwell3d->regs.transform_feedback.controls[index].varying_count == 0 &&
- maxwell3d->regs.transform_feedback.controls[index].stride == 0) {
- break;
+ const auto& control = maxwell3d->regs.transform_feedback.controls[index];
+ if (reached_end ||
+ (control.varying_count == 0 && control.stride == 0)) {
+ 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];
TouchBuffer(buffer, binding.buffer_id);
const u32 size = binding.size;
@@ -1080,12 +1090,7 @@ void BufferCache::BindHostTransformFeedbackBuffers() {
const u32 offset = buffer.Offset(binding.device_addr);
buffer.MarkUsage(offset, size);
- host_bindings.buffers.push_back(&buffer);
- host_bindings.offsets.push_back(offset);
- host_bindings.sizes.push_back(size);
- }
- if (host_bindings.buffers.size() > 0) {
- runtime.BindTransformFeedbackBuffers(host_bindings);
+ runtime.BindTransformFeedbackBuffer(index, buffer, offset, size);
}
}
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index fef315e035..483b756dee 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -231,7 +231,7 @@ public:
const VkIndexType index_type_ = index_type;
const size_t sub_first_offset = static_cast(first % 4) * GetQuadsNum(num_indices);
const size_t offset =
- (sub_first_offset + GetQuadsNum(first)) * 6ULL * BytesPerIndex(index_type);
+ (sub_first_offset + GetFirstOffsetQuads(first)) * 6ULL * BytesPerIndex(index_type);
scheduler.Record([buffer_ = *buffer, index_type_, offset](vk::CommandBuffer cmdbuf) {
cmdbuf.BindIndexBuffer(buffer_, offset, index_type_);
});
@@ -240,6 +240,8 @@ public:
protected:
virtual u32 GetQuadsNum(u32 num_indices) const = 0;
+ virtual u32 GetFirstOffsetQuads(u32 first) const = 0;
+
virtual void MakeAndUpdateIndices(u8* staging_data, size_t quad_size, u32 quad, u32 first) = 0;
const Device& device;
@@ -266,6 +268,10 @@ private:
return num_indices_ / 4;
}
+ u32 GetFirstOffsetQuads(u32 first) const override {
+ return first / 4;
+ }
+
template
static std::array MakeIndices(u32 quad, u32 first) {
std::array indices{0, 1, 2, 0, 2, 3};
@@ -306,6 +312,10 @@ private:
return num_indices_ >= 4 ? (num_indices_ - 2) / 2 : 0;
}
+ u32 GetFirstOffsetQuads(u32 first) const override {
+ return (first / 4) * 2;
+ }
+
template
static std::array MakeIndices(u32 quad, u32 first) {
std::array indices{0, 3, 1, 0, 2, 3};
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 5b0b876364..8db5ba0805 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -127,6 +127,9 @@ public:
void BindVertexBuffers(VideoCommon::HostBindings& 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);
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 9018179731..29b8d3ce67 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -717,7 +717,7 @@ public:
counter_buffers.fill(VK_NULL_HANDLE);
offsets.fill(0);
last_queries.fill(0);
- last_queries_stride.fill(1);
+ last_queries_stride.fill(0);
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -913,14 +913,16 @@ private:
has_flushed_end_pending = true;
// Refresh buffers state before beginning transform feedback so counters are up-to-date
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
scheduler.Record([](vk::CommandBuffer cmdbuf) {
cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr);
});
return;
}
- scheduler.Record([this, total = static_cast(buffers_count)](vk::CommandBuffer cmdbuf) {
+ scheduler.Record(
+ [this, total = static_cast(active_buffers_count)](vk::CommandBuffer cmdbuf) {
cmdbuf.BeginTransformFeedbackEXT(0, total, counter_buffers.data(), offsets.data());
});
}
@@ -931,23 +933,27 @@ private:
return;
}
has_flushed_end_pending = false;
- if (buffers_count == 0) {
- LOG_DEBUG(Render_Vulkan, "EndTransformFeedbackEXT called with no counters (buffers_count=0)");
+ if (active_buffers_count == 0) {
+ LOG_DEBUG(Render_Vulkan,
+ "EndTransformFeedbackEXT called with no counters (active_buffers_count=0)");
scheduler.Record([](vk::CommandBuffer cmdbuf) {
cmdbuf.EndTransformFeedbackEXT(0, 0, nullptr, nullptr);
});
} 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,
- total = static_cast(buffers_count)](vk::CommandBuffer cmdbuf) {
+ total = static_cast(active_buffers_count)](vk::CommandBuffer cmdbuf) {
cmdbuf.EndTransformFeedbackEXT(0, total, counter_buffers.data(), offsets.data());
});
}
+ active_buffers_count = 0;
}
void UpdateBuffers() {
last_queries.fill(0);
- last_queries_stride.fill(1);
+ last_queries_stride.fill(0);
streams_mask = 0; // reset previously recorded streams
runtime.View3DRegs([this](Maxwell3D& maxwell3d) {
buffers_count = 0;
@@ -962,7 +968,7 @@ private:
LOG_WARNING(Render_Vulkan, "TransformFeedback stream {} out of range", stream);
continue;
}
- last_queries_stride[stream] = tf.controls[i].stride;
+ last_queries_stride[stream] += tf.controls[i].stride;
streams_mask |= 1ULL << stream;
buffers_count = std::max(buffers_count, stream + 1);
}
@@ -1039,6 +1045,7 @@ private:
bool has_started{};
bool has_flushed_end_pending{};
size_t buffers_count{};
+ size_t active_buffers_count{};
std::array counter_buffers{};
std::array offsets{};
std::array last_queries;
@@ -1160,7 +1167,7 @@ public:
}
return index;
}
- new_query->stride = 1;
+ new_query->stride = 0;
runtime.View3DRegs([new_query, subreport](Maxwell3D& maxwell3d) {
for (size_t i = 0; i < Maxwell3D::Regs::NumTransformFeedbackBuffers; i++) {
const auto& tf = maxwell3d.regs.transform_feedback;
@@ -1170,8 +1177,7 @@ public:
if (tf.controls[i].stream != subreport) {
continue;
}
- new_query->stride = tf.controls[i].stride;
- break;
+ new_query->stride += tf.controls[i].stride;
}
});
}