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; } }); }