mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 21:11:53 +01:00
Split out megabuffer allocation from pushing data
The `Allocate` method allocates the given amount of space in a megabuffer chunk, returning a descriptor of the allocated region. This is useful for situations where you want to write directly to the megabuffer, avoiding the need for an intermediary buffer.
This commit is contained in:
parent
cdc6a4628a
commit
e6741642ba
@ -23,15 +23,15 @@ namespace skyline::gpu {
|
||||
return backing.vkBuffer;
|
||||
}
|
||||
|
||||
vk::DeviceSize MegaBufferChunk::Push(const std::shared_ptr<FenceCycle> &newCycle, span<u8> data, bool pageAlign) {
|
||||
std::pair<vk::DeviceSize, span<u8>> MegaBufferChunk::Allocate(const std::shared_ptr<FenceCycle> &newCycle, vk::DeviceSize size, bool pageAlign) {
|
||||
if (pageAlign) {
|
||||
// If page aligned data was requested then align the free
|
||||
auto alignedFreeBase{util::AlignUp(static_cast<size_t>(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<vk::DeviceSize>(resultSpan.data() - backing.data());
|
||||
freeRegion = freeRegion.subspan(size);
|
||||
|
||||
return {static_cast<vk::DeviceSize>(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<FenceCycle> &cycle, span<u8> 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<FenceCycle> &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<FenceCycle> &cycle, span<u8> data, bool pageAlign) {
|
||||
auto allocation{Allocate(cycle, data.size(), pageAlign)};
|
||||
allocation.region.copy_from(data);
|
||||
return allocation;
|
||||
}
|
||||
}
|
||||
|
@ -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<FenceCycle> &newCycle, span<u8> data, bool pageAlign = false);
|
||||
std::pair<vk::DeviceSize, span<u8>> Allocate(const std::shared_ptr<FenceCycle> &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<u8> 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<FenceCycle> &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
|
||||
|
Loading…
Reference in New Issue
Block a user