base memory allocator and chunked arenas for orca

This commit is contained in:
Martin Fouilleul 2023-04-17 18:12:21 +02:00
parent f36e144bc0
commit e9e9ab68c2
16 changed files with 312 additions and 142 deletions

View File

@ -14,7 +14,7 @@
#include"graphics_internal.h" #include"graphics_internal.h"
#include"gl_loader.h" #include"gl_loader.h"
#if OS_MACOS #if PLATFORM_MACOS
//NOTE: EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE on osx defaults to CGL backend, which doesn't handle SwapInterval correctly //NOTE: EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE on osx defaults to CGL backend, which doesn't handle SwapInterval correctly
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE #define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE

View File

@ -85,11 +85,14 @@ typedef struct mg_handle_slot
} mg_handle_slot; } mg_handle_slot;
static const u32 MG_HANDLES_MAX_COUNT = 512;
typedef struct mg_data typedef struct mg_data
{ {
bool init; bool init;
mem_arena handleArena; mg_handle_slot handleArray[MG_HANDLES_MAX_COUNT];
int handleNextIndex;
list_info handleFreeList; list_info handleFreeList;
mem_arena resourceArena; mem_arena resourceArena;
@ -146,7 +149,7 @@ void mg_init()
{ {
if(!__mgData.init) if(!__mgData.init)
{ {
mem_arena_init(&__mgData.handleArena); __mgData.handleNextIndex = 0;
mem_arena_init(&__mgData.resourceArena); mem_arena_init(&__mgData.resourceArena);
__mgData.init = true; __mgData.init = true;
} }
@ -162,21 +165,24 @@ u64 mg_handle_alloc(mg_handle_kind kind, void* data)
{ {
mg_init(); mg_init();
} }
mem_arena* arena = &__mgData.handleArena;
mg_handle_slot* slot = list_pop_entry(&__mgData.handleFreeList, mg_handle_slot, freeListElt); mg_handle_slot* slot = list_pop_entry(&__mgData.handleFreeList, mg_handle_slot, freeListElt);
if(!slot) if(!slot && __mgData.handleNextIndex < MG_HANDLES_MAX_COUNT)
{ {
slot = mem_arena_alloc_type(arena, mg_handle_slot); slot = &__mgData.handleArray[__mgData.handleNextIndex];
DEBUG_ASSERT(slot); __mgData.handleNextIndex++;
slot->generation = 1; slot->generation = 1;
} }
slot->kind = kind; u64 h = 0;
slot->data = data; if(slot)
{
u64 h = ((u64)(slot - (mg_handle_slot*)arena->ptr))<<32 slot->kind = kind;
|((u64)(slot->generation)); slot->data = data;
h = ((u64)(slot - __mgData.handleArray))<<32
|((u64)(slot->generation));
}
return(h); return(h);
} }
@ -186,11 +192,10 @@ void mg_handle_recycle(u64 h)
u32 index = h>>32; u32 index = h>>32;
u32 generation = h & 0xffffffff; u32 generation = h & 0xffffffff;
mem_arena* arena = &__mgData.handleArena;
if(index*sizeof(mg_handle_slot) < arena->offset) if(index*sizeof(mg_handle_slot) < __mgData.handleNextIndex)
{ {
mg_handle_slot* slot = (mg_handle_slot*)arena->ptr + index; mg_handle_slot* slot = &__mgData.handleArray[index];
if(slot->generation == generation) if(slot->generation == generation)
{ {
DEBUG_ASSERT(slot->generation != UINT32_MAX, "surface slot generation wrap around\n"); DEBUG_ASSERT(slot->generation != UINT32_MAX, "surface slot generation wrap around\n");
@ -208,11 +213,10 @@ void* mg_data_from_handle(mg_handle_kind kind, u64 h)
u32 index = h>>32; u32 index = h>>32;
u32 generation = h & 0xffffffff; u32 generation = h & 0xffffffff;
mem_arena* arena = &__mgData.handleArena;
if(index*sizeof(mg_handle_slot) < arena->offset) if(index < __mgData.handleNextIndex)
{ {
mg_handle_slot* slot = (mg_handle_slot*)arena->ptr + index; mg_handle_slot* slot = &__mgData.handleArray[index];
if( slot->generation == generation if( slot->generation == generation
&& slot->kind == kind) && slot->kind == kind)
{ {
@ -278,10 +282,10 @@ mg_image_data* mg_image_data_from_handle(mg_image handle)
//--------------------------------------------------------------- //---------------------------------------------------------------
#if MG_COMPILE_BACKEND_GL #if MG_COMPILE_BACKEND_GL
#if defined(OS_WIN64) #if defined(PLATFORM_WIN64)
#include"wgl_surface.h" #include"wgl_surface.h"
#define gl_surface_create_for_window mg_wgl_surface_create_for_window #define gl_surface_create_for_window mg_wgl_surface_create_for_window
#elif defined(OS_MACOS) #elif defined(PLATFORM_MACOS)
/* /*
#include"nsgl_surface.h" #include"nsgl_surface.h"
#define gl_surface_create_for_window nsgl_surface_create_for_window #define gl_surface_create_for_window nsgl_surface_create_for_window
@ -328,7 +332,7 @@ bool mg_is_canvas_backend_available(mg_backend_id backend)
#if MG_COMPILE_BACKEND_METAL #if MG_COMPILE_BACKEND_METAL
case MG_BACKEND_METAL: case MG_BACKEND_METAL:
#endif #endif
#if MG_COMPILE_BACKEND_GL && defined(OS_WIN64) #if MG_COMPILE_BACKEND_GL && defined(PLATFORM_WIN64)
case MG_BACKEND_GL: case MG_BACKEND_GL:
#endif #endif
result = true; result = true;
@ -417,9 +421,9 @@ mg_surface mg_surface_create_host(mp_window window)
} }
mg_surface handle = mg_surface_nil(); mg_surface handle = mg_surface_nil();
mg_surface_data* surface = 0; mg_surface_data* surface = 0;
#if OS_MACOS #if PLATFORM_MACOS
surface = mg_osx_surface_create_host(window); surface = mg_osx_surface_create_host(window);
#elif OS_WIN64 #elif PLATFORM_WIN64
surface = mg_win32_surface_create_host(window); surface = mg_win32_surface_create_host(window);
#endif #endif

View File

@ -26,7 +26,7 @@ typedef enum {
//NOTE: these macros are used to select which backend to include when building milepost //NOTE: these macros are used to select which backend to include when building milepost
// they can be overridden by passing them to the compiler command line // they can be overridden by passing them to the compiler command line
#if defined(OS_MACOS) #if defined(PLATFORM_MACOS)
#ifndef MG_COMPILE_BACKEND_METAL #ifndef MG_COMPILE_BACKEND_METAL
#define MG_COMPILE_BACKEND_METAL 1 #define MG_COMPILE_BACKEND_METAL 1
#endif #endif
@ -45,7 +45,7 @@ typedef enum {
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE #define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif #endif
#elif defined(OS_WIN64) #elif defined(PLATFORM_WIN64)
#ifndef MG_COMPILE_BACKEND_GL #ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1 #define MG_COMPILE_BACKEND_GL 1
#endif #endif
@ -60,7 +60,7 @@ typedef enum {
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE #define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif #endif
#elif defined(OS_LINUX) #elif defined(PLATFORM_LINUX)
#ifndef MG_COMPILE_BACKEND_GL #ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1 #define MG_COMPILE_BACKEND_GL 1
#endif #endif

View File

@ -22,12 +22,12 @@
//--------------------------------------------------------------- //---------------------------------------------------------------
#include"platform.h" #include"platform.h"
#if defined(OS_WIN64) #if defined(PLATFORM_WIN64)
#include"platform/win32_base_allocator.c" #include"platform/win32_memory.c"
#include"platform/win32_clock.c" #include"platform/win32_clock.c"
//TODO //TODO
#elif defined(OS_MACOS) #elif defined(PLATFORM_MACOS)
#include"platform/unix_base_allocator.c" #include"platform/unix_memory.c"
#include"platform/osx_clock.c" #include"platform/osx_clock.c"
/* /*
#include"platform/unix_rng.c" #include"platform/unix_rng.c"
@ -35,8 +35,8 @@
#include"platform/posix_socket.c" #include"platform/posix_socket.c"
*/ */
#elif defined(OS_LINUX) #elif defined(PLATFORM_LINUX)
#include"platform/unix_base_allocator.c" #include"platform/unix_base_memory.c"
#include"platform/linux_clock.c" #include"platform/linux_clock.c"
/* /*
#include"platform/unix_rng.c" #include"platform/unix_rng.c"
@ -51,7 +51,7 @@
// app/graphics layer // app/graphics layer
//--------------------------------------------------------------- //---------------------------------------------------------------
#if defined(OS_WIN64) #if defined(PLATFORM_WIN64)
#include"win32_app.c" #include"win32_app.c"
#include"graphics.c" #include"graphics.c"
@ -68,7 +68,7 @@
#include"egl_surface.c" #include"egl_surface.c"
#endif #endif
#elif defined(OS_MACOS) #elif defined(PLATFORM_MACOS)
//NOTE: macos application layer and graphics backends are defined in milepost.m //NOTE: macos application layer and graphics backends are defined in milepost.m
#else #else
#error "Unsupported platform" #error "Unsupported platform"

View File

@ -14,9 +14,9 @@
#include"platform.h" #include"platform.h"
#include"ringbuffer.h" #include"ringbuffer.h"
#if defined(OS_WIN64) || defined(OS_WIN32) #if defined(PLATFORM_WIN64) || defined(PLATFORM_WIN32)
#include"win32_app.h" #include"win32_app.h"
#elif defined(OS_MACOS) #elif defined(PLATFORM_MACOS)
#include"osx_app.h" #include"osx_app.h"
#else #else
#error "platform not supported yet" #error "platform not supported yet"

View File

@ -0,0 +1,87 @@
/************************************************************//**
*
* @file: orca_memory.c
* @author: Martin Fouilleul
* @date: 17/04/2023
*
*****************************************************************/
#include"platform_memory.h"
extern void* orca_mem_grow(u64 size);
void* orca_mem_base_reserve(mem_base_allocator* context, u64 size)
{
return(orca_mem_grow(size));
}
void orca_mem_base_nop(mem_base_allocator* context, void* ptr, u64 size) {}
mem_base_allocator* mem_base_allocator_default()
{
static mem_base_allocator base = {0};
if(base.reserve == 0)
{
base.reserve = orca_mem_base_reserve;
base.commit = orca_mem_base_nop;
base.decommit = orca_mem_base_nop;
base.release = orca_mem_base_nop;
}
return(&base);
}
//TODO: implement malloc/realloc/free/memset/etc here...
void* memset(void* b, int c, size_t n)
{
for(size_t i = 0; i<n; i++)
{
((char*)b)[i] = (u8)c;
}
return(b);
}
void* memcpy(void *restrict dst, const void *restrict src, size_t n)
{
for(size_t i = 0; i<n; i++)
{
((char*)dst)[i] = ((char*)src)[i];
}
return(dst);
}
void* memmove(void *dst, const void *src, size_t n)
{
if(src < dst)
{
for(size_t i = n-1; i>=0; i--)
{
((char*)dst)[i] = ((char*)src)[i];
}
}
else if(src > dst)
{
for(size_t i = 0; i<n; i++)
{
((char*)dst)[i] = ((char*)src)[i];
}
}
return(dst);
}
int memcmp(const void *s1, const void *s2, size_t n)
{
const unsigned char* c1 = (const unsigned char*)s1;
const unsigned char* c2 = (const unsigned char*)s2;
for(size_t i = 0; i<n; i++)
{
if(c1[i] != c2[i])
{
return(c1 - c2);
}
}
return(0);
}

View File

@ -33,17 +33,17 @@
// OS identification // OS identification
//----------------------------------------------------------------- //-----------------------------------------------------------------
#if defined(_WIN64) #if defined(_WIN64)
#define OS_WIN64 1 #define PLATFORM_WIN64 1
#elif defined(_WIN32) #elif defined(_WIN32)
#error "Unsupported OS (32bit only version of Windows)" #error "Unsupported OS (32bit only version of Windows)"
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
#define OS_MACOS 1 #define PLATFORM_MACOS 1
#elif defined(__gnu_linux__) #elif defined(__gnu_linux__)
#define OS_LINUX 1 #define PLATFORM_LINUX 1
#elif defined(__ORCA__) #elif defined(__ORCA__)
#define OS_ORCA 1 #define PLATFORM_ORCA 1
#else #else
#error "Can't identify OS" #error "Can't identify platform"
#endif #endif
//----------------------------------------------------------------- //-----------------------------------------------------------------

View File

@ -1,28 +0,0 @@
/************************************************************//**
*
* @file: platform_base_allocator.h
* @author: Martin Fouilleul
* @date: 10/09/2021
* @revision:
*
*****************************************************************/
#ifndef __PLATFORM_BASE_ALLOCATOR_H_
#define __PLATFORM_BASE_ALLOCATOR_H_
#include"typedefs.h"
#include"memory.h"
#ifdef __cplusplus
extern "C" {
#endif
void* mem_base_reserve_mmap(void* context, u64 size);
void mem_base_release_mmap(void* context, void* ptr, u64 size);
mem_base_allocator* mem_base_allocator_default();
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__PLATFORM_BASE_ALLOCATOR_H_

View File

@ -0,0 +1,74 @@
/************************************************************//**
*
* @file: platform_memory.h
* @author: Martin Fouilleul
* @date: 10/09/2021
* @revision:
*
*****************************************************************/
#ifndef __PLATFORM_MEMORY_H_
#define __PLATFORM_MEMORY_H_
#include"typedefs.h"
#include"platform.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------------------
//NOTE(martin): base allocator
//--------------------------------------------------------------------------------
typedef struct mem_base_allocator mem_base_allocator;
typedef void*(*mem_reserve_function)(mem_base_allocator* context, u64 size);
typedef void(*mem_modify_function)(mem_base_allocator* context, void* ptr, u64 size);
typedef struct mem_base_allocator
{
mem_reserve_function reserve;
mem_modify_function commit;
mem_modify_function decommit;
mem_modify_function release;
} mem_base_allocator;
MP_API mem_base_allocator* mem_base_allocator_default();
#define mem_base_reserve(base, size) base->reserve(base, size)
#define mem_base_commit(base, ptr, size) base->commit(base, ptr, size)
#define mem_base_decommit(base, ptr, size) base->decommit(base, ptr, size)
#define mem_base_release(base, ptr, size) base->release(base, ptr, size)
//--------------------------------------------------------------------------------
//NOTE(martin): malloc/free
//--------------------------------------------------------------------------------
#if PLATFORM_ORCA
void* malloc(size_t size);
void* realloc(void* ptr, size_t size);
void free(void* ptr);
#else
#include<stdlib.h>
#endif
#define malloc_type(type) ((type*)malloc(sizeof(type)))
#define malloc_array(type, count) ((type*)malloc(sizeof(type)*count))
//--------------------------------------------------------------------------------
//NOTE(martin): memset / memcpy
//--------------------------------------------------------------------------------
#if PLATFORM_ORCA
void* memset(void *b, int c, size_t len);
void* memcpy(void *restrict dst, const void *restrict src, size_t n);
void* memmove(void *dst, const void *src, size_t len);
int memcmp(const void *s1, const void *s2, size_t n);
#else
#include<string.h>
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__PLATFORM_MEMORY_H_

View File

@ -1,25 +1,25 @@
/************************************************************//** /************************************************************//**
* *
* @file: unix_base_allocator.c * @file: unix_memory.c
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 10/09/2021 * @date: 10/09/2021
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#include<sys/mman.h> #include<sys/mman.h>
#include"platform_base_allocator.h" #include"platform_memory.h"
/*NOTE(martin): /*NOTE(martin):
Linux and MacOS don't make a distinction between reserved and committed memory, contrary to Windows Linux and MacOS don't make a distinction between reserved and committed memory, contrary to Windows
*/ */
void mem_base_nop(void* context, void* ptr, u64 size) {} void mem_base_nop(mem_base_allocator* context, void* ptr, u64 size) {}
void* mem_base_reserve_mmap(void* context, u64 size) void* mem_base_reserve_mmap(mem_base_allocator* context, u64 size)
{ {
return(mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0)); return(mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0));
} }
void mem_base_release_mmap(void* context, void* ptr, u64 size) void mem_base_release_mmap(mem_base_allocator* context, void* ptr, u64 size)
{ {
munmap(ptr, size); munmap(ptr, size);
} }

View File

@ -1,6 +1,6 @@
/************************************************************//** /************************************************************//**
* *
* @file: win32_base_allocator.c * @file: win32_memory.c
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 17/12/2022 * @date: 17/12/2022
* @revision: * @revision:
@ -8,27 +8,25 @@
*****************************************************************/ *****************************************************************/
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include<windows.h> #include<windows.h>
#include"platform_base_allocator.h" #include"platform_memory.h"
void mem_base_nop(void* context, void* ptr, u64 size) {} void* mem_base_reserve_win32(mem_base_allocator* context, u64 size)
void* mem_base_reserve_win32(void* context, u64 size)
{ {
void* result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); void* result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
return(result); return(result);
} }
void mem_base_commit_win32(void* context, void* ptr, u64 size) void mem_base_commit_win32(mem_base_allocator* context, void* ptr, u64 size)
{ {
VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE); VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE);
} }
void mem_base_release_win32(void* context, void* ptr, u64 size) void mem_base_release_win32(mem_base_allocator* context, void* ptr, u64 size)
{ {
VirtualFree(ptr, size, MEM_RELEASE); VirtualFree(ptr, size, MEM_RELEASE);
} }
void mem_base_decommit_win32(void* context, void* ptr, u64 size) void mem_base_decommit_win32(mem_base_allocator* context, void* ptr, u64 size)
{ {
VirtualFree(ptr, size, MEM_DECOMMIT); VirtualFree(ptr, size, MEM_DECOMMIT);
} }

View File

@ -2340,9 +2340,9 @@ typedef struct ui_edit_command
} ui_edit_command; } ui_edit_command;
#if OS_WIN64 #if PLATFORM_WIN64
#define OS_COPY_PASTE_MOD MP_KEYMOD_CTRL #define OS_COPY_PASTE_MOD MP_KEYMOD_CTRL
#elif OS_MACOS #elif PLATFORM_MACOS
#define OS_COPY_PASTE_MOD MP_KEYMOD_CMD #define OS_COPY_PASTE_MOD MP_KEYMOD_CMD
#endif #endif

View File

@ -21,11 +21,6 @@
//TODO(martin): this is a compiler-specific attribute, recognized by clang and gcc. See if there's a more portable approach //TODO(martin): this is a compiler-specific attribute, recognized by clang and gcc. See if there's a more portable approach
//#define INLINE_GEN __attribute__((used)) static inline //#define INLINE_GEN __attribute__((used)) static inline
//NOTE(martin): typed and array mallocs
#define malloc_type(type) ((type*)malloc(sizeof(type)))
#define malloc_array(type, count) ((type*)malloc(sizeof(type)*count))
//NOTE(martin): 'hygienic' templates, to replace macros and avoid multiple evaluation problems. //NOTE(martin): 'hygienic' templates, to replace macros and avoid multiple evaluation problems.
#ifdef __cplusplus #ifdef __cplusplus
//NOTE(martin): in C++ we use templates and decltype/declval //NOTE(martin): in C++ we use templates and decltype/declval
@ -128,9 +123,11 @@ static inline u64 next_pow2_u64(u64 x)
//NOTE: assert macros //NOTE: assert macros
#ifndef NO_ASSERT #ifndef NO_ASSERT
#ifdef OS_ORCA #ifdef PLATFORM_ORCA
//TODO add a runtime-provided assert //TODO add a runtime-provided assert
#define _ASSERT_(x, msg) extern void orca_assert(bool x);
#define _ASSERT_(x, msg) orca_assert(x)
#else #else
#include<assert.h> #include<assert.h>
#define _ASSERT_(x, msg) assert(x && msg) #define _ASSERT_(x, msg) assert(x && msg)

View File

@ -6,19 +6,43 @@
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#include<string.h> // memset
#include"platform.h" #include"platform.h"
#include"memory.h" #include"memory.h"
#include"platform_base_allocator.h" #include"platform_memory.h"
#include"macro_helpers.h" #include"macro_helpers.h"
static const u32 MEM_ARENA_DEFAULT_RESERVE_SIZE = 1<<30; #if PLATFORM_ORCA
static const u32 MEM_ARENA_COMMIT_ALIGNMENT = 1<<20; static const u32 MEM_ARENA_DEFAULT_RESERVE_SIZE = 1<<20;
#else
static const u32 MEM_ARENA_DEFAULT_RESERVE_SIZE = 1<<30;
#endif
static const u32 MEM_ARENA_COMMIT_ALIGNMENT = 4<<10;
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
//NOTE(martin): memory arena //NOTE(martin): memory arena
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
mem_arena_chunk* mem_arena_chunk_alloc(mem_arena* arena, u64 reserveSize)
{
reserveSize = AlignUpOnPow2(reserveSize, MEM_ARENA_COMMIT_ALIGNMENT);
u64 commitSize = AlignUpOnPow2(sizeof(mem_arena_chunk), MEM_ARENA_COMMIT_ALIGNMENT);
char* mem = mem_base_reserve(arena->base, reserveSize);
mem_base_commit(arena->base, mem, commitSize);
mem_arena_chunk* chunk = (mem_arena_chunk*)mem;
chunk->ptr = mem;
chunk->cap = reserveSize;
chunk->offset = sizeof(mem_arena_chunk);
chunk->committed = commitSize;
list_push_back(&arena->chunks, &chunk->listElt);
return(chunk);
}
void mem_arena_init(mem_arena* arena) void mem_arena_init(mem_arena* arena)
{ {
mem_arena_init_with_options(arena, &(mem_arena_options){0}); mem_arena_init_with_options(arena, &(mem_arena_options){0});
@ -26,42 +50,69 @@ void mem_arena_init(mem_arena* arena)
void mem_arena_init_with_options(mem_arena* arena, mem_arena_options* options) void mem_arena_init_with_options(mem_arena* arena, mem_arena_options* options)
{ {
arena->base = options->base ? options->base : mem_base_allocator_default(); memset(arena, 0, sizeof(mem_arena));
arena->cap = options->reserve ? options->reserve : MEM_ARENA_DEFAULT_RESERVE_SIZE;
arena->ptr = mem_base_reserve(arena->base, arena->cap); arena->base = options->base ? options->base : mem_base_allocator_default();
arena->committed = 0;
arena->offset = 0; u64 reserveSize = options->reserve ? (options->reserve + sizeof(mem_arena_chunk)) : MEM_ARENA_DEFAULT_RESERVE_SIZE;
arena->currentChunk = mem_arena_chunk_alloc(arena, reserveSize);
} }
void mem_arena_release(mem_arena* arena) void mem_arena_release(mem_arena* arena)
{ {
mem_base_release(arena->base, arena->ptr, arena->cap); for_list_safe(&arena->chunks, chunk, mem_arena_chunk, listElt)
{
mem_base_release(arena->base, chunk, chunk->cap);
}
memset(arena, 0, sizeof(mem_arena)); memset(arena, 0, sizeof(mem_arena));
} }
void* mem_arena_alloc(mem_arena* arena, u64 size) void* mem_arena_alloc(mem_arena* arena, u64 size)
{ {
u64 nextOffset = arena->offset + size; mem_arena_chunk* chunk = arena->currentChunk;
ASSERT(nextOffset <= arena->cap); ASSERT(chunk);
if(nextOffset > arena->committed) u64 nextOffset = chunk->offset + size;
u64 lastCap = chunk->cap;
while(chunk && nextOffset > chunk->cap)
{
chunk = list_next_entry(&arena->chunks, chunk, mem_arena_chunk, listElt);
nextOffset = chunk->offset + size;
lastCap = chunk->cap;
}
if(!chunk)
{
u64 reserveSize = maximum(lastCap * 1.5, size);
chunk = mem_arena_chunk_alloc(arena, reserveSize);
nextOffset = chunk->offset + size;
}
ASSERT(nextOffset <= chunk->cap);
arena->currentChunk = chunk;
if(nextOffset > chunk->committed)
{ {
u64 nextCommitted = AlignUpOnPow2(nextOffset, MEM_ARENA_COMMIT_ALIGNMENT); u64 nextCommitted = AlignUpOnPow2(nextOffset, MEM_ARENA_COMMIT_ALIGNMENT);
nextCommitted = ClampHighBound(nextCommitted, arena->cap); nextCommitted = ClampHighBound(nextCommitted, chunk->cap);
u64 commitSize = nextCommitted - arena->committed; u64 commitSize = nextCommitted - chunk->committed;
mem_base_commit(arena->base, arena->ptr + arena->committed, commitSize); mem_base_commit(arena->base, chunk->ptr + chunk->committed, commitSize);
arena->committed = nextCommitted; chunk->committed = nextCommitted;
} }
char* p = arena->ptr + arena->offset; char* p = chunk->ptr + chunk->offset;
arena->offset += size; chunk->offset += size;
return(p); return(p);
} }
void mem_arena_clear(mem_arena* arena) void mem_arena_clear(mem_arena* arena)
{ {
arena->offset = 0; for_list(&arena->chunks, chunk, mem_arena_chunk, listElt)
{
chunk->offset = sizeof(mem_arena_chunk);
}
arena->currentChunk = list_first_entry(&arena->chunks, mem_arena_chunk, listElt);
} }
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
@ -98,7 +149,6 @@ void* mem_pool_alloc(mem_pool* pool)
void mem_pool_recycle(mem_pool* pool, void* ptr) void mem_pool_recycle(mem_pool* pool, void* ptr)
{ {
ASSERT((((char*)ptr) >= pool->arena.ptr) && (((char*)ptr) < (pool->arena.ptr + pool->arena.offset)));
list_push(&pool->freeList, (list_elt*)ptr); list_push(&pool->freeList, (list_elt*)ptr);
} }
@ -117,7 +167,7 @@ mp_thread_local mem_arena __scratchArena = {0};
mem_arena* mem_scratch() mem_arena* mem_scratch()
{ {
if(__scratchArena.ptr == 0) if(__scratchArena.base == 0)
{ {
mem_arena_init(&__scratchArena); mem_arena_init(&__scratchArena);
} }

View File

@ -9,46 +9,33 @@
#ifndef __MEMORY_H_ #ifndef __MEMORY_H_
#define __MEMORY_H_ #define __MEMORY_H_
#include"typedefs.h" #include"util/typedefs.h"
#include"lists.h" #include"util/lists.h"
#include"platform/platform_memory.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
//--------------------------------------------------------------------------------
//NOTE(martin): base allocator
//--------------------------------------------------------------------------------
typedef void*(*mem_reserve_function)(void* context, u64 size);
typedef void(*mem_modify_function)(void* context, void* ptr, u64 size);
typedef struct mem_base_allocator
{
mem_reserve_function reserve;
mem_modify_function commit;
mem_modify_function decommit;
mem_modify_function release;
void* context;
} mem_base_allocator;
MP_API mem_base_allocator* mem_base_allocator_default();
#define mem_base_reserve(base, size) base->reserve(base->context, size)
#define mem_base_commit(base, ptr, size) base->commit(base->context, ptr, size)
#define mem_base_decommit(base, ptr, size) base->decommit(base->context, ptr, size)
#define mem_base_release(base, ptr, size) base->release(base->context, ptr, size)
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
//NOTE(martin): memory arena //NOTE(martin): memory arena
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
typedef struct mem_arena
typedef struct mem_arena_chunk
{ {
mem_base_allocator* base; list_elt listElt;
char* ptr; char* ptr;
u64 offset; u64 offset;
u64 committed; u64 committed;
u64 cap; u64 cap;
} mem_arena_chunk;
typedef struct mem_arena
{
mem_base_allocator* base;
list_info chunks;
mem_arena_chunk* currentChunk;
} mem_arena; } mem_arena;
typedef struct mem_arena_options typedef struct mem_arena_options

View File

@ -10,7 +10,8 @@
#ifndef __TYPEDEFS_H_ #ifndef __TYPEDEFS_H_
#define __TYPEDEFS_H_ #define __TYPEDEFS_H_
#include<inttypes.h> #include<stddef.h>
#include<stdint.h>
#include<float.h> //FLT_MAX/MIN etc... #include<float.h> //FLT_MAX/MIN etc...
#ifndef __cplusplus #ifndef __cplusplus