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.
This commit is contained in:
PixelyIon 2022-06-05 15:50:49 +05:30
parent 8991ccac65
commit 5129d2ae78
No known key found for this signature in database
GPG Key ID: 11BC6C3201BC2C05
3 changed files with 42 additions and 21 deletions

View File

@ -91,18 +91,28 @@ namespace skyline::gpu {
BufferManager::MegaBufferSlot::MegaBufferSlot(GPU &gpu) : backing(gpu.memory.AllocateBuffer(Size)) {} 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() { 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() { void MegaBuffer::Reset() {
freeRegion = slot.backing.subspan(PAGE_SIZE); freeRegion = slot->backing.subspan(PAGE_SIZE);
} }
vk::Buffer MegaBuffer::GetBacking() const { vk::Buffer MegaBuffer::GetBacking() const {
return slot.backing.vkBuffer; return slot->backing.vkBuffer;
} }
vk::DeviceSize MegaBuffer::Push(span<u8> data, bool pageAlign) { vk::DeviceSize MegaBuffer::Push(span<u8> data, bool pageAlign) {
@ -111,8 +121,8 @@ namespace skyline::gpu {
if (pageAlign) { if (pageAlign) {
// If page aligned data was requested then align the free // If page aligned data was requested then align the free
auto alignedFreeBase{util::AlignUp(static_cast<size_t>(freeRegion.data() - slot.backing.data()), PAGE_SIZE)}; auto alignedFreeBase{util::AlignUp(static_cast<size_t>(freeRegion.data() - slot->backing.data()), PAGE_SIZE)};
freeRegion = slot.backing.subspan(alignedFreeBase); freeRegion = slot->backing.subspan(alignedFreeBase);
} }
// Allocate space for data from the free region // Allocate space for data from the free region
@ -121,11 +131,11 @@ namespace skyline::gpu {
// Move the free region along // Move the free region along
freeRegion = freeRegion.subspan(data.size()); freeRegion = freeRegion.subspan(data.size());
return static_cast<vk::DeviceSize>(resultSpan.data() - slot.backing.data()); return static_cast<vk::DeviceSize>(resultSpan.data() - slot->backing.data());
} }
MegaBuffer BufferManager::AcquireMegaBuffer(const std::shared_ptr<FenceCycle> &cycle) { MegaBuffer BufferManager::AcquireMegaBuffer(const std::shared_ptr<FenceCycle> &cycle) {
std::lock_guard lock{mutex}; std::scoped_lock lock{mutex};
for (auto &slot : megaBuffers) { for (auto &slot : megaBuffers) {
if (!slot.active.test_and_set(std::memory_order_acq_rel)) { if (!slot.active.test_and_set(std::memory_order_acq_rel)) {

View File

@ -60,7 +60,7 @@ namespace skyline::gpu {
*/ */
class MegaBuffer { class MegaBuffer {
private: private:
BufferManager::MegaBufferSlot &slot; BufferManager::MegaBufferSlot *slot;
span<u8> freeRegion; //!< The unallocated space in the megabuffer span<u8> freeRegion; //!< The unallocated space in the megabuffer
public: public:
@ -68,6 +68,8 @@ namespace skyline::gpu {
~MegaBuffer(); ~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 * @brief Resets the free region of the megabuffer to its initial state, data is left intact but may be overwritten
*/ */

View File

@ -46,29 +46,38 @@ namespace skyline::gpu {
*/ */
class ActiveCommandBuffer { class ActiveCommandBuffer {
private: private:
CommandBufferSlot &slot; CommandBufferSlot *slot;
public: 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() { ~ActiveCommandBuffer() {
slot.active.clear(std::memory_order_release); if (slot)
slot->active.clear(std::memory_order_release);
} }
vk::Fence GetFence() { vk::Fence GetFence() {
return *slot.fence; return *slot->fence;
} }
std::shared_ptr<FenceCycle> GetFenceCycle() { std::shared_ptr<FenceCycle> GetFenceCycle() {
return slot.cycle; return slot->cycle;
} }
vk::raii::CommandBuffer &operator*() { vk::raii::CommandBuffer &operator*() {
return slot.commandBuffer; return slot->commandBuffer;
} }
vk::raii::CommandBuffer *operator->() { 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 * @note This should be used when a single allocated command buffer is used for all submissions from a component
*/ */
std::shared_ptr<FenceCycle> Reset() { std::shared_ptr<FenceCycle> Reset() {
slot.cycle->Wait(); slot->cycle->Wait();
slot.cycle = std::make_shared<FenceCycle>(slot.device, *slot.fence); slot->cycle = std::make_shared<FenceCycle>(slot->device, *slot->fence);
slot.commandBuffer.reset(); slot->commandBuffer.reset();
return slot.cycle; return slot->cycle;
} }
}; };