commit
6431810185
@ -17,7 +17,7 @@ include $(DEVKITARM)/base_rules
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET := ctru
|
TARGET := ctru
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source source/services source/gpu
|
SOURCES := source source/services source/gpu source/allocator
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := include
|
INCLUDES := include
|
||||||
|
|
||||||
|
50
libctru/source/allocator/linear.cpp
Normal file
50
libctru/source/allocator/linear.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include <3ds.h>
|
||||||
|
#include "mem_pool.h"
|
||||||
|
|
||||||
|
extern u32 __linear_heap, __linear_heap_size;
|
||||||
|
|
||||||
|
static MemPool sLinearPool;
|
||||||
|
|
||||||
|
static bool linearInit()
|
||||||
|
{
|
||||||
|
auto blk = MemBlock::Create((u8*)__linear_heap, __linear_heap_size);
|
||||||
|
if (blk)
|
||||||
|
{
|
||||||
|
sLinearPool.AddBlock(blk);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* linearAlloc(size_t size)
|
||||||
|
{
|
||||||
|
// Initialize the pool if it is not ready
|
||||||
|
if (!sLinearPool.Ready() && !linearInit())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Reserve memory for MemChunk structure
|
||||||
|
size += 16;
|
||||||
|
|
||||||
|
// Allocate the chunk
|
||||||
|
MemChunk chunk;
|
||||||
|
if (!sLinearPool.Allocate(chunk, size, 4)) // 16-byte alignment
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Copy the MemChunk structure and return memory
|
||||||
|
auto addr = chunk.addr;
|
||||||
|
*(MemChunk*)addr = chunk;
|
||||||
|
return addr + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* linearRealloc(void* mem, size_t size)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void linearFree(void* mem)
|
||||||
|
{
|
||||||
|
// Find MemChunk structure and free the chunk
|
||||||
|
auto pChunk = (MemChunk*)((u8*)mem - 16);
|
||||||
|
sLinearPool.Deallocate(*pChunk);
|
||||||
|
}
|
125
libctru/source/allocator/mem_pool.cpp
Normal file
125
libctru/source/allocator/mem_pool.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#include "mem_pool.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
// This method is currently unused
|
||||||
|
void MemPool::CoalesceLeft(MemBlock* b)
|
||||||
|
{
|
||||||
|
auto curPtr = b->base;
|
||||||
|
for (auto p = b->prev; p; p = p->prev)
|
||||||
|
{
|
||||||
|
if ((p->base + p->size) != curPtr) break;
|
||||||
|
curPtr = p->base;
|
||||||
|
p->size += b->size;
|
||||||
|
DelBlock(b);
|
||||||
|
b = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void MemPool::CoalesceRight(MemBlock* b)
|
||||||
|
{
|
||||||
|
auto curPtr = b->base + b->size;
|
||||||
|
auto next = b->next;
|
||||||
|
for (auto n = next; n; n = next)
|
||||||
|
{
|
||||||
|
next = n->next;
|
||||||
|
if (n->base != curPtr) break;
|
||||||
|
b->size += n->size;
|
||||||
|
curPtr += n->size;
|
||||||
|
DelBlock(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemPool::Allocate(MemChunk& chunk, u32 size, int align)
|
||||||
|
{
|
||||||
|
int alignM = (1 << align) - 1;
|
||||||
|
size = (size + alignM) &~ alignM; // Round the size
|
||||||
|
// Find the first suitable block
|
||||||
|
for (auto b = first; b; b = b->next)
|
||||||
|
{
|
||||||
|
auto addr = b->base;
|
||||||
|
u32 begWaste = (u32)addr & alignM;
|
||||||
|
addr += begWaste;
|
||||||
|
u32 bSize = b->size - begWaste;
|
||||||
|
if (bSize < size) continue;
|
||||||
|
|
||||||
|
// Found space!
|
||||||
|
chunk.addr = addr;
|
||||||
|
chunk.size = size;
|
||||||
|
|
||||||
|
// Resize the block
|
||||||
|
if (!begWaste)
|
||||||
|
{
|
||||||
|
b->base += size;
|
||||||
|
b->size -= size;
|
||||||
|
if (!b->size)
|
||||||
|
DelBlock(b);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
auto nAddr = addr + size;
|
||||||
|
auto nSize = bSize - size;
|
||||||
|
b->size = begWaste;
|
||||||
|
if (nSize)
|
||||||
|
{
|
||||||
|
// We need to add the tail chunk that wasn't used to the list
|
||||||
|
auto n = MemBlock::Create(nAddr, nSize);
|
||||||
|
if (n) InsertAfter(b, n);
|
||||||
|
else chunk.size += nSize; // we have no choice but to waste the space.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemPool::Deallocate(const MemChunk& chunk)
|
||||||
|
{
|
||||||
|
u8* cAddr = chunk.addr;
|
||||||
|
auto cSize = chunk.size;
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
// Try to merge the chunk somewhere into the list
|
||||||
|
for (auto b = first; !done && b; b = b->next)
|
||||||
|
{
|
||||||
|
auto addr = b->base;
|
||||||
|
if (addr > cAddr)
|
||||||
|
{
|
||||||
|
if ((cAddr + cSize) == addr)
|
||||||
|
{
|
||||||
|
// Merge the chunk to the left of the block
|
||||||
|
b->base = cAddr;
|
||||||
|
b->size += cSize;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// We need to insert a new block
|
||||||
|
auto c = MemBlock::Create(cAddr, cSize);
|
||||||
|
if (c) InsertBefore(b, c);
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
} else if ((b->base + b->size) == cAddr)
|
||||||
|
{
|
||||||
|
// Coalesce to the right
|
||||||
|
b->size += cSize;
|
||||||
|
CoalesceRight(b);
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!done)
|
||||||
|
{
|
||||||
|
// Either the list is empty or the chunk address is past the end
|
||||||
|
// address of the last block -- let's add a new block at the end
|
||||||
|
auto b = MemBlock::Create(cAddr, cSize);
|
||||||
|
if (b) AddBlock(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void MemPool::Dump(const char* title)
|
||||||
|
{
|
||||||
|
printf("<%s> VRAM Pool Dump\n", title);
|
||||||
|
for (auto b = first; b; b = b->next)
|
||||||
|
printf(" - %p (%u bytes)\n", b->base, b->size);
|
||||||
|
}
|
||||||
|
*/
|
88
libctru/source/allocator/mem_pool.h
Normal file
88
libctru/source/allocator/mem_pool.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
struct MemChunk
|
||||||
|
{
|
||||||
|
u8* addr;
|
||||||
|
u32 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MemBlock
|
||||||
|
{
|
||||||
|
MemBlock *prev, *next;
|
||||||
|
u8* base;
|
||||||
|
u32 size;
|
||||||
|
|
||||||
|
static MemBlock* Create(u8* base, u32 size)
|
||||||
|
{
|
||||||
|
auto b = (MemBlock*)malloc(sizeof(MemBlock));
|
||||||
|
if (!b) return nullptr;
|
||||||
|
b->prev = nullptr;
|
||||||
|
b->next = nullptr;
|
||||||
|
b->base = base;
|
||||||
|
b->size = size;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MemPool
|
||||||
|
{
|
||||||
|
MemBlock *first, *last;
|
||||||
|
|
||||||
|
bool Ready() { return first != nullptr; }
|
||||||
|
|
||||||
|
void AddBlock(MemBlock* blk)
|
||||||
|
{
|
||||||
|
blk->prev = last;
|
||||||
|
if (last) last->next = blk;
|
||||||
|
if (!first) first = blk;
|
||||||
|
last = blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelBlock(MemBlock* b)
|
||||||
|
{
|
||||||
|
auto prev = b->prev, &pNext = prev ? prev->next : first;
|
||||||
|
auto next = b->next, &nPrev = next ? next->prev : last;
|
||||||
|
pNext = next;
|
||||||
|
nPrev = prev;
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertBefore(MemBlock* b, MemBlock* p)
|
||||||
|
{
|
||||||
|
auto prev = b->prev, &pNext = prev ? prev->next : first;
|
||||||
|
b->prev = p;
|
||||||
|
p->next = b;
|
||||||
|
p->prev = prev;
|
||||||
|
pNext = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertAfter(MemBlock* b, MemBlock* n)
|
||||||
|
{
|
||||||
|
auto next = b->next, &nPrev = next ? next->prev : last;
|
||||||
|
b->next = n;
|
||||||
|
n->prev = b;
|
||||||
|
n->next = next;
|
||||||
|
nPrev = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//void CoalesceLeft(MemBlock* b);
|
||||||
|
void CoalesceRight(MemBlock* b);
|
||||||
|
|
||||||
|
bool Allocate(MemChunk& chunk, u32 size, int align);
|
||||||
|
void Deallocate(const MemChunk& chunk);
|
||||||
|
|
||||||
|
void Destroy()
|
||||||
|
{
|
||||||
|
MemBlock* next = nullptr;
|
||||||
|
for (auto b = first; b; b = next)
|
||||||
|
{
|
||||||
|
next = b->next;
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
first = nullptr;
|
||||||
|
last = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//void Dump(const char* title);
|
||||||
|
};
|
@ -1,32 +0,0 @@
|
|||||||
#include <3ds.h>
|
|
||||||
|
|
||||||
extern u32 __linear_heap, __linear_heap_size;
|
|
||||||
|
|
||||||
// TODO: this allocator sucks! It is not thread-safe and you cannot 'free' this memory.
|
|
||||||
void* linearAlloc(size_t size)
|
|
||||||
{
|
|
||||||
static size_t currentOffset = 0;
|
|
||||||
size_t free = __linear_heap_size - currentOffset;
|
|
||||||
|
|
||||||
// Enforce 8-byte alignment
|
|
||||||
size = (size + 7) &~ 7;
|
|
||||||
|
|
||||||
void* mem = NULL;
|
|
||||||
if (free >= size)
|
|
||||||
{
|
|
||||||
mem = (void*)(__linear_heap + currentOffset);
|
|
||||||
currentOffset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mem;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* linearRealloc(void* mem, size_t size)
|
|
||||||
{
|
|
||||||
return NULL; // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void linearFree(void* mem)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user