Remove now redundant buffer/texture/megabuffer manager locks

They have been superseeded by the global channel lock
This commit is contained in:
Billy Laws 2022-10-09 16:32:59 +01:00
parent f5a141a621
commit 05581f2230
17 changed files with 28 additions and 154 deletions

View File

@ -11,18 +11,6 @@ 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();
}
BufferManager::LockedBuffer::LockedBuffer(std::shared_ptr<Buffer> pBuffer, ContextTag tag) : buffer{std::move(pBuffer)}, lock{tag, *buffer}, stateLock(buffer->stateMutex) {}
Buffer *BufferManager::LockedBuffer::operator->() const {

View File

@ -15,7 +15,6 @@ namespace skyline::gpu {
class BufferManager {
private:
GPU &gpu;
std::mutex mutex; //!< Synchronizes access to the buffer mappings
std::vector<std::shared_ptr<Buffer>> bufferMappings; //!< A sorted vector of all buffer mappings
LinearAllocatorState<> delegateAllocatorState; //!< Linear allocator used to allocate buffer delegates
size_t nextBufferId{}; //!< The next unique buffer id to be assigned

View File

@ -126,33 +126,18 @@ namespace skyline::gpu::interconnect {
}
void CommandExecutor::RotateRecordSlot() {
if (slot)
if (slot) {
slot->capt = capt;
recordThread.ReleaseSlot(slot);
}
capt = false;
slot = recordThread.AcquireSlot();
cycle = slot->Reset(gpu);
slot->executionNumber = executionNumber;
allocator = &slot->allocator;
}
TextureManager &CommandExecutor::AcquireTextureManager() {
if (!textureManagerLock)
textureManagerLock.emplace(gpu.texture);
return gpu.texture;
}
BufferManager &CommandExecutor::AcquireBufferManager() {
if (!bufferManagerLock)
bufferManagerLock.emplace(gpu.buffer);
return gpu.buffer;
}
MegaBufferAllocator &CommandExecutor::AcquireMegaBufferAllocator() {
if (!megaBufferAllocatorLock)
megaBufferAllocatorLock.emplace(gpu.megaBufferAllocator);
return gpu.megaBufferAllocator;
}
bool CommandExecutor::CreateRenderPassWithSubpass(vk::Rect2D renderArea, span<TextureView *> inputAttachments, span<TextureView *> colorAttachments, TextureView *depthStencilAttachment, bool noSubpassCreation) {
auto addSubpass{[&] {
renderPass->AddSubpass(inputAttachments, colorAttachments, depthStencilAttachment, gpu);
@ -230,10 +215,6 @@ namespace skyline::gpu::interconnect {
}
bool CommandExecutor::AttachTexture(TextureView *view) {
if (!textureManagerLock)
// Avoids a potential deadlock with this resource being locked while acquiring the TextureManager lock while the thread owning it tries to acquire a lock on this texture
textureManagerLock.emplace(gpu.texture);
bool didLock{view->LockWithTag(tag)};
if (didLock) {
if (view->texture->FrequentlyLocked())
@ -259,10 +240,6 @@ namespace skyline::gpu::interconnect {
}
bool CommandExecutor::AttachBuffer(BufferView &view) {
if (!bufferManagerLock)
// See AttachTexture(...)
bufferManagerLock.emplace(gpu.buffer);
bool didLock{view.LockWithTag(tag)};
if (didLock) {
if (view.GetBuffer()->FrequentlyLocked())
@ -274,10 +251,6 @@ namespace skyline::gpu::interconnect {
}
void CommandExecutor::AttachLockedBufferView(BufferView &view, ContextLock<BufferView> &&lock) {
if (!bufferManagerLock)
// See AttachTexture(...)
bufferManagerLock.emplace(gpu.buffer);
if (lock.OwnsLock()) {
// Transfer ownership to executor so that the resource will stay locked for the period it is used on the GPU
if (view.GetBuffer()->FrequentlyLocked())
@ -423,10 +396,7 @@ namespace skyline::gpu::interconnect {
void CommandExecutor::ResetInternal() {
attachedTextures.clear();
textureManagerLock.reset();
attachedBuffers.clear();
bufferManagerLock.reset();
megaBufferAllocatorLock.reset();
allocator->Reset();
// Periodically clear preserve attachments just in case there are new waiters which would otherwise end up waiting forever

View File

@ -74,9 +74,6 @@ namespace skyline::gpu::interconnect {
CommandRecordThread::Slot *slot{};
node::RenderPassNode *renderPass{};
size_t subpassCount{}; //!< The number of subpasses in the current render pass
std::optional<std::scoped_lock<TextureManager>> textureManagerLock; //!< The lock on the texture manager, this is locked for the duration of the command execution from the first usage inside an execution to the submission
std::optional<std::scoped_lock<BufferManager>> bufferManagerLock; //!< The lock on the buffer manager, see above for details
std::optional<std::scoped_lock<MegaBufferAllocator>> megaBufferAllocatorLock; //!< The lock on the megabuffer allocator, see above for details
bool preserveLocked{};
/**
@ -160,17 +157,12 @@ namespace skyline::gpu::interconnect {
ContextTag tag; //!< The tag associated with this command executor, any tagged resource locking must utilize this tag
size_t submissionNumber{};
u32 executionNumber{};
bool capt{};
CommandExecutor(const DeviceState &state);
~CommandExecutor();
/**
* @return A reference to an instance of the Texture Manager which will be locked till execution
* @note Any access to the texture manager while recording commands **must** be done via this
*/
TextureManager &AcquireTextureManager();
/**
* @brief Attach the lifetime of the texture to the command buffer
* @return If this is the first usage of the backing of this resource within this execution
@ -179,12 +171,6 @@ namespace skyline::gpu::interconnect {
*/
bool AttachTexture(TextureView *view);
/**
* @return A reference to an instance of the Buffer Manager which will be locked till execution
* @note Any access to the buffer manager while recording commands **must** be done via this
*/
BufferManager &AcquireBufferManager();
/**
* @brief Attach the lifetime of a buffer view to the command buffer
* @return If this is the first usage of the backing of this resource within this execution
@ -193,12 +179,6 @@ namespace skyline::gpu::interconnect {
*/
bool AttachBuffer(BufferView &view);
/**
* @return A reference to an instance of the megabuffer allocator which will be locked till execution
* @note Any access to the megabuffer allocator while recording commands **must** be done via this
*/
MegaBufferAllocator &AcquireMegaBufferAllocator();
/**
* @brief Attach the lifetime of a buffer view that's already locked to the command buffer
* @note The supplied buffer **must** be locked with the executor's tag

View File

@ -113,11 +113,10 @@ namespace skyline::gpu::interconnect {
auto srcGuestTexture{GetGuestTexture(srcSurface)};
auto dstGuestTexture{GetGuestTexture(dstSurface)};
auto &textureManager{executor.AcquireTextureManager()};
auto srcTextureView{textureManager.FindOrCreate(srcGuestTexture, executor.tag)};
auto srcTextureView{gpu.texture.FindOrCreate(srcGuestTexture, executor.tag)};
executor.AttachTexture(srcTextureView.get());
auto dstTextureView{textureManager.FindOrCreate(dstGuestTexture, executor.tag)};
auto dstTextureView{gpu.texture.FindOrCreate(dstGuestTexture, executor.tag)};
executor.AttachTexture(dstTextureView.get());
// Blit shader always samples from centre so adjust if necessary

View File

@ -745,7 +745,7 @@ namespace skyline::gpu::interconnect {
void ConstantBufferUpdate(span<u32> data, u32 offset) {
auto constantBuffer{GetConstantBufferSelector()};
if (constantBuffer)
constantBuffer->Write<u32>(executor, executor.AcquireMegaBufferAllocator(), data, offset);
constantBuffer->Write<u32>(executor, gpu.megaBufferAllocator, data, offset);
else
throw exception("Attempting to write to invalid constant buffer!");
}
@ -1148,7 +1148,7 @@ namespace skyline::gpu::interconnect {
auto &view{*pipelineStage.constantBuffers[constantBuffer.index].view};
executor.AttachBuffer(view);
if (auto megaBufferAllocation{view.AcquireMegaBuffer(executor.cycle, executor.AcquireMegaBufferAllocator())}) {
if (auto megaBufferAllocation{view.AcquireMegaBuffer(executor.cycle, gpu.megaBufferAllocator)}) {
// If the buffer is megabuffered then since we don't get out data from the underlying buffer, rather the megabuffer which stays consistent throughout a single execution, we can skip registering usage
bufferDescriptors[bufferIndex] = vk::DescriptorBufferInfo{
.buffer = megaBufferAllocation.buffer,
@ -1741,7 +1741,7 @@ namespace skyline::gpu::interconnect {
*/
MegaBufferAllocator::Allocation GetIndexedQuadConversionBuffer(u32 count, u32 first) {
vk::DeviceSize size{conversion::quads::GetRequiredBufferSize(count, indexBuffer.GetIndexSize())};
auto allocation{executor.AcquireMegaBufferAllocator().Allocate(executor.cycle, size)};
auto allocation{gpu.megaBufferAllocator.Allocate(executor.cycle, size)};
ContextLock lock{executor.tag, indexBuffer.view};
auto guestIndexBuffer{indexBuffer.view.GetReadOnlyBackingSpan(lock.IsFirstUsage(), []() {
@ -3045,7 +3045,7 @@ namespace skyline::gpu::interconnect {
executor.AttachBuffer(indexBufferView);
boundIndexBuffer->type = indexBuffer.type;
if (auto megaBufferAllocation{indexBufferView.AcquireMegaBuffer(executor.cycle, executor.AcquireMegaBufferAllocator())}) {
if (auto megaBufferAllocation{indexBufferView.AcquireMegaBuffer(executor.cycle, gpu.megaBufferAllocator)}) {
// If the buffer is megabuffered then since we don't get out data from the underlying buffer, rather the megabuffer which stays consistent throughout a single execution, we can skip registering usage
boundIndexBuffer->handle = megaBufferAllocation.buffer;
boundIndexBuffer->offset = megaBufferAllocation.offset;
@ -3088,7 +3088,7 @@ namespace skyline::gpu::interconnect {
auto &vertexBufferView{vertexBuffer->view};
executor.AttachBuffer(vertexBufferView);
if (auto megaBufferAllocation{vertexBufferView.AcquireMegaBuffer(executor.cycle, executor.AcquireMegaBufferAllocator())}) {
if (auto megaBufferAllocation{vertexBufferView.AcquireMegaBuffer(executor.cycle, gpu.megaBufferAllocator)}) {
// If the buffer is megabuffered then since we don't get out data from the underlying buffer, rather the megabuffer which stays consistent throughout a single execution, we can skip registering usage
boundVertexBuffers->handles[index] = megaBufferAllocation.buffer;
boundVertexBuffers->offsets[index] = megaBufferAllocation.offset;

View File

@ -29,7 +29,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
if (*view) {
ctx.executor.AttachBuffer(*view);
if (megaBufferBinding = view->TryMegaBuffer(ctx.executor.cycle, ctx.executor.AcquireMegaBufferAllocator(), ctx.executor.executionNumber);
if (megaBufferBinding = view->TryMegaBuffer(ctx.executor.cycle, ctx.gpu.megaBufferAllocator, ctx.executor.executionNumber);
megaBufferBinding)
builder.SetVertexBuffer(index, megaBufferBinding);
else
@ -43,12 +43,12 @@ namespace skyline::gpu::interconnect::maxwell3d {
// TODO: null descriptor
megaBufferBinding = {};
builder.SetVertexBuffer(index, {ctx.executor.AcquireMegaBufferAllocator().Allocate(ctx.executor.cycle, 0).buffer});
builder.SetVertexBuffer(index, {ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, 0).buffer});
}
bool VertexBufferState::Refresh(InterconnectContext &ctx, StateUpdateBuilder &builder) {
if (megaBufferBinding) {
if (auto newMegaBufferBinding{view->TryMegaBuffer(ctx.executor.cycle, ctx.executor.AcquireMegaBufferAllocator(), ctx.executor.executionNumber)};
if (auto newMegaBufferBinding{view->TryMegaBuffer(ctx.executor.cycle, ctx.gpu.megaBufferAllocator, ctx.executor.executionNumber)};
newMegaBufferBinding != megaBufferBinding) {
megaBufferBinding = newMegaBufferBinding;
@ -101,7 +101,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
size_t indexSize{1U << static_cast<u32>(indexType)};
vk::DeviceSize indexBufferSize{conversion::quads::GetRequiredBufferSize(elementCount, indexSize)};
auto quadConversionAllocation{ctx.executor.AcquireMegaBufferAllocator().Allocate(ctx.executor.cycle, indexBufferSize)};
auto quadConversionAllocation{ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, indexBufferSize)};
conversion::quads::GenerateIndexedQuadConversionBuffer(quadConversionAllocation.region.data(), viewSpan.data(), elementCount, ConvertIndexType(indexType));
@ -133,7 +133,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
if (quadConversion)
megaBufferBinding = GenerateQuadConversionIndexBuffer(ctx, engine->indexBuffer.indexSize, *view, elementCount);
else
megaBufferBinding = view->TryMegaBuffer(ctx.executor.cycle, ctx.executor.AcquireMegaBufferAllocator(), ctx.executor.executionNumber);
megaBufferBinding = view->TryMegaBuffer(ctx.executor.cycle, ctx.gpu.megaBufferAllocator, ctx.executor.executionNumber);
if (megaBufferBinding)
builder.SetIndexBuffer(megaBufferBinding, indexType);
@ -153,7 +153,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
megaBufferBinding = GenerateQuadConversionIndexBuffer(ctx, engine->indexBuffer.indexSize, *view, elementCount);
builder.SetIndexBuffer(megaBufferBinding, indexType);
} else if (megaBufferBinding) {
if (auto newMegaBufferBinding{view->TryMegaBuffer(ctx.executor.cycle, ctx.executor.AcquireMegaBufferAllocator(), ctx.executor.executionNumber)};
if (auto newMegaBufferBinding{view->TryMegaBuffer(ctx.executor.cycle, ctx.gpu.megaBufferAllocator, ctx.executor.executionNumber)};
newMegaBufferBinding != megaBufferBinding) {
megaBufferBinding = newMegaBufferBinding;
@ -196,7 +196,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
}
// Bind an empty buffer ourselves since Vulkan doesn't support passing a VK_NULL_HANDLE xfb buffer
builder.SetTransformFeedbackBuffer(index, {ctx.executor.AcquireMegaBufferAllocator().Allocate(ctx.executor.cycle, 0).buffer});
builder.SetTransformFeedbackBuffer(index, {ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, 0).buffer});
}
}

View File

@ -37,7 +37,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
return;
// Otherwise perform a full lookup
view = ctx.executor.AcquireBufferManager().FindOrCreate(viewMapping, ctx.executor.tag, [&ctx](std::shared_ptr<Buffer> buffer, ContextLock<Buffer> &&lock) {
view = ctx.gpu.buffer.FindOrCreate(viewMapping, ctx.executor.tag, [&ctx](std::shared_ptr<Buffer> buffer, ContextLock<Buffer> &&lock) {
ctx.executor.AttachLockedBuffer(buffer, std::move(lock));
});
}

View File

@ -39,7 +39,6 @@ namespace skyline::gpu::interconnect::maxwell3d {
}
void ConstantBuffer::Read(CommandExecutor &executor, span<u8> dstBuffer, size_t srcOffset) {
executor.AcquireBufferManager();
ContextLock lock{executor.tag, view};
view.Read(lock.IsFirstUsage(), FlushHostCallback, dstBuffer, srcOffset);
}
@ -54,7 +53,6 @@ namespace skyline::gpu::interconnect::maxwell3d {
auto &view{*selectorState.UpdateGet(ctx, data.size_bytes()).view};
auto srcCpuBuf{data.cast<u8>()};
ctx.executor.AcquireBufferManager();
ContextLock lock{ctx.executor.tag, view};
// First attempt the write without setting up the gpu copy callback as a fast path
@ -73,7 +71,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
// This will prevent any CPU accesses to backing for the duration of the usage
callbackData.view.GetBuffer()->BlockAllCpuBackingWrites();
auto srcGpuAllocation{callbackData.ctx.executor.AcquireMegaBufferAllocator().Push(callbackData.ctx.executor.cycle, callbackData.srcCpuBuf)};
auto srcGpuAllocation{callbackData.ctx.gpu.megaBufferAllocator.Push(callbackData.ctx.executor.cycle, callbackData.srcCpuBuf)};
callbackData.ctx.executor.AddOutsideRpCommand([=, srcCpuBuf = callbackData.srcCpuBuf, view = callbackData.view, offset = callbackData.offset](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &) {
vk::BufferCopy copyRegion{
.size = srcCpuBuf.size_bytes(),

View File

@ -617,12 +617,12 @@ namespace skyline::gpu::interconnect::maxwell3d {
static DynamicBufferBinding GetConstantBufferBinding(InterconnectContext &ctx, const Shader::Info &info, BufferView view, size_t idx) {
if (!view) // Return a dummy buffer if the constant buffer isn't bound
return BufferBinding{ctx.executor.AcquireMegaBufferAllocator().Allocate(ctx.executor.cycle, 0).buffer, 0, PAGE_SIZE};
return BufferBinding{ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, 0).buffer, 0, PAGE_SIZE};
ctx.executor.AttachBuffer(view);
size_t sizeOverride{std::min<size_t>(info.constant_buffer_used_sizes[idx], view.size)};
if (auto megaBufferBinding{view.TryMegaBuffer(ctx.executor.cycle, ctx.executor.AcquireMegaBufferAllocator(), ctx.executor.executionNumber, sizeOverride)}) {
if (auto megaBufferBinding{view.TryMegaBuffer(ctx.executor.cycle, ctx.gpu.megaBufferAllocator, ctx.executor.executionNumber, sizeOverride)}) {
return megaBufferBinding;
} else {
view.GetBuffer()->BlockSequencedCpuBackingWrites();
@ -645,7 +645,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
if (desc.is_written) {
view.GetBuffer()->MarkGpuDirty();
} else {
if (auto megaBufferBinding{view.TryMegaBuffer(ctx.executor.cycle, ctx.executor.AcquireMegaBufferAllocator(), ctx.executor.executionNumber)})
if (auto megaBufferBinding{view.TryMegaBuffer(ctx.executor.cycle, ctx.gpu.megaBufferAllocator, ctx.executor.executionNumber)})
return megaBufferBinding;
}

View File

@ -312,7 +312,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
auto mappings{ctx.channelCtx.asCtx->gmmu.TranslateRange(textureHeader.Iova(), guest.GetSize())};
guest.mappings.assign(mappings.begin(), mappings.end());
texture = ctx.executor.AcquireTextureManager().FindOrCreate(guest, ctx.executor.tag);
texture = ctx.gpu.texture.FindOrCreate(guest, ctx.executor.tag);
}
textureHeaderCache[index] = {textureHeader, texture.get(), ctx.executor.executionNumber};

View File

@ -49,18 +49,6 @@ namespace skyline::gpu {
MegaBufferAllocator::MegaBufferAllocator(GPU &gpu) : gpu{gpu}, activeChunk{chunks.emplace(chunks.end(), gpu)} {}
void MegaBufferAllocator::lock() {
mutex.lock();
}
void MegaBufferAllocator::unlock() {
mutex.unlock();
}
bool MegaBufferAllocator::try_lock() {
return mutex.try_lock();
}
MegaBufferAllocator::Allocation MegaBufferAllocator::Allocate(const std::shared_ptr<FenceCycle> &cycle, vk::DeviceSize size, bool pageAlign) {
if (auto allocation{activeChunk->Allocate(cycle, size, pageAlign)}; allocation.first)
return {activeChunk->GetBacking(), allocation.first, allocation.second};

View File

@ -40,7 +40,6 @@ namespace skyline::gpu {
class MegaBufferAllocator {
private:
GPU &gpu;
std::mutex mutex;
std::list<MegaBufferChunk> chunks; //!< A pool of all allocated megabuffer chunks, these are dynamically utilized
decltype(chunks)::iterator activeChunk; //!< Currently active chunk of the megabuffer which is being allocated into
@ -60,24 +59,6 @@ namespace skyline::gpu {
MegaBufferAllocator(GPU &gpu);
/**
* @brief Acquires an exclusive lock on the allocator for the calling thread
* @note Naming is in accordance to the BasicLockable named requirement
*/
void lock();
/**
* @brief Relinquishes an existing lock on the allocator by the calling thread
* @note Naming is in accordance to the BasicLockable named requirement
*/
void unlock();
/**
* @brief Attempts to acquire an exclusive lock but returns immediately if it's captured by another thread
* @note Naming is in accordance to the Lockable named requirement
*/
bool try_lock();
/**
* @brief Allocates data in a megabuffer chunk and returns an structure describing the allocation
* @param pageAlign Whether the pushed data should be page aligned in the megabuffer

View File

@ -97,6 +97,8 @@ namespace skyline::gpu {
frame.fence.Wait(state.soc->host1x);
std::scoped_lock textureLock(*frame.textureView);
// std::this_thread::sleep_for(std::chrono::milliseconds(64));
auto texture{frame.textureView->texture};
if (frame.textureView->format != swapchainFormat || texture->dimensions != swapchainExtent)
UpdateSwapchain(frame.textureView->format, texture->dimensions);

View File

@ -6,18 +6,6 @@
namespace skyline::gpu {
TextureManager::TextureManager(GPU &gpu) : gpu(gpu) {}
void TextureManager::lock() {
mutex.lock();
}
void TextureManager::unlock() {
mutex.unlock();
}
bool TextureManager::try_lock() {
return mutex.try_lock();
}
std::shared_ptr<TextureView> TextureManager::FindOrCreate(const GuestTexture &guestTexture, ContextTag tag) {
auto guestMapping{guestTexture.mappings.front()};

View File

@ -26,30 +26,11 @@ namespace skyline::gpu {
};
GPU &gpu;
std::mutex mutex; //!< Synchronizes access to the texture mappings
std::vector<TextureMapping> textures; //!< A sorted vector of all texture mappings
public:
TextureManager(GPU &gpu);
/**
* @brief Acquires an exclusive lock on the texture for the calling thread
* @note Naming is in accordance to the BasicLockable named requirement
*/
void lock();
/**
* @brief Relinquishes an existing lock on the texture by the calling thread
* @note Naming is in accordance to the BasicLockable named requirement
*/
void unlock();
/**
* @brief Attempts to acquire an exclusive lock but returns immediately if it's captured by another thread
* @note Naming is in accordance to the Lockable named requirement
*/
bool try_lock();
/**
* @return A pre-existing or newly created Texture object which matches the specified criteria
* @note The texture manager **must** be locked prior to calling this

View File

@ -345,7 +345,7 @@ namespace skyline::service::hosbinder {
gpu::GuestTexture guestTexture(span<u8>{}, dimensions, format, tileConfig, vk::ImageViewType::e2D);
guestTexture.mappings[0] = span<u8>(nvMapHandleObj->GetPointer() + surface.offset, guestTexture.GetLayerStride());
std::scoped_lock textureLock{state.gpu->texture};
std::scoped_lock channelLock{state.gpu->channelLock};
buffer.texture = state.gpu->texture.FindOrCreate(guestTexture);
}