[fence_manager] fence-only non-stubbed forced delay (up to 70% less delays than gpu>fast)

This commit is contained in:
xbzk 2026-04-14 13:23:55 -03:00
parent e875a3196b
commit 1db3f552a6
11 changed files with 51 additions and 17 deletions

View file

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@ -71,14 +71,15 @@ public:
uncommitted_operations.emplace_back(std::move(func)); uncommitted_operations.emplace_back(std::move(func));
} }
void SignalFence(std::function<void()>&& func) { void SignalFence(std::function<void()>&& func, bool ordered = false) {
if constexpr (!can_async_check) { if constexpr (!can_async_check) {
TryReleasePendingFences<false>(); TryReleasePendingFences<false>();
} }
const bool should_flush = ShouldFlush(); const bool should_flush = ShouldFlush();
const bool delay_fence = Settings::IsGPULevelHigh() || (Settings::IsGPULevelMedium() && should_flush); const bool delay_fence = ordered || Settings::IsGPULevelHigh() || Settings::getDebugKnobAt(4) ||
(Settings::IsGPULevelMedium() && should_flush);
CommitAsyncFlushes(); CommitAsyncFlushes();
TFence new_fence = CreateFence(!should_flush); TFence new_fence = CreateFence(!should_flush && !ordered);
if constexpr (can_async_check) { if constexpr (can_async_check) {
guard.lock(); guard.lock();
} }

View file

@ -246,6 +246,23 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
return; return;
} }
DAddr cpu_addr = *cpu_addr_opt; DAddr cpu_addr = *cpu_addr_opt;
u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
if (is_fence && Settings::getDebugKnobAt(0)) { //xbzk: toggle/knob here to control antiflicker
u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
std::function<void()> operation([this, pointer, pointer_timestamp, payload, has_timestamp] {
if (has_timestamp) {
const u64 timestamp = impl->gpu.GetTicks();
const u64 value = static_cast<u64>(payload);
std::memcpy(pointer_timestamp, &timestamp, 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); const size_t new_query_id = streamer->WriteCounter(cpu_addr, has_timestamp, payload, subreport);
auto* query = streamer->GetQuery(new_query_id); auto* query = streamer->GetQuery(new_query_id);
if (is_fence) { if (is_fence) {
@ -258,7 +275,6 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
return std::make_pair<u64, u32>(cur_addr >> Core::DEVICE_PAGEBITS, return std::make_pair<u64, u32>(cur_addr >> Core::DEVICE_PAGEBITS,
static_cast<u32>(cur_addr & Core::DEVICE_PAGEMASK)); static_cast<u32>(cur_addr & Core::DEVICE_PAGEMASK));
}; };
u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8); u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
bool is_synced = !Settings::IsGPULevelHigh() && is_fence; bool is_synced = !Settings::IsGPULevelHigh() && is_fence;
std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location, std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location,

View file

@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -69,7 +72,7 @@ public:
virtual void DisableGraphicsUniformBuffer(size_t stage, u32 index) = 0; virtual void DisableGraphicsUniformBuffer(size_t stage, u32 index) = 0;
/// Signal a GPU based semaphore as a fence /// Signal a GPU based semaphore as a fence
virtual void SignalFence(std::function<void()>&& func) = 0; virtual void SignalFence(std::function<void()>&& func, bool ordered = false) = 0;
/// Send an operation to be done after a certain amount of flushes. /// Send an operation to be done after a certain amount of flushes.
virtual void SyncOperation(std::function<void()>&& func) = 0; virtual void SyncOperation(std::function<void()>&& func) = 0;

View file

@ -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-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // 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::InvalidateGPUCache() {}
void RasterizerNull::UnmapMemory(DAddr addr, u64 size) {} void RasterizerNull::UnmapMemory(DAddr addr, u64 size) {}
void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {} void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {}
void RasterizerNull::SignalFence(std::function<void()>&& func) { void RasterizerNull::SignalFence(std::function<void()>&& func, bool ordered) {
func(); func();
} }
void RasterizerNull::SyncOperation(std::function<void()>&& func) { void RasterizerNull::SyncOperation(std::function<void()>&& func) {

View file

@ -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-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -59,7 +62,7 @@ public:
void InvalidateGPUCache() override; void InvalidateGPUCache() override;
void UnmapMemory(DAddr addr, u64 size) override; void UnmapMemory(DAddr addr, u64 size) override;
void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
void SignalFence(std::function<void()>&& func) override; void SignalFence(std::function<void()>&& func, bool ordered = false) override;
void SyncOperation(std::function<void()>&& func) override; void SyncOperation(std::function<void()>&& func) override;
void SignalSyncPoint(u32 value) override; void SignalSyncPoint(u32 value) override;
void SignalReference() override; void SignalReference() override;

View file

@ -607,8 +607,8 @@ void RasterizerOpenGL::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {
} }
} }
void RasterizerOpenGL::SignalFence(std::function<void()>&& func) { void RasterizerOpenGL::SignalFence(std::function<void()>&& func, bool ordered) {
fence_manager.SignalFence(std::move(func)); fence_manager.SignalFence(std::move(func), ordered);
} }
void RasterizerOpenGL::SyncOperation(std::function<void()>&& func) { void RasterizerOpenGL::SyncOperation(std::function<void()>&& func) {

View file

@ -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-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -104,7 +107,7 @@ public:
void InvalidateGPUCache() override; void InvalidateGPUCache() override;
void UnmapMemory(DAddr addr, u64 size) override; void UnmapMemory(DAddr addr, u64 size) override;
void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
void SignalFence(std::function<void()>&& func) override; void SignalFence(std::function<void()>&& func, bool ordered = false) override;
void SyncOperation(std::function<void()>&& func) override; void SyncOperation(std::function<void()>&& func) override;
void SignalSyncPoint(u32 value) override; void SignalSyncPoint(u32 value) override;
void SignalReference() override; void SignalReference() override;

View file

@ -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-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -21,9 +24,7 @@ void InnerFence::Queue() {
if (is_stubbed) { if (is_stubbed) {
return; return;
} }
// Get the current tick so we can wait for it wait_tick = scheduler.Flush();
wait_tick = scheduler.CurrentTick();
scheduler.Flush();
} }
bool InnerFence::IsSignaled() const { bool InnerFence::IsSignaled() const {

View file

@ -770,8 +770,8 @@ void RasterizerVulkan::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {
} }
} }
void RasterizerVulkan::SignalFence(std::function<void()>&& func) { void RasterizerVulkan::SignalFence(std::function<void()>&& func, bool ordered) {
fence_manager.SignalFence(std::move(func)); fence_manager.SignalFence(std::move(func), ordered);
} }
void RasterizerVulkan::SyncOperation(std::function<void()>&& func) { void RasterizerVulkan::SyncOperation(std::function<void()>&& func) {

View file

@ -109,7 +109,7 @@ public:
void InvalidateGPUCache() override; void InvalidateGPUCache() override;
void UnmapMemory(DAddr addr, u64 size) override; void UnmapMemory(DAddr addr, u64 size) override;
void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
void SignalFence(std::function<void()>&& func) override; void SignalFence(std::function<void()>&& func, bool ordered = false) override;
void SyncOperation(std::function<void()>&& func) override; void SyncOperation(std::function<void()>&& func) override;
void SignalSyncPoint(u32 value) override; void SignalSyncPoint(u32 value) override;
void SignalReference() override; void SignalReference() override;

View file

@ -65,6 +65,10 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
Scheduler::~Scheduler() = default; Scheduler::~Scheduler() = default;
u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
if (Settings::getDebugKnobAt(3) && chunk->Empty() && !signal_semaphore && !wait_semaphore) {//xbzk: improves fps by skipping flushes
const u64 current = CurrentTick();
return current > 0 ? current - 1 : 0;
}
// When flushing, we only send data to the worker thread; no waiting is necessary. // When flushing, we only send data to the worker thread; no waiting is necessary.
const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore); const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
AllocateNewContext(); AllocateNewContext();