| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <AnKi/Gr/Utils/StackGpuAllocator.h>
- namespace anki
- {
- class StackGpuAllocatorChunk
- {
- public:
- StackGpuAllocatorChunk* m_next;
- StackGpuAllocatorMemory* m_mem;
- Atomic<PtrSize> m_offset;
- PtrSize m_size;
- };
- StackGpuAllocator::~StackGpuAllocator()
- {
- Chunk* chunk = m_chunkListHead;
- while(chunk)
- {
- if(chunk->m_mem)
- {
- m_iface->free(chunk->m_mem);
- }
- Chunk* next = chunk->m_next;
- m_alloc.deleteInstance(chunk);
- chunk = next;
- }
- }
- void StackGpuAllocator::init(GenericMemoryPoolAllocator<U8> alloc, StackGpuAllocatorInterface* iface)
- {
- ANKI_ASSERT(iface);
- m_alloc = alloc;
- m_iface = iface;
- iface->getChunkGrowInfo(m_scale, m_bias, m_initialSize);
- ANKI_ASSERT(m_scale >= 1.0);
- ANKI_ASSERT(m_initialSize > 0);
- m_alignment = iface->getMaxAlignment();
- ANKI_ASSERT(m_alignment > 0);
- alignRoundUp(m_alignment, m_initialSize);
- }
- Error StackGpuAllocator::allocate(PtrSize size, StackGpuAllocatorHandle& handle)
- {
- alignRoundUp(m_alignment, size);
- ANKI_ASSERT(size > 0);
- ANKI_ASSERT(size <= m_initialSize && "The chunks should have enough space to hold at least one allocation");
- Chunk* crntChunk;
- Bool retry = true;
- do
- {
- crntChunk = m_crntChunk.load();
- PtrSize offset;
- if(crntChunk && ((offset = crntChunk->m_offset.fetchAdd(size)) + size) <= crntChunk->m_size)
- {
- // All is fine, there is enough space in the chunk
- handle.m_memory = crntChunk->m_mem;
- handle.m_offset = offset;
- retry = false;
- }
- else
- {
- // Need new chunk
- LockGuard<Mutex> lock(m_lock);
- // Make sure that only one thread will create a new chunk
- if(m_crntChunk.load() == crntChunk)
- {
- // We can create a new chunk
- if(crntChunk == nullptr || crntChunk->m_next == nullptr)
- {
- // Need to create a new chunk
- Chunk* newChunk = m_alloc.newInstance<Chunk>();
- if(crntChunk)
- {
- crntChunk->m_next = newChunk;
- newChunk->m_size = PtrSize(F32(crntChunk->m_size) * m_scale + F32(m_bias));
- }
- else
- {
- newChunk->m_size = m_initialSize;
- if(m_chunkListHead == nullptr)
- {
- m_chunkListHead = newChunk;
- }
- }
- alignRoundUp(m_alignment, newChunk->m_size);
- newChunk->m_next = nullptr;
- newChunk->m_offset.setNonAtomically(0);
- ANKI_CHECK(m_iface->allocate(newChunk->m_size, newChunk->m_mem));
- m_crntChunk.store(newChunk);
- }
- else
- {
- // Need to recycle one
- crntChunk->m_next->m_offset.setNonAtomically(0);
- m_crntChunk.store(crntChunk->m_next);
- }
- }
- }
- } while(retry);
- return Error::NONE;
- }
- void StackGpuAllocator::reset()
- {
- m_crntChunk.setNonAtomically(m_chunkListHead);
- if(m_chunkListHead)
- {
- m_chunkListHead->m_offset.setNonAtomically(0);
- }
- }
- } // end namespace anki
|