diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 261c1d7d06..7fc57d2871 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -654,6 +654,7 @@ void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, offset = 0; size = 0; } + scheduler.MarkTransformFeedbackUsed(); scheduler.Record([index, buffer, offset, size](vk::CommandBuffer cmdbuf) { const VkDeviceSize vk_offset = offset; const VkDeviceSize vk_size = size; @@ -666,19 +667,26 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings< // Already logged in the rasterizer return; } - boost::container::static_vector buffer_handles(bindings.buffers.size()); - for (u32 i = 0; i < bindings.buffers.size(); ++i) { + const u32 count = std::min(static_cast(bindings.buffers.size()), + VideoCommon::NUM_TRANSFORM_FEEDBACK_BUFFERS); + std::array handles{}; + std::array offsets{}; + std::array sizes{}; + for (u32 i = 0; i < count; ++i) { auto handle = bindings.buffers[i]->Handle(); if (handle == VK_NULL_HANDLE) { ReserveNullBuffer(); handle = *null_buffer; - bindings.offsets[i] = 0; - bindings.sizes[i] = 0; + } else { + offsets[i] = bindings.offsets[i]; + sizes[i] = bindings.sizes[i]; } - buffer_handles[i] = handle; + handles[i] = handle; } - scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { - cmdbuf.BindTransformFeedbackBuffersEXT(0, u32(buffer_handles_.size()), buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data()); + scheduler.MarkTransformFeedbackUsed(); + scheduler.Record([count, handles, offsets, sizes](vk::CommandBuffer cmdbuf) { + cmdbuf.BindTransformFeedbackBuffersEXT(0, count, handles.data(), offsets.data(), + sizes.data()); }); } diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index a12dc00771..4e817ef99f 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -919,7 +919,7 @@ private: return; } has_flushed_end_pending = true; - // Refresh buffers state before beginning transform feedback so counters are up-to-date + scheduler.MarkTransformFeedbackUsed(); UpdateBuffers(); if (!has_started || buffers_count == 0) { // No counter buffers available: begin without counters diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 6a7528e0fa..fea8ca73ab 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -400,7 +400,7 @@ void Scheduler::EndRenderPass() Record([num_images = num_renderpass_images, images = renderpass_images, ranges = renderpass_image_ranges, - has_transform_feedback = device.IsExtTransformFeedbackSupported()]( + has_transform_feedback = state.uses_transform_feedback]( vk::CommandBuffer cmdbuf) { std::array barriers; for (size_t i = 0; i < num_images; ++i) { @@ -455,6 +455,7 @@ void Scheduler::EndRenderPass() }); state.renderpass = VkRenderPass{}; + state.uses_transform_feedback = false; num_renderpass_images = 0; } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index e0066dfa69..e7fae7fb91 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -74,6 +74,11 @@ public: return state.renderpass != VK_NULL_HANDLE; } + /// Flags that transform feedback writes have been recorded since the last render pass end. + void MarkTransformFeedbackUsed() noexcept { + state.uses_transform_feedback = true; + } + /// Update the pipeline to the current execution context. bool UpdateGraphicsPipeline(GraphicsPipeline* pipeline); @@ -267,6 +272,7 @@ private: bool is_rescaling = false; bool rescaling_defined = false; bool needs_state_enable_refresh = false; + bool uses_transform_feedback = false; }; struct DeferredClear {