mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-27 00:24:14 +01:00
Avoid waiting on texture/buffer fence with trapMutex locked
This could cause deadlocks under certain circumstances by preventing the GPFIFO from making any progress while also waiting on it at the same time.
This commit is contained in:
parent
3e8bd26978
commit
993ffb56f4
@ -23,11 +23,23 @@ namespace skyline::gpu {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
std::unique_lock stateLock{buffer->stateMutex};
|
std::unique_lock stateLock{buffer->stateMutex};
|
||||||
if (buffer->AllCpuBackingWritesBlocked()) {
|
if (buffer->AllCpuBackingWritesBlocked() || buffer->dirtyState == DirtyState::GpuDirty) {
|
||||||
stateLock.unlock(); // If the lock isn't unlocked, a deadlock from threads waiting on the other lock can occur
|
stateLock.unlock(); // If the lock isn't unlocked, a deadlock from threads waiting on the other lock can occur
|
||||||
|
|
||||||
// If this mutex would cause other callbacks to be blocked then we should block on this mutex in advance
|
// If this mutex would cause other callbacks to be blocked then we should block on this mutex in advance
|
||||||
std::scoped_lock lock{*buffer};
|
std::shared_ptr<FenceCycle> waitCycle{};
|
||||||
|
do {
|
||||||
|
if (waitCycle)
|
||||||
|
waitCycle->Wait();
|
||||||
|
|
||||||
|
std::scoped_lock lock{*buffer};
|
||||||
|
if (waitCycle && buffer->cycle == waitCycle) {
|
||||||
|
buffer->cycle = {};
|
||||||
|
waitCycle = {};
|
||||||
|
} else {
|
||||||
|
waitCycle = buffer->cycle;
|
||||||
|
}
|
||||||
|
} while (waitCycle);
|
||||||
}
|
}
|
||||||
}, [weakThis] {
|
}, [weakThis] {
|
||||||
TRACE_EVENT("gpu", "Buffer::ReadTrap");
|
TRACE_EVENT("gpu", "Buffer::ReadTrap");
|
||||||
@ -47,6 +59,9 @@ namespace skyline::gpu {
|
|||||||
if (!lock)
|
if (!lock)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (buffer->cycle)
|
||||||
|
return false;
|
||||||
|
|
||||||
buffer->SynchronizeGuest(true); // We can skip trapping since the caller will do it
|
buffer->SynchronizeGuest(true); // We can skip trapping since the caller will do it
|
||||||
return true;
|
return true;
|
||||||
}, [weakThis] {
|
}, [weakThis] {
|
||||||
@ -69,7 +84,9 @@ namespace skyline::gpu {
|
|||||||
if (!lock)
|
if (!lock)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
buffer->WaitOnFence();
|
if (buffer->cycle)
|
||||||
|
return false;
|
||||||
|
|
||||||
buffer->SynchronizeGuest(true); // We need to assume the buffer is dirty since we don't know what the guest is writing
|
buffer->SynchronizeGuest(true); // We need to assume the buffer is dirty since we don't know what the guest is writing
|
||||||
buffer->dirtyState = DirtyState::CpuDirty;
|
buffer->dirtyState = DirtyState::CpuDirty;
|
||||||
|
|
||||||
@ -128,8 +145,6 @@ namespace skyline::gpu {
|
|||||||
void Buffer::WaitOnFence() {
|
void Buffer::WaitOnFence() {
|
||||||
TRACE_EVENT("gpu", "Buffer::WaitOnFence");
|
TRACE_EVENT("gpu", "Buffer::WaitOnFence");
|
||||||
|
|
||||||
std::scoped_lock lock{stateMutex};
|
|
||||||
|
|
||||||
if (cycle) {
|
if (cycle) {
|
||||||
cycle->Wait();
|
cycle->Wait();
|
||||||
cycle = nullptr;
|
cycle = nullptr;
|
||||||
@ -137,8 +152,6 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::PollFence() {
|
bool Buffer::PollFence() {
|
||||||
std::scoped_lock lock{stateMutex};
|
|
||||||
|
|
||||||
if (!cycle)
|
if (!cycle)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -219,7 +232,6 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::Read(bool isFirstUsage, const std::function<void()> &flushHostCallback, span<u8> data, vk::DeviceSize offset) {
|
void Buffer::Read(bool isFirstUsage, const std::function<void()> &flushHostCallback, span<u8> data, vk::DeviceSize offset) {
|
||||||
std::scoped_lock lock{stateMutex};
|
|
||||||
if (dirtyState == DirtyState::GpuDirty)
|
if (dirtyState == DirtyState::GpuDirty)
|
||||||
SynchronizeGuestImmediate(isFirstUsage, flushHostCallback);
|
SynchronizeGuestImmediate(isFirstUsage, flushHostCallback);
|
||||||
|
|
||||||
|
@ -159,7 +159,19 @@ namespace skyline::gpu {
|
|||||||
stateLock.unlock(); // If the lock isn't unlocked, a deadlock from threads waiting on the other lock can occur
|
stateLock.unlock(); // If the lock isn't unlocked, a deadlock from threads waiting on the other lock can occur
|
||||||
|
|
||||||
// If this mutex would cause other callbacks to be blocked then we should block on this mutex in advance
|
// If this mutex would cause other callbacks to be blocked then we should block on this mutex in advance
|
||||||
std::scoped_lock lock{*texture};
|
std::shared_ptr<FenceCycle> waitCycle{};
|
||||||
|
do {
|
||||||
|
if (waitCycle)
|
||||||
|
waitCycle->Wait();
|
||||||
|
|
||||||
|
std::scoped_lock lock{*texture};
|
||||||
|
if (waitCycle && texture->cycle == waitCycle) {
|
||||||
|
texture->cycle = {};
|
||||||
|
waitCycle = {};
|
||||||
|
} else {
|
||||||
|
waitCycle = texture->cycle;
|
||||||
|
}
|
||||||
|
} while (waitCycle);
|
||||||
}
|
}
|
||||||
}, [weakThis] {
|
}, [weakThis] {
|
||||||
TRACE_EVENT("gpu", "Texture::ReadTrap");
|
TRACE_EVENT("gpu", "Texture::ReadTrap");
|
||||||
@ -179,6 +191,9 @@ namespace skyline::gpu {
|
|||||||
if (!lock)
|
if (!lock)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (texture->cycle)
|
||||||
|
return false;
|
||||||
|
|
||||||
texture->SynchronizeGuest(false, true); // We can skip trapping since the caller will do it
|
texture->SynchronizeGuest(false, true); // We can skip trapping since the caller will do it
|
||||||
return true;
|
return true;
|
||||||
}, [weakThis] {
|
}, [weakThis] {
|
||||||
@ -200,6 +215,10 @@ namespace skyline::gpu {
|
|||||||
std::unique_lock lock{*texture, std::try_to_lock};
|
std::unique_lock lock{*texture, std::try_to_lock};
|
||||||
if (!lock)
|
if (!lock)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (texture->cycle)
|
||||||
|
return false;
|
||||||
|
|
||||||
texture->SynchronizeGuest(true, true); // We need to assume the texture is dirty since we don't know what the guest is writing
|
texture->SynchronizeGuest(true, true); // We need to assume the texture is dirty since we don't know what the guest is writing
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user