From a19510fba907a7d4479d085259df815403a37c49 Mon Sep 17 00:00:00 2001 From: xbzk Date: Tue, 14 Apr 2026 13:23:55 -0300 Subject: [PATCH] [fence_manager] fence-only non-stubbed forced delay (up to 70% less delays than gpu>fast) --- src/video_core/fence_manager.h | 9 +++++---- src/video_core/query_cache/query_cache.h | 18 +++++++++++++++++- src/video_core/rasterizer_interface.h | 5 ++++- .../renderer_null/null_rasterizer.cpp | 5 ++++- src/video_core/renderer_null/null_rasterizer.h | 5 ++++- .../renderer_opengl/gl_rasterizer.cpp | 4 ++-- src/video_core/renderer_opengl/gl_rasterizer.h | 5 ++++- .../renderer_vulkan/vk_fence_manager.cpp | 7 ++++--- .../renderer_vulkan/vk_rasterizer.cpp | 4 ++-- src/video_core/renderer_vulkan/vk_rasterizer.h | 2 +- .../renderer_vulkan/vk_scheduler.cpp | 4 ++++ 11 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index e4c4329e81..d883de9d2b 100644 --- a/src/video_core/fence_manager.h +++ b/src/video_core/fence_manager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project @@ -71,14 +71,15 @@ public: uncommitted_operations.emplace_back(std::move(func)); } - void SignalFence(std::function&& func) { + void SignalFence(std::function&& func, bool ordered = false) { if constexpr (!can_async_check) { TryReleasePendingFences(); } const bool should_flush = ShouldFlush(); - const bool delay_fence = Settings::IsGPULevelHigh() || (Settings::IsGPULevelMedium() && should_flush); + const bool delay_fence = ordered || Settings::IsGPULevelHigh() || + (Settings::IsGPULevelMedium() && should_flush); CommitAsyncFlushes(); - TFence new_fence = CreateFence(!should_flush); + TFence new_fence = CreateFence(!should_flush && !ordered); if constexpr (can_async_check) { guard.lock(); } diff --git a/src/video_core/query_cache/query_cache.h b/src/video_core/query_cache/query_cache.h index 6bed91a53e..974ad4c7ed 100644 --- a/src/video_core/query_cache/query_cache.h +++ b/src/video_core/query_cache/query_cache.h @@ -246,6 +246,23 @@ void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type return; } DAddr cpu_addr = *cpu_addr_opt; + u8* pointer = impl->device_memory.template GetPointer(cpu_addr); + if (is_fence && !Settings::getDebugKnobAt(0)) { + u8* pointer_timestamp = impl->device_memory.template GetPointer(cpu_addr + 8); + std::function operation([this, pointer, pointer_timestamp, payload, has_timestamp] { + if (has_timestamp) { + const u64 timestamp = impl->gpu.GetTicks(); + const u64 value = static_cast(payload); + std::memcpy(pointer_timestamp, ×tamp, sizeof(timestamp)); + std::memcpy(pointer, &value, sizeof(value)); + } else { + std::memcpy(pointer, &payload, sizeof(payload)); + } + }); + const bool impose_ordering_for_fences = true; + impl->rasterizer.SignalFence(std::move(operation), impose_ordering_for_fences); + return; + } const size_t new_query_id = streamer->WriteCounter(cpu_addr, has_timestamp, payload, subreport); auto* query = streamer->GetQuery(new_query_id); if (is_fence) { @@ -258,7 +275,6 @@ void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type return std::make_pair(cur_addr >> Core::DEVICE_PAGEBITS, static_cast(cur_addr & Core::DEVICE_PAGEMASK)); }; - u8* pointer = impl->device_memory.template GetPointer(cpu_addr); u8* pointer_timestamp = impl->device_memory.template GetPointer(cpu_addr + 8); bool is_synced = !Settings::IsGPULevelHigh() && is_fence; std::function operation([this, is_synced, streamer, query_base = query, query_location, diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 481efbf53b..8217966bed 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -69,7 +72,7 @@ public: virtual void DisableGraphicsUniformBuffer(size_t stage, u32 index) = 0; /// Signal a GPU based semaphore as a fence - virtual void SignalFence(std::function&& func) = 0; + virtual void SignalFence(std::function&& func, bool ordered = false) = 0; /// Send an operation to be done after a certain amount of flushes. virtual void SyncOperation(std::function&& func) = 0; diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp index a5cda0f389..7f975db42f 100644 --- a/src/video_core/renderer_null/null_rasterizer.cpp +++ b/src/video_core/renderer_null/null_rasterizer.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -63,7 +66,7 @@ VideoCore::RasterizerDownloadArea RasterizerNull::GetFlushArea(PAddr addr, u64 s void RasterizerNull::InvalidateGPUCache() {} void RasterizerNull::UnmapMemory(DAddr addr, u64 size) {} void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {} -void RasterizerNull::SignalFence(std::function&& func) { +void RasterizerNull::SignalFence(std::function&& func, bool ordered) { func(); } void RasterizerNull::SyncOperation(std::function&& func) { diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h index c7f5849c75..c039c5c7d5 100644 --- a/src/video_core/renderer_null/null_rasterizer.h +++ b/src/video_core/renderer_null/null_rasterizer.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -59,7 +62,7 @@ public: void InvalidateGPUCache() override; void UnmapMemory(DAddr addr, u64 size) override; void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; - void SignalFence(std::function&& func) override; + void SignalFence(std::function&& func, bool ordered = false) override; void SyncOperation(std::function&& func) override; void SignalSyncPoint(u32 value) override; void SignalReference() override; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 70f244809f..3d24904a53 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -607,8 +607,8 @@ void RasterizerOpenGL::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) { } } -void RasterizerOpenGL::SignalFence(std::function&& func) { - fence_manager.SignalFence(std::move(func)); +void RasterizerOpenGL::SignalFence(std::function&& func, bool ordered) { + fence_manager.SignalFence(std::move(func), ordered); } void RasterizerOpenGL::SyncOperation(std::function&& func) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 6eae51ff7d..cc6d1c333b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -104,7 +107,7 @@ public: void InvalidateGPUCache() override; void UnmapMemory(DAddr addr, u64 size) override; void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; - void SignalFence(std::function&& func) override; + void SignalFence(std::function&& func, bool ordered = false) override; void SyncOperation(std::function&& func) override; void SignalSyncPoint(u32 value) override; void SignalReference() override; diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp index fad9e38324..aba99485dc 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -21,9 +24,7 @@ void InnerFence::Queue() { if (is_stubbed) { return; } - // Get the current tick so we can wait for it - wait_tick = scheduler.CurrentTick(); - scheduler.Flush(); + wait_tick = scheduler.Flush(); } bool InnerFence::IsSignaled() const { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 3c3367cfd8..ed3f8c08a9 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -770,8 +770,8 @@ void RasterizerVulkan::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) { } } -void RasterizerVulkan::SignalFence(std::function&& func) { - fence_manager.SignalFence(std::move(func)); +void RasterizerVulkan::SignalFence(std::function&& func, bool ordered) { + fence_manager.SignalFence(std::move(func), ordered); } void RasterizerVulkan::SyncOperation(std::function&& func) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 841933d31d..a0aab08792 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -109,7 +109,7 @@ public: void InvalidateGPUCache() override; void UnmapMemory(DAddr addr, u64 size) override; void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; - void SignalFence(std::function&& func) override; + void SignalFence(std::function&& func, bool ordered = false) override; void SyncOperation(std::function&& func) override; void SignalSyncPoint(u32 value) override; void SignalReference() override; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index fdaf9baacc..b1f76798b9 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -65,6 +65,10 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_) Scheduler::~Scheduler() = default; u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { + if (!Settings::getDebugKnobAt(0) && chunk->Empty() && !signal_semaphore && !wait_semaphore) { + const u64 current = CurrentTick(); + return current > 0 ? current - 1 : 0; + } // When flushing, we only send data to the worker thread; no waiting is necessary. const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore); AllocateNewContext();