diff --git a/app/src/main/cpp/skyline/gpu/buffer.cpp b/app/src/main/cpp/skyline/gpu/buffer.cpp index 45e5af1d..3a1b0d5c 100644 --- a/app/src/main/cpp/skyline/gpu/buffer.cpp +++ b/app/src/main/cpp/skyline/gpu/buffer.cpp @@ -160,31 +160,32 @@ namespace skyline::gpu { gpu.state.nce->RetrapRegions(*trapHandle, !rwTrap); // Trap any future CPU reads (optionally) + writes to this buffer } - void Buffer::SynchronizeGuest(bool skipTrap, bool nonBlocking, bool setDirty) { + bool Buffer::SynchronizeGuest(bool skipTrap, bool nonBlocking, bool setDirty) { if (!guest) - return; + return false; auto currentState{dirtyState.load(std::memory_order_relaxed)}; do { if (currentState == DirtyState::CpuDirty || (currentState == DirtyState::Clean && setDirty)) - return; // If the buffer is synchronized (Clean/CpuDirty), there is no need to synchronize it + return true; // If the buffer is synchronized (Clean/CpuDirty), there is no need to synchronize it + else if (currentState == DirtyState::GpuDirty && nonBlocking && !PollFence()) + return false; // If the buffer is GPU dirty and the fence is not signalled then we can't block } while (!dirtyState.compare_exchange_strong(currentState, setDirty ? DirtyState::CpuDirty : DirtyState::Clean, std::memory_order_relaxed)); - if (nonBlocking && !PollFence()) - return; - TRACE_EVENT("gpu", "Buffer::SynchronizeGuest"); if (!skipTrap) gpu.state.nce->RetrapRegions(*trapHandle, true); if (setDirty && currentState == DirtyState::Clean) - return; // If the texture was simply transitioned from Clean to CpuDirty, there is no need to synchronize it + return true; // If the texture was simply transitioned from Clean to CpuDirty, there is no need to synchronize it if (!nonBlocking) WaitOnFence(); std::memcpy(mirror.data(), backing.data(), mirror.size()); + + return true; } void Buffer::SynchronizeGuestImmediate(bool isFirstUsage, const std::function &flushHostCallback) { @@ -231,10 +232,8 @@ namespace skyline::gpu { } std::pair> Buffer::AcquireCurrentSequence() { - SynchronizeGuest(false, true); // First try to remove GPU dirtiness by doing an immediate sync and taking a quick shower - - if (dirtyState == DirtyState::GpuDirty) - // Bail out if buffer is GPU dirty - since we don't know the contents ahead of time the sequence is indeterminate + if (!SynchronizeGuest(false, true)) + // Bail out if buffer cannot be synced, we don't know the contents ahead of time so the sequence is indeterminate return {}; SynchronizeHost(); // Ensure that the returned mirror is fully up-to-date by performing a CPU -> GPU sync diff --git a/app/src/main/cpp/skyline/gpu/buffer.h b/app/src/main/cpp/skyline/gpu/buffer.h index f7333833..7c533ed3 100644 --- a/app/src/main/cpp/skyline/gpu/buffer.h +++ b/app/src/main/cpp/skyline/gpu/buffer.h @@ -234,9 +234,10 @@ namespace skyline::gpu { * @param skipTrap If true, setting up a CPU trap will be skipped and the dirty state will be Clean/CpuDirty * @param nonBlocking If true, the call will return immediately if the fence is not signalled, skipping the sync * @param setDirty If true, the buffer will be marked as CpuDirty rather than Clean + * @return If the buffer's contents were successfully synchronized, this'll only be false on non-blocking operations or lack of a guest buffer * @note The buffer **must** be locked prior to calling this */ - void SynchronizeGuest(bool skipTrap = false, bool nonBlocking = false, bool setDirty = false); + bool SynchronizeGuest(bool skipTrap = false, bool nonBlocking = false, bool setDirty = false); /** * @brief Synchronizes the guest buffer with the host buffer immediately, flushing GPU work if necessary