1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-11-27 14:22:17 +00:00
Atmosphere/troposphere/daybreak/nanovg/source/framework/CMemPool.cpp

176 lines
4.5 KiB
C++
Raw Normal View History

/*
** Sample Framework for deko3d Applications
** CMemPool.cpp: Pooled dynamic memory allocation manager class
*/
#include "CMemPool.h"
inline auto CMemPool::_newSlice() -> Slice*
{
Slice* ret = m_sliceHeap.pop();
if (!ret) ret = (Slice*)::malloc(sizeof(Slice));
return ret;
}
inline void CMemPool::_deleteSlice(Slice* s)
{
if (!s) return;
m_sliceHeap.add(s);
}
CMemPool::~CMemPool()
{
m_memMap.iterate([](Slice* s) { ::free(s); });
m_sliceHeap.iterate([](Slice* s) { ::free(s); });
m_blocks.iterate([](Block* blk) {
blk->m_obj.destroy();
::free(blk);
});
}
auto CMemPool::allocate(uint32_t size, uint32_t alignment) -> Handle
{
if (!size) return nullptr;
if (alignment & (alignment - 1)) return nullptr;
size = (size + alignment - 1) &~ (alignment - 1);
#ifdef DEBUG_CMEMPOOL
printf("Allocating size=%u alignment=0x%x\n", size, alignment);
{
Slice* temp = /*m_freeList*/m_memMap.first();
while (temp)
{
printf("-- blk %p | 0x%08x-0x%08x | %s used\n", temp->m_block, temp->m_start, temp->m_end, temp->m_pool ? " " : "not");
temp = /*m_freeList*/m_memMap.next(temp);
}
}
#endif
uint32_t start_offset = 0;
uint32_t end_offset = 0;
Slice* slice = m_freeList.find(size, decltype(m_freeList)::LowerBound);
while (slice)
{
#ifdef DEBUG_CMEMPOOL
printf(" * Checking slice 0x%x - 0x%x\n", slice->m_start, slice->m_end);
#endif
start_offset = (slice->m_start + alignment - 1) &~ (alignment - 1);
end_offset = start_offset + size;
if (end_offset <= slice->m_end)
break;
slice = m_freeList.next(slice);
}
if (!slice)
{
Block* blk = (Block*)::malloc(sizeof(Block));
if (!blk)
return nullptr;
uint32_t unusableSize = (m_flags & DkMemBlockFlags_Code) ? DK_SHADER_CODE_UNUSABLE_SIZE : 0;
uint32_t blkSize = m_blockSize - unusableSize;
blkSize = size > blkSize ? size : blkSize;
blkSize = (blkSize + unusableSize + DK_MEMBLOCK_ALIGNMENT - 1) &~ (DK_MEMBLOCK_ALIGNMENT - 1);
#ifdef DEBUG_CMEMPOOL
printf(" ! Allocating block of size 0x%x\n", blkSize);
#endif
blk->m_obj = dk::MemBlockMaker{m_dev, blkSize}.setFlags(m_flags).create();
if (!blk->m_obj)
{
::free(blk);
return nullptr;
}
slice = _newSlice();
if (!slice)
{
blk->m_obj.destroy();
::free(blk);
return nullptr;
}
slice->m_pool = nullptr;
slice->m_block = blk;
slice->m_start = 0;
slice->m_end = blkSize - unusableSize;
m_memMap.add(slice);
blk->m_cpuAddr = blk->m_obj.getCpuAddr();
blk->m_gpuAddr = blk->m_obj.getGpuAddr();
m_blocks.add(blk);
start_offset = 0;
end_offset = size;
}
else
{
#ifdef DEBUG_CMEMPOOL
printf(" * found it\n");
#endif
m_freeList.remove(slice);
}
if (start_offset != slice->m_start)
{
Slice* t = _newSlice();
if (!t) goto _bad;
t->m_pool = nullptr;
t->m_block = slice->m_block;
t->m_start = slice->m_start;
t->m_end = start_offset;
#ifdef DEBUG_CMEMPOOL
printf("-> subdivide left: %08x-%08x\n", t->m_start, t->m_end);
#endif
m_memMap.addBefore(slice, t);
m_freeList.insert(t, true);
slice->m_start = start_offset;
}
if (end_offset != slice->m_end)
{
Slice* t = _newSlice();
if (!t) goto _bad;
t->m_pool = nullptr;
t->m_block = slice->m_block;
t->m_start = end_offset;
t->m_end = slice->m_end;
#ifdef DEBUG_CMEMPOOL
printf("-> subdivide right: %08x-%08x\n", t->m_start, t->m_end);
#endif
m_memMap.addAfter(slice, t);
m_freeList.insert(t, true);
slice->m_end = end_offset;
}
slice->m_pool = this;
return slice;
_bad:
m_freeList.insert(slice, true);
return nullptr;
}
void CMemPool::_destroy(Slice* slice)
{
slice->m_pool = nullptr;
Slice* left = m_memMap.prev(slice);
Slice* right = m_memMap.next(slice);
if (left && left->canCoalesce(*slice))
{
slice->m_start = left->m_start;
m_freeList.remove(left);
m_memMap.remove(left);
_deleteSlice(left);
}
if (right && slice->canCoalesce(*right))
{
slice->m_end = right->m_end;
m_freeList.remove(right);
m_memMap.remove(right);
_deleteSlice(right);
}
m_freeList.insert(slice, true);
}