| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- // Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <anki/gr/common/GpuBlockAllocator.h>
- namespace anki
- {
- //==============================================================================
- // GpuBlockAllocator::Block =
- //==============================================================================
- class GpuBlockAllocator::Block
- : public IntrusiveListEnabled<GpuBlockAllocator::Block>
- {
- public:
- PtrSize m_offset = 0;
- U32 m_allocationCount = 0;
- };
- //==============================================================================
- // GpuBlockAllocator =
- //==============================================================================
- //==============================================================================
- GpuBlockAllocator::~GpuBlockAllocator()
- {
- if(m_freeBlockCount != m_blocks.getSize())
- {
- ANKI_LOGW("Forgot to free memory");
- }
- m_blocks.destroy(m_alloc);
- m_freeBlocksStack.destroy(m_alloc);
- }
- //==============================================================================
- void GpuBlockAllocator::init(
- GenericMemoryPoolAllocator<U8> alloc, PtrSize totalSize, PtrSize blockSize)
- {
- ANKI_ASSERT(!isCreated());
- ANKI_ASSERT(totalSize > 0 && blockSize > 0);
- ANKI_ASSERT(totalSize > blockSize);
- ANKI_ASSERT((totalSize % blockSize) == 0);
- m_alloc = alloc;
- m_size = totalSize;
- m_blockSize = blockSize;
- m_blocks.create(alloc, totalSize / blockSize);
- m_freeBlocksStack.create(alloc, m_blocks.getSize());
- m_freeBlockCount = m_blocks.getSize();
- m_currentBlock = MAX_U32;
- U count = m_freeBlocksStack.getSize();
- for(U32& i : m_freeBlocksStack)
- {
- i = --count;
- }
- }
- //==============================================================================
- Bool GpuBlockAllocator::blockHasEnoughSpace(
- U blockIdx, PtrSize size, U alignment) const
- {
- ANKI_ASSERT(size > 0);
- const Block& block = m_blocks[blockIdx];
- PtrSize allocEnd = getAlignedRoundUp(alignment, block.m_offset) + size;
- PtrSize blockEnd = (blockIdx + 1) * m_blockSize;
- return allocEnd <= blockEnd;
- }
- //==============================================================================
- Error GpuBlockAllocator::allocate(
- PtrSize size, U alignment, DynamicBufferToken& handle, Bool handleOomError)
- {
- ANKI_ASSERT(isCreated());
- ANKI_ASSERT(size < m_blockSize);
- Block* block = nullptr;
- Error err = ErrorCode::NONE;
- LockGuard<Mutex> lock(m_mtx);
- if(m_currentBlock == MAX_U32
- || !blockHasEnoughSpace(m_currentBlock, size, alignment))
- {
- // Need new block
- if(m_freeBlockCount > 0)
- {
- // Pop block from free
- U blockIdx = --m_freeBlockCount;
- block = &m_blocks[blockIdx];
- block->m_offset = blockIdx * m_blockSize;
- ANKI_ASSERT(block->m_allocationCount == 0);
- // Make it in-use
- m_currentBlock = blockIdx;
- }
- }
- if(block)
- {
- PtrSize outOffset = getAlignedRoundUp(alignment, block->m_offset);
- block->m_offset = outOffset + size;
- ANKI_ASSERT(
- block->m_offset <= (block - &m_blocks[0] + 1) * m_blockSize);
- ++block->m_allocationCount;
- // Update the handle
- handle.m_offset = outOffset;
- handle.m_range = size;
- }
- else if(handleOomError)
- {
- ANKI_LOGF("Out of memory");
- }
- else
- {
- err = ErrorCode::OUT_OF_MEMORY;
- }
- return err;
- }
- //==============================================================================
- void GpuBlockAllocator::free(const DynamicBufferToken& handle)
- {
- ANKI_ASSERT(isCreated());
- ANKI_ASSERT(handle.m_range > 0);
- ANKI_ASSERT(handle.m_offset < m_size);
- U blockIdx = handle.m_offset / m_blockSize;
- LockGuard<Mutex> lock(m_mtx);
- ANKI_ASSERT(m_blocks[blockIdx].m_allocationCount > 0);
- if((--m_blocks[blockIdx].m_allocationCount) == 0)
- {
- // Block no longer in use
- if(m_currentBlock == blockIdx)
- {
- m_currentBlock = MAX_U32;
- }
- m_freeBlocksStack[m_freeBlockCount++] = blockIdx;
- }
- }
- } // end namespace anki
|