diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 4de5d3f7a5..49a2eaf3a3 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 709f65dc25..8e5824f44f 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 d0c5624046..60e147a5ed 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -536,7 +536,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, dynamic_rendering = device.IsKhrDynamicRenderingSupported()]( vk::CommandBuffer cmdbuf) { std::array barriers; @@ -599,6 +599,7 @@ void Scheduler::EndRenderPass() state.framebuffer = VkFramebuffer{}; state.attachment_views = {}; state.rendering = false; + 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 f32cfd38a3..c4a3107c60 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.rendering; } + /// 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); @@ -277,6 +282,7 @@ private: bool is_rescaling = false; bool rescaling_defined = false; bool needs_state_enable_refresh = false; + bool uses_transform_feedback = false; }; struct DeferredClear {