diff --git a/src/Video/LowLevelRenderer/Interface/BufferAllocator.cpp b/src/Video/LowLevelRenderer/Interface/BufferAllocator.cpp index 75b78029..e82ab119 100644 --- a/src/Video/LowLevelRenderer/Interface/BufferAllocator.cpp +++ b/src/Video/LowLevelRenderer/Interface/BufferAllocator.cpp @@ -11,12 +11,14 @@ BufferAllocator::BufferAllocator(uint32_t frames) { usedBufferObjects = new std::vector[frames]; pools = new Pool[frames]; +#if HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_SUBALLOCATE for (uint32_t i = 0; i < frames; ++i) { for (uint32_t usage = 0; usage < static_cast(Buffer::BufferUsage::COUNT); ++usage) { - pools[frame].currentRawBuffer[usage] = 0; - pools[frame].currentOffset[usage] = 0; + pools[i].subPools[usage].currentRawBuffer = 0; + pools[i].subPools[usage].currentOffset = 0; } } +#endif } BufferAllocator::~BufferAllocator() { @@ -30,9 +32,17 @@ BufferAllocator::~BufferAllocator() { } for (uint32_t usage = 0; usage < static_cast(Buffer::BufferUsage::COUNT); ++usage) { - for (RawBuffer* rawBuffer : pools[i].rawBuffers[usage]) { +#if HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_SUBALLOCATE + for (RawBuffer* rawBuffer : pools[i].subPools[usage].rawBuffers) { delete rawBuffer; } +#elif HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_WHOLE + for (auto& it : pools[i].subPools[usage]) { + for (RawBuffer* rawBuffer : it.second.rawBuffers) { + delete rawBuffer; + } + } +#endif } } delete[] freeBufferObjects; @@ -49,8 +59,14 @@ void BufferAllocator::BeginFrame() { usedBufferObjects[frame].clear(); for (uint32_t usage = 0; usage < static_cast(Buffer::BufferUsage::COUNT); ++usage) { - pools[frame].currentRawBuffer[usage] = 0; - pools[frame].currentOffset[usage] = 0; +#if HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_SUBALLOCATE + pools[frame].subPools[usage].currentRawBuffer = 0; + pools[frame].subPools[usage].currentOffset = 0; +#elif HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_WHOLE + for (auto& it : pools[frame].subPools[usage]) { + it.second.currentRawBuffer = 0; + } +#endif } } @@ -92,26 +108,41 @@ BufferAllocation BufferAllocator::AllocateTemporary(Buffer::BufferUsage bufferUs /// @todo Handle large allocations. assert(size < poolSize); - // Use next buffer if we've run out of space in the current one. + // Get the sub pool. uint32_t bufferUsageInt = static_cast(bufferUsage); - if (pools[frame].currentOffset[bufferUsageInt] + size > poolSize) { - pools[frame].currentRawBuffer[bufferUsageInt]++; - pools[frame].currentOffset[bufferUsageInt] = 0; +#if HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_SUBALLOCATE + SubPool& subPool = pools[frame].subPools[bufferUsageInt]; +#elif HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_WHOLE + SubPool& subPool = pools[frame].subPools[bufferUsageInt][size]; +#endif + +#if HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_SUBALLOCATE + // Use next buffer if we've run out of space in the current one. + if (subPool.currentOffset + size > poolSize) { + subPool.currentRawBuffer++; + subPool.currentOffset = 0; } +#endif // Get a new allocation if we don't have any more buffers to suballocate from. - if (pools[frame].rawBuffers[bufferUsageInt].size() <= pools[frame].currentRawBuffer[bufferUsageInt]) { - pools[frame].rawBuffers[bufferUsageInt].push_back(Allocate(bufferUsage, true, poolSize)); + if (subPool.rawBuffers.size() <= subPool.currentRawBuffer) { + subPool.rawBuffers.push_back(Allocate(bufferUsage, true, poolSize)); } // Suballocate. BufferAllocation allocation; - allocation.buffer = pools[frame].rawBuffers[bufferUsageInt][pools[frame].currentRawBuffer[bufferUsageInt]]; - allocation.offset = pools[frame].currentOffset[bufferUsageInt]; + allocation.buffer = subPool.rawBuffers[subPool.currentRawBuffer]; allocation.size = size; allocation.temporaryAllocation = true; - pools[frame].currentOffset[bufferUsageInt] += size; +#if HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_SUBALLOCATE + allocation.offset = subPool.currentOffset; + subPool.currentOffset += size; +#elif HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_WHOLE + allocation.offset = 0; + + subPool.currentRawBuffer++; +#endif return allocation; } diff --git a/src/Video/LowLevelRenderer/Interface/BufferAllocator.hpp b/src/Video/LowLevelRenderer/Interface/BufferAllocator.hpp index fca6ddd7..b11bfce1 100644 --- a/src/Video/LowLevelRenderer/Interface/BufferAllocator.hpp +++ b/src/Video/LowLevelRenderer/Interface/BufferAllocator.hpp @@ -2,8 +2,19 @@ #include #include +#include #include "Buffer.hpp" +// There are two different strategies for temporary buffer allocation. +// HYMN_BUFFER_STRATEGY_WHOLE: +// Buffers are allocated of the requested size (eg. a 128B request results in a 128B buffer). +// HYMN_BUFFER_STRATEGY_SUBALLOCATE +// 1 MB large buffers are allocated and requests are satisfied by sub-allocating from these (eg. a 128B request results in an offset into a 1MB buffer). + +#define HYMN_BUFFER_STRATEGY_SUBALLOCATE 0 +#define HYMN_BUFFER_STRATEGY_WHOLE 1 +#define HYMN_BUFFER_STRATEGY HYMN_BUFFER_STRATEGY_SUBALLOCATE + namespace Video { /// A large buffer from which buffers are sub-allocated. @@ -92,11 +103,23 @@ class BufferAllocator { std::vector* freeBufferObjects; std::vector* usedBufferObjects; + struct SubPool { + std::vector rawBuffers; + uint32_t currentRawBuffer = 0; +#if HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_SUBALLOCATE + uint32_t currentOffset; +#endif + }; + +#if HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_SUBALLOCATE + struct Pool { + SubPool subPools[static_cast(Buffer::BufferUsage::COUNT)]; + }; +#elif HYMN_BUFFER_STRATEGY == HYMN_BUFFER_STRATEGY_WHOLE struct Pool { - std::vector rawBuffers[static_cast(Buffer::BufferUsage::COUNT)]; - uint32_t currentRawBuffer[static_cast(Buffer::BufferUsage::COUNT)]; - uint32_t currentOffset[static_cast(Buffer::BufferUsage::COUNT)]; + std::map subPools[static_cast(Buffer::BufferUsage::COUNT)]; }; +#endif Pool* pools; };