Introduce Context semantics to GPU resource locking

Resources on the GPU can be fairly convoluted and involve overlaps which can lead to the same GPU resources being utilized with different views, we previously utilized fences to lock resources to prevent concurrent access but this was overly harsh as it would block usage of resources till GPU completion of the commands associated with a resource.

Fences have now been replaced with locks but locks run into the issue of being per-view and therefore to add a common object for tracking usage the concept of "tags" was introduced to track a single context so locks can be skipped if they're from the same context. This is important to prevent a deadlock when locking a resource which has been already locked from the current context with a different view.
This commit is contained in:
PixelyIon
2022-06-26 14:32:34 +05:30
parent d913f29662
commit 6b9269b88e
13 changed files with 336 additions and 111 deletions

View File

@ -106,6 +106,21 @@ namespace skyline::gpu {
}
}
bool TextureView::LockWithTag(ContextTag tag) {
auto backing{std::atomic_load(&texture)};
while (true) {
bool didLock{backing->LockWithTag(tag)};
auto latestBacking{std::atomic_load(&texture)};
if (backing == latestBacking)
return didLock;
if (didLock)
backing->unlock();
backing = latestBacking;
}
}
void TextureView::unlock() {
texture->unlock();
}
@ -564,12 +579,34 @@ namespace skyline::gpu {
}
Texture::~Texture() {
std::scoped_lock lock{*this};
if (trapHandle)
gpu.state.nce->DeleteTrap(*trapHandle);
SynchronizeGuest(true);
if (alignedMirror.valid())
munmap(alignedMirror.data(), alignedMirror.size());
WaitOnFence();
}
void Texture::lock() {
mutex.lock();
}
bool Texture::LockWithTag(ContextTag pTag) {
if (pTag && pTag == tag)
return false;
mutex.lock();
tag = pTag;
return true;
}
void Texture::unlock() {
tag = ContextTag{};
mutex.unlock();
}
bool Texture::try_lock() {
return mutex.try_lock();
}
void Texture::MarkGpuDirty() {