diff --git a/src/video_core/query_cache/query_cache.h b/src/video_core/query_cache/query_cache.h index 78b42b518b..edfda06352 100644 --- a/src/video_core/query_cache/query_cache.h +++ b/src/video_core/query_cache/query_cache.h @@ -113,9 +113,10 @@ struct QueryCacheBase::QueryCacheBaseImpl { using RuntimeType = typename Traits::RuntimeType; QueryCacheBaseImpl(QueryCacheBase* owner_, VideoCore::RasterizerInterface& rasterizer_, - Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_, Tegra::GPU& gpu_) - : owner{owner_}, rasterizer{rasterizer_}, - cpu_memory{cpu_memory_}, runtime{runtime_}, gpu{gpu_} { + Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_, Tegra::GPU& gpu_, + bool has_broken_occlusion_query_) + : owner{owner_}, rasterizer{rasterizer_}, cpu_memory{cpu_memory_}, runtime{runtime_}, + gpu{gpu_}, has_broken_occlusion_query{has_broken_occlusion_query_} { streamer_mask = 0; for (size_t i = 0; i < static_cast(QueryType::MaxQueryTypes); i++) { streamers[i] = runtime.GetStreamerInterface(static_cast(i)); @@ -163,6 +164,7 @@ struct QueryCacheBase::QueryCacheBaseImpl { Tegra::GPU& gpu; std::array(QueryType::MaxQueryTypes)> streamers; u64 streamer_mask; + bool has_broken_occlusion_query; std::mutex flush_guard; std::deque flushes_pending; std::vector::QueryLocation> pending_unregister; @@ -171,10 +173,11 @@ struct QueryCacheBase::QueryCacheBaseImpl { template QueryCacheBase::QueryCacheBase(Tegra::GPU& gpu_, VideoCore::RasterizerInterface& rasterizer_, - Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_) + Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_, + bool has_broken_occlusion_query_) : cached_queries{} { impl = std::make_unique::QueryCacheBaseImpl>( - this, rasterizer_, cpu_memory_, runtime_, gpu_); + this, rasterizer_, cpu_memory_, runtime_, gpu_, has_broken_occlusion_query_); } template @@ -223,6 +226,19 @@ void QueryCacheBase::BindToChannel(s32 id) { impl->runtime.Bind3DEngine(maxwell3d); } +constexpr u64 OcclusionQueryAdjustValue(bool has_broken_occlusion_query, QueryType counter_type) { + if (!has_broken_occlusion_query) { + return 0; + } + switch (counter_type) { + case QueryType::ZPassPixelCount: + case QueryType::ZPassPixelCount64: + return 120; + default: + return 0; + } +} + template void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type, QueryPropertiesFlags flags, u32 payload, u32 subreport) { @@ -256,9 +272,10 @@ void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type u8* pointer = impl->cpu_memory.GetPointer(cpu_addr); u8* pointer_timestamp = impl->cpu_memory.GetPointer(cpu_addr + 8); bool is_synced = !Settings::IsGPULevelHigh() && is_fence; + u64 adjustment = OcclusionQueryAdjustValue(impl->has_broken_occlusion_query, counter_type); std::function operation([this, is_synced, streamer, query_base = query, query_location, - pointer, pointer_timestamp] { + pointer, pointer_timestamp, adjustment] { if (True(query_base->flags & QueryFlagBits::IsInvalidated)) { if (!is_synced) [[likely]] { impl->pending_unregister.push_back(query_location); @@ -269,7 +286,7 @@ void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type UNREACHABLE(); return; } - query_base->value += streamer->GetAmmendValue(); + query_base->value += streamer->GetAmmendValue() + adjustment; streamer->SetAccumulationValue(query_base->value); if (True(query_base->flags & QueryFlagBits::HasTimestamp)) { u64 timestamp = impl->gpu.GetTicks(); diff --git a/src/video_core/query_cache/query_cache_base.h b/src/video_core/query_cache/query_cache_base.h index 07be421c60..473fdd718d 100644 --- a/src/video_core/query_cache/query_cache_base.h +++ b/src/video_core/query_cache/query_cache_base.h @@ -53,7 +53,8 @@ public: }; explicit QueryCacheBase(Tegra::GPU& gpu, VideoCore::RasterizerInterface& rasterizer_, - Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_); + Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_, + bool has_broken_occlusion_query_); ~QueryCacheBase(); @@ -178,4 +179,4 @@ protected: std::unique_ptr impl; }; -} // namespace VideoCommon \ No newline at end of file +} // namespace VideoCommon diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 66c03bf173..9a965120c4 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -116,8 +116,9 @@ public: Scheduler& scheduler_, const MemoryAllocator& memory_allocator_, ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool) - : BaseStreamer(id_), runtime{runtime_}, rasterizer{rasterizer_}, device{device_}, - scheduler{scheduler_}, memory_allocator{memory_allocator_} { + : BaseStreamer(id_), runtime{runtime_}, + rasterizer{rasterizer_}, device{device_}, scheduler{scheduler_}, + memory_allocator{memory_allocator_}, is_broken{device.HasBrokenOcclusionQuery()} { current_bank = nullptr; current_query = nullptr; ammend_value = 0; @@ -150,12 +151,14 @@ public: return; } ReserveHostQuery(); - scheduler.Record([query_pool = current_query_pool, - query_index = current_bank_slot](vk::CommandBuffer cmdbuf) { - const bool use_precise = Settings::IsGPULevelHigh(); - cmdbuf.BeginQuery(query_pool, static_cast(query_index), - use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0); - }); + if (!is_broken) { + scheduler.Record([query_pool = current_query_pool, + query_index = current_bank_slot](vk::CommandBuffer cmdbuf) { + const bool use_precise = Settings::IsGPULevelHigh(); + cmdbuf.BeginQuery(query_pool, static_cast(query_index), + use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0); + }); + } has_started = true; } @@ -163,10 +166,12 @@ public: if (!has_started) { return; } - scheduler.Record([query_pool = current_query_pool, - query_index = current_bank_slot](vk::CommandBuffer cmdbuf) { - cmdbuf.EndQuery(query_pool, static_cast(query_index)); - }); + if (!is_broken) { + scheduler.Record([query_pool = current_query_pool, + query_index = current_bank_slot](vk::CommandBuffer cmdbuf) { + cmdbuf.EndQuery(query_pool, static_cast(query_index)); + }); + } has_started = false; } @@ -573,6 +578,7 @@ private: bool accumulation_since_last_sync{}; VideoCommon::HostQueryBase* current_query; bool has_started{}; + bool is_broken{}; std::mutex flush_guard; std::unique_ptr queries_prefix_scan_pass; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index c0e8431e4c..07b05059f3 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -174,7 +174,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra buffer_cache(*this, cpu_memory_, buffer_cache_runtime), query_cache_runtime(this, cpu_memory_, buffer_cache, device, memory_allocator, scheduler, staging_pool, compute_pass_descriptor_queue, descriptor_pool), - query_cache(gpu, *this, cpu_memory_, query_cache_runtime), + query_cache(gpu, *this, cpu_memory_, query_cache_runtime, device.HasBrokenOcclusionQuery()), pipeline_cache(*this, device, scheduler, descriptor_pool, guest_descriptor_queue, render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), accelerate_dma(buffer_cache, texture_cache, scheduler), diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index e518756d23..6db812a8f3 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -513,6 +513,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR #endif } + if (is_turnip) { + LOG_WARNING(Render_Vulkan, "Turnip drivers have broken occlusion queries"); + has_broken_occlusion_query = true; + } + if (is_arm) { must_emulate_scaled_formats = true; diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index b213ed7dd3..781f9a692e 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -599,6 +599,10 @@ public: return has_broken_cube_compatibility; } + bool HasBrokenOcclusionQuery() const { + return has_broken_occlusion_query; + } + /// Returns the vendor name reported from Vulkan. std::string_view GetVendorName() const { return properties.driver.driverName; @@ -794,6 +798,7 @@ private: bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device. bool has_broken_compute{}; ///< Compute shaders can cause crashes bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit + bool has_broken_occlusion_query{}; ///< Has broken occlusion queries bool has_renderdoc{}; ///< Has RenderDoc attached bool has_nsight_graphics{}; ///< Has Nsight Graphics attached bool supports_d24_depth{}; ///< Supports D24 depth buffers.