From 30613d23b0cdc6b5d3e50776e65a5cc0bd10b123 Mon Sep 17 00:00:00 2001 From: popcoder565 <339285150+popcoder565@users.noreply.github.com> Date: Thu, 8 Oct 2026 04:45:02 -0400 Subject: [PATCH] fix(agc): poll for completions with a high-resolution timer on Windows An idle queue worker with completions pending waited on its condition variable for 1 ms before each reap. With MinGW that wait goes through winpthreads, which ends a timed wait on a 15.6 ms GetTickCount64 step, so deferred end-of-pipe interrupts reached the guest about 15 ms after the GPU had finished. On Windows the worker now sleeps with PollSleep between reaps, and so does the wait for a wait-free submission's order release. Co-Authored-By: Claude Opus 5.5 --- .../Execution/src/Driver/Queues/QueueWorker.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/QueueWorker.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/QueueWorker.cpp index dca6dd040..a7fc27355 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/QueueWorker.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/QueueWorker.cpp @@ -2,6 +2,7 @@ #include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp" #include "prx/libSceAgcDriver/Execution/include/Driver/Synchronization/SynchronizationStatistics.hpp" #include "prx/libSceAgcDriver/Execution/include/Driver/Queues/WorkerAffinity.hpp" +#include "prx/libSceAgcDriver/Execution/include/Driver/Synchronization/WaitMemory.hpp" #include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp" #include "prx/libSceAgcDriver/Execution/include/WorkerSampler.hpp" #include @@ -58,6 +59,16 @@ void Driver::run(std::uint32_t id) noexcept { workerQueued() = &worker.queued; if (traceGpu && pending.empty()) std::fprintf(stderr, "[gpu] %.1f idle queue=0x%x\n", TraceMs(), id); const auto ready = [&] { return failure || stopping || !pending.empty(); }; + const auto poll = [&](const auto& done) { +#ifdef _WIN32 + lock.unlock(); + PollSleep(); + lock.lock(); + return done(); +#else + return changed.wait_for(lock, std::chrono::milliseconds(1), done); +#endif + }; while (!ready()) { if (!completionsPending() || (id != 0 && Graphics::Recorder::PendingCompletionLabels() == 0)) { @@ -66,7 +77,7 @@ void Driver::run(std::uint32_t id) noexcept { if (id == 0) queue0Dormant.store(false, std::memory_order_relaxed); break; } - if (changed.wait_for(lock, std::chrono::milliseconds(1), ready)) break; + if (poll(ready)) break; lock.unlock(); reapCompletionLabels(); lock.lock(); @@ -80,7 +91,8 @@ void Driver::run(std::uint32_t id) noexcept { if (id == 0) queue0Executing = submission.suspend ? 0 : submission.received; if (submission.waitFree) { orderHolders.fetch_add(1, std::memory_order_acq_rel); - while (!failure && !stopping && !orderReleased(id, submission.received)) changed.wait_for(lock, std::chrono::milliseconds(1)); + const auto released = [&] { return failure || stopping || orderReleased(id, submission.received); }; + while (!released()) poll(released); orderHolders.fetch_sub(1, std::memory_order_acq_rel); rethrowFailure(); }