From 94c9f828c55e1efbca3d6a4dfa11fc5f31a0357f Mon Sep 17 00:00:00 2001 From: wildcard Date: Thu, 14 Aug 2025 22:00:09 +0200 Subject: [PATCH] [VK]Improve query reset before use so that now queries are reset outside render pass and are batched Note to testers, please enable validation layers and see if there are any errors related to queries not being reset before every use, Thanks. --- src/video_core/query_cache/query_cache.h | 8 ++++++- src/video_core/query_cache/query_cache_base.h | 6 +++-- .../renderer_vulkan/vk_query_cache.cpp | 24 +++++++++++++++++-- .../renderer_vulkan/vk_query_cache.h | 4 ++-- .../renderer_vulkan/vk_scheduler.cpp | 5 ++++ 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/video_core/query_cache/query_cache.h b/src/video_core/query_cache/query_cache.h index 6e084cc079..865e707f21 100644 --- a/src/video_core/query_cache/query_cache.h +++ b/src/video_core/query_cache/query_cache.h @@ -27,7 +27,7 @@ #include "video_core/query_cache/query_cache_base.h" #include "video_core/query_cache/query_stream.h" #include "video_core/query_cache/types.h" - +namespace Vulkan { class Scheduler; } namespace VideoCommon { using Maxwell = Tegra::Engines::Maxwell3D; @@ -222,6 +222,12 @@ void QueryCacheBase::CounterReset(QueryType counter_type) { streamer->ResetCounter(); } +// Called at frame start to batch vkCmdResetQueryPool outside render passes. +template +void QueryCacheBase::FramePrologueResets(Vulkan::Scheduler& scheduler) { + impl->runtime.FramePrologueResets(scheduler); +} + template void QueryCacheBase::BindToChannel(s32 id) { VideoCommon::ChannelSetupCaches::BindToChannel(id); diff --git a/src/video_core/query_cache/query_cache_base.h b/src/video_core/query_cache/query_cache_base.h index 00c25c8d63..3eddd5a7f2 100644 --- a/src/video_core/query_cache/query_cache_base.h +++ b/src/video_core/query_cache/query_cache_base.h @@ -21,7 +21,9 @@ namespace VideoCore { class RasterizerInterface; } - +namespace Vulkan { + class Scheduler; +} namespace Tegra { class GPU; } @@ -53,7 +55,7 @@ public: RuntimeType& runtime_); ~QueryCacheBase(); - + void FramePrologueResets(Vulkan::Scheduler& scheduler); void InvalidateRegion(VAddr addr, std::size_t size) { IterateCache(addr, size, [this](QueryLocation location) { InvalidateQuery(location); }); diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 89e0b1114e..7d64d2eaac 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -156,7 +156,7 @@ public: ReserveHostQuery(); - // Ensure outside render pass + /* Ensure outside render pass scheduler.RequestOutsideRenderPassOperationContext(); // Reset query pool outside render pass @@ -167,7 +167,7 @@ public: // Manually restart the render pass (required for vkCmdClearAttachments, etc.) scheduler.RequestRenderpass(texture_cache.GetFramebuffer()); - + */ // Begin query inside the newly started render pass scheduler.Record([query_pool = current_query_pool, query_index = current_bank_slot](vk::CommandBuffer cmdbuf) { @@ -402,6 +402,13 @@ public: } } + VkQueryPool GetOrCreateCurrentPoolForPrologue() { + if (!current_bank || current_bank->IsClosed()) { + ReserveBank(); + } + return current_query_pool; + } + private: template void ApplyBankOp(VideoCommon::HostQueryBase* query, Func&& func) { @@ -1305,6 +1312,19 @@ void QueryCacheRuntime::ResumeHostConditionalRendering() { impl->is_hcr_running = true; } +void QueryCacheRuntime::FramePrologueResets(Scheduler& scheduler) { + // Reset the occlusion queries we plan to use this frame in one go. + // Ensure this is recorded OUTSIDE any render pass. + const VkQueryPool pool = impl->sample_streamer.GetOrCreateCurrentPoolForPrologue(); + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([pool](vk::CommandBuffer cmdbuf) { + // Reset the whole bank so subsequent BeginQuery calls don't need per-slot resets. + cmdbuf.ResetQueryPool(pool, + /*first*/ 0, + /*count*/ SamplesQueryBank::BANK_SIZE); + }); +} + void QueryCacheRuntime::HostConditionalRenderingCompareValueImpl(VideoCommon::LookupData object, bool is_equal) { { diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h index b8dae9bc2d..05e270e5f1 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.h +++ b/src/video_core/renderer_vulkan/vk_query_cache.h @@ -20,7 +20,7 @@ namespace Vulkan { class Device; class Scheduler; class StagingBufferPool; - +class Scheduler; struct QueryCacheRuntimeImpl; class QueryCacheRuntime { @@ -33,7 +33,7 @@ public: ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool, TextureCache& texture_cache_); ~QueryCacheRuntime(); - + void FramePrologueResets(Scheduler& scheduler); template void SyncValues(std::span values, VkBuffer base_src_buffer = nullptr); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 530d161dfe..7560852f97 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -257,6 +257,11 @@ u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_se void Scheduler::AllocateNewContext() { // Enable counters once again. These are disabled when a command buffer is finished. + // Record per frame query resets outside any render pass, before the first draw. + if (query_cache) { + query_cache->FramePrologueResets(*this); + } + } void Scheduler::InvalidateState() {