From 5129d2ae789de1b4b7794a817dcd839191c9b2be Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Sun, 5 Jun 2022 15:50:49 +0530 Subject: [PATCH] Add move-assignment semantics to `ActiveCommandBuffer`/`MegaBuffer` We need move-assignment semantics to viably utilize these objects as class members, they cannot be replaced without move-assign (or copy-assign but that is undesirable here). This commit fixes that by introducing a move assignment operator to them while making the `slot` a pointer which has the necessary nullability semantics. --- .../main/cpp/skyline/gpu/buffer_manager.cpp | 28 +++++++++++------ app/src/main/cpp/skyline/gpu/buffer_manager.h | 4 ++- .../main/cpp/skyline/gpu/command_scheduler.h | 31 ++++++++++++------- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/buffer_manager.cpp b/app/src/main/cpp/skyline/gpu/buffer_manager.cpp index 90e627c4..04b64def 100644 --- a/app/src/main/cpp/skyline/gpu/buffer_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/buffer_manager.cpp @@ -91,18 +91,28 @@ namespace skyline::gpu { BufferManager::MegaBufferSlot::MegaBufferSlot(GPU &gpu) : backing(gpu.memory.AllocateBuffer(Size)) {} - MegaBuffer::MegaBuffer(BufferManager::MegaBufferSlot &slot) : slot{slot}, freeRegion{slot.backing.subspan(PAGE_SIZE)} {} + MegaBuffer::MegaBuffer(BufferManager::MegaBufferSlot &slot) : slot{&slot}, freeRegion{slot.backing.subspan(PAGE_SIZE)} {} MegaBuffer::~MegaBuffer() { - slot.active.clear(std::memory_order_release); + if (slot) + slot->active.clear(std::memory_order_release); + } + + MegaBuffer &MegaBuffer::operator=(MegaBuffer &&other) { + if (slot) + slot->active.clear(std::memory_order_release); + slot = other.slot; + freeRegion = other.freeRegion; + other.slot = nullptr; + return *this; } void MegaBuffer::Reset() { - freeRegion = slot.backing.subspan(PAGE_SIZE); + freeRegion = slot->backing.subspan(PAGE_SIZE); } vk::Buffer MegaBuffer::GetBacking() const { - return slot.backing.vkBuffer; + return slot->backing.vkBuffer; } vk::DeviceSize MegaBuffer::Push(span data, bool pageAlign) { @@ -111,8 +121,8 @@ namespace skyline::gpu { if (pageAlign) { // If page aligned data was requested then align the free - auto alignedFreeBase{util::AlignUp(static_cast(freeRegion.data() - slot.backing.data()), PAGE_SIZE)}; - freeRegion = slot.backing.subspan(alignedFreeBase); + auto alignedFreeBase{util::AlignUp(static_cast(freeRegion.data() - slot->backing.data()), PAGE_SIZE)}; + freeRegion = slot->backing.subspan(alignedFreeBase); } // Allocate space for data from the free region @@ -121,11 +131,11 @@ namespace skyline::gpu { // Move the free region along freeRegion = freeRegion.subspan(data.size()); - return static_cast(resultSpan.data() - slot.backing.data()); + return static_cast(resultSpan.data() - slot->backing.data()); } MegaBuffer BufferManager::AcquireMegaBuffer(const std::shared_ptr &cycle) { - std::lock_guard lock{mutex}; + std::scoped_lock lock{mutex}; for (auto &slot : megaBuffers) { if (!slot.active.test_and_set(std::memory_order_acq_rel)) { @@ -138,7 +148,7 @@ namespace skyline::gpu { } } - auto& megaBuffer{megaBuffers.emplace_back(gpu)}; + auto &megaBuffer{megaBuffers.emplace_back(gpu)}; megaBuffer.cycle = cycle; return {megaBuffer}; } diff --git a/app/src/main/cpp/skyline/gpu/buffer_manager.h b/app/src/main/cpp/skyline/gpu/buffer_manager.h index 6319ce7c..dad387de 100644 --- a/app/src/main/cpp/skyline/gpu/buffer_manager.h +++ b/app/src/main/cpp/skyline/gpu/buffer_manager.h @@ -60,7 +60,7 @@ namespace skyline::gpu { */ class MegaBuffer { private: - BufferManager::MegaBufferSlot &slot; + BufferManager::MegaBufferSlot *slot; span freeRegion; //!< The unallocated space in the megabuffer public: @@ -68,6 +68,8 @@ namespace skyline::gpu { ~MegaBuffer(); + MegaBuffer &operator=(MegaBuffer &&other); + /** * @brief Resets the free region of the megabuffer to its initial state, data is left intact but may be overwritten */ diff --git a/app/src/main/cpp/skyline/gpu/command_scheduler.h b/app/src/main/cpp/skyline/gpu/command_scheduler.h index 7ac4c6cf..816112f1 100644 --- a/app/src/main/cpp/skyline/gpu/command_scheduler.h +++ b/app/src/main/cpp/skyline/gpu/command_scheduler.h @@ -46,29 +46,38 @@ namespace skyline::gpu { */ class ActiveCommandBuffer { private: - CommandBufferSlot &slot; + CommandBufferSlot *slot; public: - constexpr ActiveCommandBuffer(CommandBufferSlot &slot) : slot(slot) {} + constexpr ActiveCommandBuffer(CommandBufferSlot &slot) : slot{&slot} {} + + constexpr ActiveCommandBuffer &operator=(ActiveCommandBuffer &&other) { + if (slot) + slot->active.clear(std::memory_order_release); + slot = other.slot; + other.slot = nullptr; + return *this; + } ~ActiveCommandBuffer() { - slot.active.clear(std::memory_order_release); + if (slot) + slot->active.clear(std::memory_order_release); } vk::Fence GetFence() { - return *slot.fence; + return *slot->fence; } std::shared_ptr GetFenceCycle() { - return slot.cycle; + return slot->cycle; } vk::raii::CommandBuffer &operator*() { - return slot.commandBuffer; + return slot->commandBuffer; } vk::raii::CommandBuffer *operator->() { - return &slot.commandBuffer; + return &slot->commandBuffer; } /** @@ -76,10 +85,10 @@ namespace skyline::gpu { * @note This should be used when a single allocated command buffer is used for all submissions from a component */ std::shared_ptr Reset() { - slot.cycle->Wait(); - slot.cycle = std::make_shared(slot.device, *slot.fence); - slot.commandBuffer.reset(); - return slot.cycle; + slot->cycle->Wait(); + slot->cycle = std::make_shared(slot->device, *slot->fence); + slot->commandBuffer.reset(); + return slot->cycle; } };