mirror of
https://github.com/Takiiiiiiii/strato.git
synced 2025-07-17 08:46:39 +00:00
Allow external synchronization for buffers
In certain situations such as constant buffer updates, we desire to use the guest buffer as a shadow buffer forwarding all writes directly to it while we update the host using inline buffer updates so they happen in-sequence. This requires special behavior as we cannot let any synchronization operations take place as they would break the shadow buffer, as a result, an external synchronization flag has been added to prevent this from happening. It should be noted that this flag is not respected for buffer recreation which will lead to UB, this can and will break updates in certain cases and this change isn't complete without buffer manager support.
This commit is contained in:
@ -45,12 +45,29 @@ namespace skyline::gpu {
|
||||
}
|
||||
|
||||
void Buffer::MarkGpuDirty() {
|
||||
if (dirtyState == DirtyState::GpuDirty)
|
||||
if (dirtyState == DirtyState::GpuDirty || externallySynchronized) {
|
||||
externallySynchronized = false; // We want to handle synchronize internally after the GPU work is done
|
||||
return;
|
||||
}
|
||||
gpu.state.nce->RetrapRegions(*trapHandle, false);
|
||||
dirtyState = DirtyState::GpuDirty;
|
||||
}
|
||||
|
||||
void Buffer::MarkExternallySynchronized() {
|
||||
TRACE_EVENT("gpu", "Buffer::MarkExternallySynchronized");
|
||||
if (externallySynchronized)
|
||||
return;
|
||||
|
||||
if (dirtyState == DirtyState::GpuDirty)
|
||||
std::memcpy(mirror.data(), backing.data(), mirror.size());
|
||||
else if (dirtyState == DirtyState::CpuDirty)
|
||||
std::memcpy(backing.data(), mirror.data(), mirror.size());
|
||||
|
||||
dirtyState = DirtyState::GpuDirty; // Any synchronization will take place on the GPU which in itself would make the buffer dirty
|
||||
gpu.state.nce->RetrapRegions(*trapHandle, false);
|
||||
externallySynchronized = true;
|
||||
}
|
||||
|
||||
void Buffer::WaitOnFence() {
|
||||
TRACE_EVENT("gpu", "Buffer::WaitOnFence");
|
||||
|
||||
@ -67,6 +84,9 @@ namespace skyline::gpu {
|
||||
|
||||
WaitOnFence();
|
||||
|
||||
if (externallySynchronized)
|
||||
return; // If the buffer is externally synchronized, we don't need to synchronize it
|
||||
|
||||
TRACE_EVENT("gpu", "Buffer::SynchronizeHost");
|
||||
|
||||
std::memcpy(backing.data(), mirror.data(), mirror.size());
|
||||
@ -81,12 +101,15 @@ namespace skyline::gpu {
|
||||
}
|
||||
|
||||
void Buffer::SynchronizeHostWithCycle(const std::shared_ptr<FenceCycle> &pCycle, bool rwTrap) {
|
||||
if (dirtyState != DirtyState::CpuDirty || !guest)
|
||||
if (dirtyState != DirtyState::CpuDirty || !guest || externallySynchronized)
|
||||
return;
|
||||
|
||||
if (!cycle.owner_before(pCycle))
|
||||
WaitOnFence();
|
||||
|
||||
if (externallySynchronized)
|
||||
return;
|
||||
|
||||
TRACE_EVENT("gpu", "Buffer::SynchronizeHostWithCycle");
|
||||
|
||||
std::memcpy(backing.data(), mirror.data(), mirror.size());
|
||||
@ -101,12 +124,15 @@ namespace skyline::gpu {
|
||||
}
|
||||
|
||||
void Buffer::SynchronizeGuest(bool skipTrap, bool skipFence) {
|
||||
if (dirtyState != DirtyState::GpuDirty || !guest)
|
||||
if (dirtyState != DirtyState::GpuDirty || !guest || externallySynchronized)
|
||||
return; // If the buffer has not been used on the GPU or there's no guest buffer, there is no need to synchronize it
|
||||
|
||||
if (!skipFence)
|
||||
WaitOnFence();
|
||||
|
||||
if (externallySynchronized)
|
||||
return; // If the buffer is externally synchronized, we don't need to synchronize it
|
||||
|
||||
TRACE_EVENT("gpu", "Buffer::SynchronizeGuest");
|
||||
|
||||
std::memcpy(mirror.data(), backing.data(), mirror.size());
|
||||
@ -131,6 +157,9 @@ namespace skyline::gpu {
|
||||
};
|
||||
|
||||
void Buffer::SynchronizeGuestWithCycle(const std::shared_ptr<FenceCycle> &pCycle) {
|
||||
if (!guest)
|
||||
return; // If there's no guest buffer, there is no need to synchronize it
|
||||
|
||||
if (!cycle.owner_before(pCycle))
|
||||
WaitOnFence();
|
||||
|
||||
@ -139,16 +168,16 @@ namespace skyline::gpu {
|
||||
}
|
||||
|
||||
void Buffer::Read(span<u8> data, vk::DeviceSize offset) {
|
||||
if (dirtyState == DirtyState::CpuDirty || dirtyState == DirtyState::Clean)
|
||||
if (externallySynchronized || dirtyState == DirtyState::CpuDirty || dirtyState == DirtyState::Clean)
|
||||
std::memcpy(data.data(), mirror.data() + offset, data.size());
|
||||
else if (dirtyState == DirtyState::GpuDirty)
|
||||
std::memcpy(data.data(), backing.data() + offset, data.size());
|
||||
}
|
||||
|
||||
void Buffer::Write(span<u8> data, vk::DeviceSize offset, bool skipCleanHostWrite) {
|
||||
if (dirtyState == DirtyState::CpuDirty || dirtyState == DirtyState::Clean)
|
||||
void Buffer::Write(span<u8> data, vk::DeviceSize offset) {
|
||||
if (externallySynchronized || dirtyState == DirtyState::CpuDirty || dirtyState == DirtyState::Clean)
|
||||
std::memcpy(mirror.data() + offset, data.data(), data.size());
|
||||
if ((!skipCleanHostWrite && dirtyState == DirtyState::Clean) || dirtyState == DirtyState::GpuDirty)
|
||||
if (!externallySynchronized && ((dirtyState == DirtyState::Clean) || dirtyState == DirtyState::GpuDirty))
|
||||
std::memcpy(backing.data() + offset, data.data(), data.size());
|
||||
}
|
||||
|
||||
@ -234,7 +263,7 @@ namespace skyline::gpu {
|
||||
bufferDelegate->buffer->Read(data, offset + bufferDelegate->view->offset);
|
||||
}
|
||||
|
||||
void BufferView::Write(span<u8> data, vk::DeviceSize offset, bool skipCleanHostWrite) const {
|
||||
bufferDelegate->buffer->Write(data, offset + bufferDelegate->view->offset, skipCleanHostWrite);
|
||||
void BufferView::Write(span<u8> data, vk::DeviceSize offset) const {
|
||||
bufferDelegate->buffer->Write(data, offset + bufferDelegate->view->offset);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user