mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 18:01:49 +01:00
Fix Buffer::SynchronizeGuest
Non-Blocking Behavior
The buffer's non-blocking behavior could lead to an invalid state where the dirty state doesn't adequately represent the buffer's true state, the check has now been moved inside the CAS loop as its behavior changes depending on the dirty state. In addition, `SynchronizeGuest` returns a boolean denoting if the synchronization was successful now to make code flows depending on non-blocking synchronization cleaner.
This commit is contained in:
parent
c1f2445772
commit
745d809e07
@ -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<void()> &flushHostCallback) {
|
||||
@ -231,10 +232,8 @@ namespace skyline::gpu {
|
||||
}
|
||||
|
||||
std::pair<u64, span<u8>> 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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user