Skip to content

Commit

Permalink
Merge pull request devkitPro#1 from smealum/refactor
Browse files Browse the repository at this point in the history
Refactor
  • Loading branch information
Arisotura committed Sep 18, 2014
2 parents bc6cb66 + eaa7948 commit 059fc25
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 33 deletions.
2 changes: 1 addition & 1 deletion libctru/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ include $(DEVKITARM)/base_rules
#---------------------------------------------------------------------------------
TARGET := ctru
BUILD := build
SOURCES := source source/services source/gpu
SOURCES := source source/services source/gpu source/allocator
DATA := data
INCLUDES := include

Expand Down
50 changes: 50 additions & 0 deletions libctru/source/allocator/linear.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 125 additions & 0 deletions libctru/source/allocator/mem_pool.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 88 additions & 0 deletions libctru/source/allocator/mem_pool.h
Original file line number Diff line number Diff line change
@@ -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);
};
32 changes: 0 additions & 32 deletions libctru/source/linear.c

This file was deleted.

0 comments on commit 059fc25

Please sign in to comment.