Lock TextureManager/BufferManager during submission

Multiple threads concurrently accessing the `TextureManager`/`BufferManager` (Referred to as "resource managers") has a potential deadlock with a resource being locked while acquiring the resource manager lock while the thread owning it tries to acquire a lock on the resource resulting in a deadlock.

This has been fixed with locking of resource manager now being externally handled which ensures it can be locked prior to locking any resources, `CommandExecutor` provides accessors for retrieving the resource manager which automatically handles locking aside doing so on attachment of resources.
This commit is contained in:
PixelyIon
2022-06-26 14:58:58 +05:30
parent 1239907ce8
commit 0ac5f4ce27
9 changed files with 117 additions and 16 deletions

View File

@ -12,6 +12,18 @@ namespace skyline::gpu {
return it->guest->begin().base() < pointer;
}
void BufferManager::lock() {
mutex.lock();
}
void BufferManager::unlock() {
mutex.unlock();
}
bool BufferManager::try_lock() {
return mutex.try_lock();
}
BufferView BufferManager::FindOrCreate(GuestBuffer guestMapping, ContextTag tag) {
/*
* We align the buffer to the page boundary to ensure that:
@ -22,8 +34,6 @@ namespace skyline::gpu {
vk::DeviceSize offset{static_cast<size_t>(guestMapping.begin().base() - alignedStart)}, size{guestMapping.size()};
guestMapping = span<u8>{alignedStart, alignedEnd};
std::scoped_lock lock(mutex);
// Lookup for any buffers overlapping with the supplied guest mapping
boost::container::small_vector<std::shared_ptr<Buffer>, 4> overlaps;
for (auto entryIt{std::lower_bound(buffers.begin(), buffers.end(), guestMapping.end().base(), BufferLessThan)}; entryIt != buffers.begin() && (*--entryIt)->guest->begin() <= guestMapping.end();)
@ -89,7 +99,9 @@ namespace skyline::gpu {
return newBuffer->GetView(static_cast<vk::DeviceSize>(guestMapping.begin() - newBuffer->guest->begin()) + offset, size);
}
BufferManager::MegaBufferSlot::MegaBufferSlot(GPU &gpu) : backing(gpu.memory.AllocateBuffer(Size)) {}
constexpr static vk::DeviceSize MegaBufferSize{100 * 1024 * 1024}; //!< Size in bytes of the megabuffer (100MiB)
BufferManager::MegaBufferSlot::MegaBufferSlot(GPU &gpu) : backing(gpu.memory.AllocateBuffer(MegaBufferSize)) {}
MegaBuffer::MegaBuffer(BufferManager::MegaBufferSlot &slot) : slot{&slot}, freeRegion{slot.backing.subspan(PAGE_SIZE)} {}
@ -135,7 +147,7 @@ namespace skyline::gpu {
}
MegaBuffer BufferManager::AcquireMegaBuffer(const std::shared_ptr<FenceCycle> &cycle) {
std::scoped_lock lock{mutex};
std::scoped_lock lock{megaBufferMutex};
for (auto &slot : megaBuffers) {
if (!slot.active.test_and_set(std::memory_order_acq_rel)) {