diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index e4c4329e81..2ddae39750 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 force_delay = 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 = force_delay || Settings::IsGPULevelHigh() || + (Settings::IsGPULevelMedium() && should_flush); CommitAsyncFlushes(); - TFence new_fence = CreateFence(!should_flush); + TFence new_fence = CreateFence(!should_flush && !force_delay); 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 4ed42487aa..1b0f59020b 100644 --- a/src/video_core/query_cache/query_cache.h +++ b/src/video_core/query_cache/query_cache.h @@ -246,11 +246,24 @@ 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) { + 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)); + } + }); + impl->rasterizer.SignalFence(std::move(operation), true); + 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) { - query->flags |= QueryFlagBits::IsFence; - } QueryLocation query_location{}; query_location.stream_id.Assign(static_cast(streamer_id)); query_location.query_id.Assign(static_cast(new_query_id)); @@ -258,9 +271,8 @@ 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; + bool is_synced = false; std::function operation([this, is_synced, streamer, query_base = query, query_location, pointer, pointer_timestamp] { if (True(query_base->flags & QueryFlagBits::IsInvalidated)) { @@ -291,23 +303,19 @@ void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type impl->pending_unregister.push_back(query_location); } }); - if (is_fence) { - impl->rasterizer.SignalFence(std::move(operation)); - } else { - if (!Settings::IsGPULevelHigh() && counter_type == QueryType::Payload) { - if (has_timestamp) { - u64 timestamp = impl->gpu.GetTicks(); - 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)); - } - streamer->Free(new_query_id); - return; + if (!Settings::IsGPULevelHigh() && counter_type == QueryType::Payload) { + if (has_timestamp) { + u64 timestamp = impl->gpu.GetTicks(); + 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)); } - impl->rasterizer.SyncOperation(std::move(operation)); + streamer->Free(new_query_id); + return; } + impl->rasterizer.SyncOperation(std::move(operation)); if (is_synced) { streamer->Free(new_query_id); return; diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 481efbf53b..ac453fc48a 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 force_delay = 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..cacdd20fa4 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 force_delay) { 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..44791fcff2 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 force_delay = 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 e268c4d2c6..d69a9fd8fe 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 force_delay) { + fence_manager.SignalFence(std::move(func), force_delay); } 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..e6407803de 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 force_delay = 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_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index ba7b5d8c1b..882b24fe77 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -744,8 +744,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 force_delay) { + fence_manager.SignalFence(std::move(func), force_delay); } 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 b689c6b660..9622e1a047 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.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 2019 yuzu Emulator Project @@ -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 force_delay = false) override; void SyncOperation(std::function&& func) override; void SignalSyncPoint(u32 value) override; void SignalReference() override;