Set state to CpuDirty directly in SynchronizeGuest

`SynchronizeGuest` could only set the dirty state to `Clean` which was redundant since calls to it from inside the write trap handler would set it to `CpuDirty` directly after, this fixes that by doing it inside the function when necessary.
This commit is contained in:
PixelyIon 2022-07-13 22:09:09 +05:30
parent 4f6a67af36
commit c1f2445772
No known key found for this signature in database
GPG Key ID: 11BC6C3201BC2C05
4 changed files with 23 additions and 17 deletions

View File

@ -31,8 +31,7 @@ namespace skyline::gpu {
std::unique_lock lock{*this, std::try_to_lock}; std::unique_lock lock{*this, std::try_to_lock};
if (!lock) if (!lock)
return false; return false;
SynchronizeGuest(true); SynchronizeGuest(true, false, true); // We need to assume the buffer is dirty since we don't know what the guest is writing
dirtyState = DirtyState::CpuDirty; // We need to assume the buffer is dirty since we don't know what the guest is writing
return true; return true;
}); });
} }
@ -161,15 +160,15 @@ namespace skyline::gpu {
gpu.state.nce->RetrapRegions(*trapHandle, !rwTrap); // Trap any future CPU reads (optionally) + writes to this buffer gpu.state.nce->RetrapRegions(*trapHandle, !rwTrap); // Trap any future CPU reads (optionally) + writes to this buffer
} }
void Buffer::SynchronizeGuest(bool skipTrap, bool nonBlocking) { void Buffer::SynchronizeGuest(bool skipTrap, bool nonBlocking, bool setDirty) {
if (!guest) if (!guest)
return; return;
auto currentState{dirtyState.load(std::memory_order_relaxed)}; auto currentState{dirtyState.load(std::memory_order_relaxed)};
do { do {
if (currentState != DirtyState::GpuDirty) if (currentState == DirtyState::CpuDirty || (currentState == DirtyState::Clean && setDirty))
return; // If the buffer has not been used on the GPU, there is no need to synchronize it return; // If the buffer is synchronized (Clean/CpuDirty), there is no need to synchronize it
} while (!dirtyState.compare_exchange_strong(currentState, DirtyState::Clean, std::memory_order_relaxed)); } while (!dirtyState.compare_exchange_strong(currentState, setDirty ? DirtyState::CpuDirty : DirtyState::Clean, std::memory_order_relaxed));
if (nonBlocking && !PollFence()) if (nonBlocking && !PollFence())
return; return;
@ -179,6 +178,9 @@ namespace skyline::gpu {
if (!skipTrap) if (!skipTrap)
gpu.state.nce->RetrapRegions(*trapHandle, true); 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
if (!nonBlocking) if (!nonBlocking)
WaitOnFence(); WaitOnFence();

View File

@ -233,9 +233,10 @@ namespace skyline::gpu {
* @brief Synchronizes the guest buffer with the host buffer * @brief Synchronizes the guest buffer with the host buffer
* @param skipTrap If true, setting up a CPU trap will be skipped and the dirty state will be Clean/CpuDirty * @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 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
* @note The buffer **must** be locked prior to calling this * @note The buffer **must** be locked prior to calling this
*/ */
void SynchronizeGuest(bool skipTrap = false, bool nonBlocking = false); void 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 * @brief Synchronizes the guest buffer with the host buffer immediately, flushing GPU work if necessary

View File

@ -160,8 +160,7 @@ namespace skyline::gpu {
std::unique_lock lock{*this, std::try_to_lock}; std::unique_lock lock{*this, std::try_to_lock};
if (!lock) if (!lock)
return false; return false;
SynchronizeGuest(true); SynchronizeGuest(true, true); // We need to assume the texture is dirty since we don't know what the guest is writing
dirtyState = DirtyState::CpuDirty; // We need to assume the texture is dirty since we don't know what the guest is writing
WaitOnFence(); WaitOnFence();
return true; return true;
}); });
@ -555,9 +554,9 @@ namespace skyline::gpu {
} }
Texture::~Texture() { Texture::~Texture() {
SynchronizeGuest(true);
if (trapHandle) if (trapHandle)
gpu.state.nce->DeleteTrap(*trapHandle); gpu.state.nce->DeleteTrap(*trapHandle);
SynchronizeGuest(true);
if (alignedMirror.valid()) if (alignedMirror.valid())
munmap(alignedMirror.data(), alignedMirror.size()); munmap(alignedMirror.data(), alignedMirror.size());
WaitOnFence(); WaitOnFence();
@ -705,20 +704,23 @@ namespace skyline::gpu {
gpu.state.nce->RetrapRegions(*trapHandle, !rwTrap); // Trap any future CPU reads (optionally) + writes to this texture gpu.state.nce->RetrapRegions(*trapHandle, !rwTrap); // Trap any future CPU reads (optionally) + writes to this texture
} }
void Texture::SynchronizeGuest(bool skipTrap) { void Texture::SynchronizeGuest(bool skipTrap, bool setDirty) {
if (!guest) if (!guest)
return; return;
auto currentState{dirtyState.load(std::memory_order_relaxed)}; auto currentState{dirtyState.load(std::memory_order_relaxed)};
do { do {
if (currentState != DirtyState::GpuDirty) if (currentState == DirtyState::CpuDirty || (currentState == DirtyState::Clean && setDirty))
return; // If the buffer has not been used on the GPU, there is no need to synchronize it return; // If the texture is synchronized (Clean/CpuDirty), there is no need to synchronize it
} while (!dirtyState.compare_exchange_strong(currentState, DirtyState::Clean, std::memory_order_relaxed)); } while (!dirtyState.compare_exchange_strong(currentState, setDirty ? DirtyState::CpuDirty : DirtyState::Clean, std::memory_order_relaxed));
TRACE_EVENT("gpu", "Texture::SynchronizeGuest"); TRACE_EVENT("gpu", "Texture::SynchronizeGuest");
if (!skipTrap) if (!skipTrap)
gpu.state.nce->RetrapRegions(*trapHandle, true); gpu.state.nce->RetrapRegions(*trapHandle, !setDirty);
if (setDirty && currentState == DirtyState::Clean)
return; // If the texture was simply transitioned from Clean to CpuDirty, there is no need to synchronize it
if (layout == vk::ImageLayout::eUndefined || format != guest->format) if (layout == vk::ImageLayout::eUndefined || format != guest->format)
// If the state of the host texture is undefined then so can the guest // If the state of the host texture is undefined then so can the guest
@ -752,7 +754,7 @@ namespace skyline::gpu {
auto currentState{dirtyState.load(std::memory_order_relaxed)}; auto currentState{dirtyState.load(std::memory_order_relaxed)};
do { do {
if (currentState != DirtyState::GpuDirty) if (currentState != DirtyState::GpuDirty)
return; // If the buffer has not been used on the GPU, there is no need to synchronize it return; // If the texture has not been used on the GPU, there is no need to synchronize it
} while (!dirtyState.compare_exchange_strong(currentState, DirtyState::Clean, std::memory_order_relaxed)); } while (!dirtyState.compare_exchange_strong(currentState, DirtyState::Clean, std::memory_order_relaxed));
TRACE_EVENT("gpu", "Texture::SynchronizeGuestWithBuffer"); TRACE_EVENT("gpu", "Texture::SynchronizeGuestWithBuffer");

View File

@ -559,10 +559,11 @@ namespace skyline::gpu {
/** /**
* @brief Synchronizes the guest texture with the host texture after it has been modified * @brief Synchronizes the guest texture with the host texture after it has been modified
* @param skipTrap If true, setting up a CPU trap will be skipped and the dirty state will be Clean/CpuDirty * @param skipTrap If true, setting up a CPU trap will be skipped and the dirty state will be Clean/CpuDirty
* @param setDirty If true, the texture will be marked as CpuDirty rather than Clean
* @note The texture **must** be locked prior to calling this * @note The texture **must** be locked prior to calling this
* @note The guest texture should not be null prior to calling this * @note The guest texture should not be null prior to calling this
*/ */
void SynchronizeGuest(bool skipTrap = false); void SynchronizeGuest(bool skipTrap = false, bool setDirty = false);
/** /**
* @brief Synchronizes the guest texture with the host texture after it has been modified * @brief Synchronizes the guest texture with the host texture after it has been modified