diff --git a/app/src/main/cpp/skyline/gpu/megabuffer.cpp b/app/src/main/cpp/skyline/gpu/megabuffer.cpp index f7bb3646..1737a627 100644 --- a/app/src/main/cpp/skyline/gpu/megabuffer.cpp +++ b/app/src/main/cpp/skyline/gpu/megabuffer.cpp @@ -23,15 +23,15 @@ namespace skyline::gpu { return backing.vkBuffer; } - vk::DeviceSize MegaBufferChunk::Push(const std::shared_ptr &newCycle, span data, bool pageAlign) { + std::pair> MegaBufferChunk::Allocate(const std::shared_ptr &newCycle, vk::DeviceSize size, bool pageAlign) { if (pageAlign) { // If page aligned data was requested then align the free auto alignedFreeBase{util::AlignUp(static_cast(freeRegion.data() - backing.data()), PAGE_SIZE)}; freeRegion = backing.subspan(alignedFreeBase); } - if (data.size() > freeRegion.size()) - return 0; + if (size > freeRegion.size()) + return {0, {}}; if (cycle != newCycle) { newCycle->ChainCycle(cycle); @@ -39,12 +39,12 @@ namespace skyline::gpu { } // Allocate space for data from the free region - auto resultSpan{freeRegion.subspan(0, data.size())}; - resultSpan.copy_from(data); + auto resultSpan{freeRegion.subspan(0, size)}; // Move the free region along - freeRegion = freeRegion.subspan(data.size()); - return static_cast(resultSpan.data() - backing.data()); + freeRegion = freeRegion.subspan(size); + + return {static_cast(resultSpan.data() - backing.data()), resultSpan}; } MegaBufferAllocator::MegaBufferAllocator(GPU &gpu) : gpu{gpu}, activeChunk{chunks.emplace(chunks.end(), gpu)} {} @@ -61,17 +61,23 @@ namespace skyline::gpu { return mutex.try_lock(); } - MegaBufferAllocator::Allocation MegaBufferAllocator::Push(const std::shared_ptr &cycle, span data, bool pageAlign) { - if (vk::DeviceSize offset{activeChunk->Push(cycle, data, pageAlign)}; offset) - return {activeChunk->GetBacking(), offset}; + MegaBufferAllocator::Allocation MegaBufferAllocator::Allocate(const std::shared_ptr &cycle, vk::DeviceSize size, bool pageAlign) { + if (auto allocation{activeChunk->Allocate(cycle, size, pageAlign)}; allocation.first) + return {activeChunk->GetBacking(), allocation.first, allocation.second}; activeChunk = ranges::find_if(chunks, [&](auto &chunk) { return chunk.TryReset(); }); if (activeChunk == chunks.end()) // If there are no chunks available, allocate a new one activeChunk = chunks.emplace(chunks.end(), gpu); - if (vk::DeviceSize offset{activeChunk->Push(cycle, data, pageAlign)}; offset) - return {activeChunk->GetBacking(), offset}; + if (auto allocation{activeChunk->Allocate(cycle, size, pageAlign)}; allocation.first) + return {activeChunk->GetBacking(), allocation.first, allocation.second}; else - throw exception("Failed to to allocate megabuffer space for size: 0x{:X}", data.size()); + throw exception("Failed to to allocate megabuffer space for size: 0x{:X}", size); + } + + MegaBufferAllocator::Allocation MegaBufferAllocator::Push(const std::shared_ptr &cycle, span data, bool pageAlign) { + auto allocation{Allocate(cycle, data.size(), pageAlign)}; + allocation.region.copy_from(data); + return allocation; } } diff --git a/app/src/main/cpp/skyline/gpu/megabuffer.h b/app/src/main/cpp/skyline/gpu/megabuffer.h index bd1d88ef..6e17e291 100644 --- a/app/src/main/cpp/skyline/gpu/megabuffer.h +++ b/app/src/main/cpp/skyline/gpu/megabuffer.h @@ -30,11 +30,7 @@ namespace skyline::gpu { */ vk::Buffer GetBacking() const; - /** - * @brief Pushes data to the chunk and returns the offset at which it was written - * @param pageAlign Whether the pushed data should be page aligned in the chunk - */ - vk::DeviceSize Push(const std::shared_ptr &newCycle, span data, bool pageAlign = false); + std::pair> Allocate(const std::shared_ptr &newCycle, vk::DeviceSize size, bool pageAlign = false); }; /** @@ -55,6 +51,7 @@ namespace skyline::gpu { struct Allocation { vk::Buffer buffer; //!< The megabuffer chunk backing hat the allocation was made within vk::DeviceSize offset; //!< The offset of the allocation in the chunk + span region; //!< The CPU mapped region of the allocation in the chunk operator bool() const { return offset != 0; @@ -81,6 +78,13 @@ namespace skyline::gpu { */ 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 + * @note The allocator *MUST* be locked before calling this function + */ + Allocation Allocate(const std::shared_ptr &cycle, vk::DeviceSize size, bool pageAlign = false); + /** * @brief Pushes data to a megabuffer chunk and returns an structure describing the allocation * @param pageAlign Whether the pushed data should be page aligned in the megabuffer