Browse Source

[video_core] Add in-flight flush throttling to prevent CPU/GPU desync (#4085)

Prevent the CPU from getting too far ahead of the GPU by limiting pending flushes.

This fixes graphical issues in games that rely on better CPU and GPU synchronization in the Scheduler, such as the flickering bug inside shrines in The Legend of Zelda: Tears of the Kingdom.

This is enabled when the GPU is in Accurate mode.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4085
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
pull/4067/head
MaranBr 3 days ago
committed by crueter
parent
commit
ba608d2b57
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 14
      src/video_core/renderer_vulkan/vk_scheduler.cpp
  2. 2
      src/video_core/renderer_vulkan/vk_scheduler.h

14
src/video_core/renderer_vulkan/vk_scheduler.cpp

@ -27,6 +27,7 @@
namespace Vulkan { namespace Vulkan {
constexpr u64 MAX_PENDING_FLUSHES = 5;
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf, void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
vk::CommandBuffer upload_cmdbuf) { vk::CommandBuffer upload_cmdbuf) {
@ -115,7 +116,18 @@ 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) {
// When flushing, we only send data to the worker thread; no waiting is necessary.
// Prevent the CPU from getting too far ahead of the GPU by limiting pending flushes.
const bool should_throttle = Settings::IsGPULevelHigh();
if (should_throttle) {
const u64 current_tick = master_semaphore->CurrentTick();
const u64 gap = current_tick > last_submitted_tick ? current_tick - last_submitted_tick : 0;
const u64 step = (std::min)(MAX_PENDING_FLUSHES, gap);
const u64 new_tick = last_submitted_tick + step;
if (new_tick < current_tick) {
last_submitted_tick = new_tick;
master_semaphore->Wait(last_submitted_tick);
}
}
const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore); const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
AllocateNewContext(); AllocateNewContext();
return signal_value; return signal_value;

2
src/video_core/renderer_vulkan/vk_scheduler.h

@ -296,6 +296,8 @@ private:
double last_target_fps{}; double last_target_fps{};
u64 max_frame_count{}; u64 max_frame_count{};
u64 frame_counter{}; u64 frame_counter{};
u64 last_submitted_tick = 0;
}; };
} // namespace Vulkan } // namespace Vulkan
Loading…
Cancel
Save