diff --git a/build.sh b/build.sh index 33c6948..38443e5 100755 --- a/build.sh +++ b/build.sh @@ -57,7 +57,7 @@ clang_out="-o" gcc_common="${include_flags} ${render_flag} -DCOMPILER_GCC -std=c99 -fuse-ld=mold -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -DVMA_STATIC_VULKAN_FUNCTIONS=0" gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common}" gcc_release="$compiler -O2 ${gcc_common} ${render_flag}" -gcc_test="$compiler -O2 -DBUILD_TEST=1 ${gcc_common} ${render_flag}" +gcc_test="$compiler -O0 -DBUILD_TEST=1 ${gcc_common} ${render_flag}" gcc_link="-lpthread -lm -lrt -ldl ${render_link} -lstdc++" gcc_out="-o" diff --git a/src/allocators.c b/src/allocators.c index e0c0b14..9973c9b 100644 --- a/src/allocators.c +++ b/src/allocators.c @@ -1,7 +1,7 @@ // ::Allocator::Globals:: Allocator g_alloc; -read_only FLNode FL_NIL_NODE = {}; +read_only FLNode FL_NIL_NODE = {0}; // ::Allocator::Util::Header:: @@ -95,6 +95,8 @@ static Arena * CreateArenaDebug(rawptr buffer, usize length, u32 init_line_no) // ::Allocator::Arena::End:: + + // ::Allocator::GlobalAlloc::Start:: static void InitAllocator(usize init_size, usize grow_size) @@ -152,34 +154,71 @@ static void AllocGrow() } -// ::Allocator::FreeList::End:: +// ::Allocator::GlobalAlloc::End:: -static void FLAllocInit(FLAlloc *alloc, usize size) + + +// ::Allocator::FreeList::Start:: + +static void FreeListInit(FLAlloc *alloc, usize size) { - alloc->data = MemAllocZeroed(size); - alloc->size = size; + alloc->lists = MemAllocZeroed(sizeof(FreeList *) * 16); + alloc->list_count = 1; + alloc->list_capacity = 16; + alloc->ticket = 0; + alloc->next_ticket = 0; alloc->nil = &FL_NIL_NODE; - FLAllocFreeAll(alloc); + alloc->grow_size = size; + + _FreeListInit(&alloc->lists[0], size); + + FreeListFreeAll(alloc); } -static void FLAllocFreeAll(FLAlloc *alloc) +static void _FreeListInit(FreeList **alloc, usize size) { - FLNode *node = (FLNode *)alloc->data; - node->size = alloc->size; - node->next = alloc->nil; - - alloc->used = 0; - alloc->head = node; + *alloc = (FreeList *)MemAllocZeroed(size); + (*alloc)->data = (rawptr)(((uintptr)*alloc) + ((uintptr)sizeof(FreeList))); + (*alloc)->size = size; + (*alloc)->used = sizeof(FreeList); } -static FLNode *FreeListSearch(FLAlloc *alloc, usize size, u32 alignment, u32 *out_padding, FLNode **prev_node) +static void FreeListFreeAll(FLAlloc *alloc) +{ + u32 ticket = __atomic_fetch_add(&alloc->ticket, 1, __ATOMIC_SEQ_CST); + while (ticket != alloc->next_ticket); + + if (alloc->list_count > 1) + { + for (u32 i = 1; i < alloc->list_count; i++) + { + MemFree(alloc->lists[i], alloc->lists[i]->size); + alloc->lists[i] = NULL; + } + + alloc->list_count = 1; + } + + FLNode *node = (FLNode *)alloc->lists[0]->data; + node->size = alloc->lists[0]->size; + node->next = &FL_NIL_NODE; + + alloc->lists[0]->head = node; + alloc->lists[0]->used = sizeof(FreeList); + + __atomic_thread_fence(__ATOMIC_RELEASE); + + __atomic_fetch_add(&alloc->next_ticket, 1, __ATOMIC_SEQ_CST); +} + +static FLNode *FreeListSearch(FreeList *alloc, usize size, usize alignment, usize *out_padding, FLNode **prev_node) { FLNode *node = alloc->head; - FLNode *prev = alloc->nil; + FLNode *prev = &FL_NIL_NODE; usize padding = 0; - while (node != alloc->nil) + while (node != &FL_NIL_NODE) { padding = CalcPaddingWithHeader((uintptr)node, (uintptr)alignment, sizeof(FLNode)); usize required_size = size + padding; @@ -199,12 +238,194 @@ static FLNode *FreeListSearch(FLAlloc *alloc, usize size, u32 alignment, u32 *ou return node; } -static rawptr FreeListAlloc(FLAlloc *alloc, usize size, u32 alignment) +/* + * NOT SAFE TO CALL OUTSIDE OF FreeListAlloc + */ +static void FreeListGrow(FLAlloc *alloc, usize alloc_size) +{ + alloc->list_count += 1; + u32 i = alloc->list_count; + if (i >= alloc->list_capacity) + { + alloc->list_capacity += 16; + rawptr new_mem = MemAlloc(sizeof(FreeList *) * alloc->list_capacity); + MemCpy(new_mem, alloc->lists, i); + MemFree(alloc->lists, sizeof(FreeList *) * i); + alloc->lists = new_mem; + } + + usize grow_size = alloc->grow_size; + if (alloc_size > grow_size) + grow_size += alloc_size; + + _FreeListInit(&alloc->lists[i], grow_size); + + FLNode *node = (FLNode *)alloc->lists[i]->data; + node->size = alloc->lists[i]->size; + node->next = alloc->nil; + + alloc->lists[i]->head = node; +} + +static rawptr _FreeListAllocAlign(FreeList *alloc, usize size, u32 alignment) { usize padding = 0; - FLNode *prev_node = alloc->nil; + FLNode *prev_node = &FL_NIL_NODE; + FLAllocHeader *header; + if (size < sizeof(FLNode)) + size = sizeof(FLNode); + + if (alignment < 8) + alignment = 8; + + FLNode *node = FreeListSearch(alloc, size, alignment, &padding, &prev_node); + + if (node == &FL_NIL_NODE) + Assert(0, "FreeListAllocAlign failed to allocate, oom"); - return NULL; + usize alignment_padding = padding - sizeof(FLAllocHeader); + usize required_space = size + padding; + usize remaining = node->size - required_space; + + if (remaining > 0) + { + FLNode *new_node = (FLNode *)(((c8 *)node) + required_space); + new_node->size = remaining; + FreeListInsert(&alloc->head, node, new_node); + } + + FreeListRemove(&alloc->head, prev_node, node); + + header = (FLAllocHeader *)(((c8 *)node) + alignment_padding); + header->size = required_space; + header->padding = alignment_padding; + + alloc->used += required_space; + + return (rawptr)(((c8 *)header) + sizeof(FLAllocHeader)); } + +static rawptr FreeListAlloc(FLAlloc *alloc, usize size) +{ + return FreeListAllocAlign(alloc, size, DEFAULT_ALIGNMENT); +} + +static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, u32 alignment) +{ + u32 ticket = __atomic_fetch_add(&alloc->ticket, 1, __ATOMIC_SEQ_CST); + while (ticket != alloc->next_ticket); + + FreeList *fl = NULL; + for (u32 i = 0; i < alloc->list_count; i++) + { + usize remaining = alloc->lists[i]->size - alloc->lists[i]->used; + if (size < remaining) + { + fl = alloc->lists[i]; + break; + } + } + + if (fl == NULL) + { + FreeListGrow(alloc, size); + fl = alloc->lists[alloc->list_count-1]; + } + + rawptr ptr = _FreeListAllocAlign(fl, size, alignment); + + __atomic_thread_fence(__ATOMIC_RELEASE); + + __atomic_add_fetch(&alloc->next_ticket, 1, __ATOMIC_SEQ_CST); + + return ptr; +} + +static void _FreeListFree(FreeList *alloc, rawptr ptr) +{ + FLAllocHeader *header = cast(FLAllocHeader *, u8ptr(ptr) - sizeof(FLAllocHeader)); + FLNode *free_node = cast(FLNode *,header); + free_node->size = header->size + header->padding; + free_node->next = &FL_NIL_NODE; + + FLNode *prev_node = &FL_NIL_NODE; + FLNode *node = alloc->head; + while (node != &FL_NIL_NODE) + { + if (ptr < node) + { + FreeListInsert(&alloc->head, prev_node, free_node); + break; + } + + prev_node = node; + node = node->next; + } + + alloc->used -= free_node->size; + + FreeListCoalescence(alloc, prev_node, free_node); +} + +static void FreeListFree(FLAlloc *alloc, rawptr ptr) +{ + if (ptr == NULL) return; + + u32 ticket = __atomic_fetch_add(&alloc->ticket, 1, __ATOMIC_SEQ_CST); + while (ticket != alloc->next_ticket); + + for (u32 i = 0; i < alloc->list_count; i++) + { + uintptr ptr_addr = uintptr(ptr); + uintptr start = uintptr(alloc->lists[i]->data); + uintptr end = uintptr(alloc->lists[i]->data) + uintptr(alloc->lists[i]->size); + if (ptr_addr >= start && ptr_addr < end) + { + _FreeListFree(alloc->lists[i], ptr); + break; + } + } +} + +static void FreeListCoalescence(FreeList *alloc, FLNode *prev_node, FLNode *free_node) +{ + if (free_node->next != &FL_NIL_NODE && (rawptr)(((c8 *)free_node) + free_node->size) == free_node->next) + { + free_node->size += free_node->next->size; + FreeListRemove(&alloc->head, free_node, free_node->next); + } + + if (prev_node->next != &FL_NIL_NODE && (rawptr)(((c8 *)prev_node) + prev_node->size) == free_node) + { + prev_node->size += free_node->next->size; + FreeListRemove(&alloc->head, prev_node, free_node); + } +} + +static void FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node) +{ + if (prev_node == &FL_NIL_NODE) + *head = del_node->next; + else + prev_node->next = del_node->next; +} + +static void FreeListInsert(FLNode **head, FLNode *prev_node, FLNode *new_node) +{ + if (prev_node == &FL_NIL_NODE) + { + if (*head != &FL_NIL_NODE) + new_node->next = *head; + else + *head = new_node; + } + else + { + new_node->next = prev_node->next; + prev_node->next = new_node; + } +} + +// ::Allocator::FreeList::End:: diff --git a/src/allocators.h b/src/allocators.h index 76b21d9..23d30bd 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -58,7 +58,7 @@ static void Free(rawptr ptr); typedef struct FLAllocHeader { - usize block_size; + usize size; usize padding; } FLAllocHeader; @@ -70,16 +70,35 @@ typedef struct FLNode usize size; } FLNode; -typedef struct FLAlloc +typedef struct FreeList { rawptr data; FLNode *head; - FLNode *nil; usize size; usize used; +} FreeList; + +typedef struct FLAlloc +{ + FreeList **lists; + u32 list_count; + u32 list_capacity; + u32 volatile ticket; + u32 volatile next_ticket; + FLNode *nil; + usize grow_size; } FLAlloc; -static void FLAllocInit(FLAlloc *alloc, usize size); -static void FLAllocFreeAll(FLAlloc *alloc); -static FLNode *FreeListSearch(FLAlloc *alloc, usize size, u32 alignment, u32 *out_padding, FLNode **prev_node); -static rawptr FreeListAlloc(FLAlloc *alloc, usize size, u32 alignment); +static void _FreeListInit(FreeList **alloc, usize size); +static void FreeListInit(FLAlloc *alloc, usize size); +static rawptr _FreeListAllocAlign(FreeList *alloc, usize size, u32 alignment); +static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, u32 alignment); +static rawptr FreeListAlloc(FLAlloc *alloc, usize size); +static void _FreeListFree(FreeList *alloc, rawptr ptr); +static void FreeListFree(FLAlloc *alloc, rawptr ptr); +static void FreeListFreeAll(FLAlloc *alloc); +static void FreeListGrow(FLAlloc *alloc, usize alloc_size); +static FLNode *FreeListSearch(FreeList *alloc, usize size, usize alignment, usize *out_padding, FLNode **prev_node); +static void FreeListCoalescence(FreeList *alloc, FLNode *prev_node, FLNode *free_node); +static void FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node); +static void FreeListInsert(FLNode **head, FLNode *prev_node, FLNode *new_node); diff --git a/src/entry_linux.c b/src/entry_linux.c index 3109e1b..1d49c2a 100644 --- a/src/entry_linux.c +++ b/src/entry_linux.c @@ -108,7 +108,7 @@ int main(int argc, char **argv) WaitForWindowEvent(inputs); - GameContext ctx = {}; + GameContext ctx = {0}; InitializeGame(renderer_arena, &ctx, game_arena); diff --git a/src/packer.c b/src/packer.c index 8c9965f..2b48528 100644 --- a/src/packer.c +++ b/src/packer.c @@ -31,8 +31,8 @@ const FileMapping g_Texture_File_Map[] = { { .file_name = "purplemon.png", .ix = PATTERMON_PURPLOID }, }; -c8 *g_Shader_File_Names[SHADER_ASSET_MAX] = {}; -c8 *g_Texture_File_Names[TEXTURE_ASSET_MAX] = {}; +c8 *g_Shader_File_Names[SHADER_ASSET_MAX] = {0}; +c8 *g_Texture_File_Names[TEXTURE_ASSET_MAX] = {0}; // ::Packer::Globals::End:: @@ -380,7 +380,7 @@ int main(int argc, c8 **argv) FILE *file = fopen("assets.sgp", "w+"); Assert(file != NULL, "File is null"); - FileHeader header = {}; + FileHeader header = {0}; InitHeader(&header); PackFiles(arena, &header); diff --git a/src/renderer_vulkan.c b/src/renderer_vulkan.c index adf712d..eb69eea 100644 --- a/src/renderer_vulkan.c +++ b/src/renderer_vulkan.c @@ -17,7 +17,7 @@ static Renderer renderer = { } }; -static u32 vk_thread_indices[10] = {}; +static u32 vk_thread_indices[10] = {0}; #if __linux__ pthread_cond_t cond; diff --git a/src/renderer_vulkan_public.c b/src/renderer_vulkan_public.c index b5d5cf3..0ada440 100644 --- a/src/renderer_vulkan_public.c +++ b/src/renderer_vulkan_public.c @@ -209,8 +209,8 @@ static b32 UploadToBuffer(RenderBuffer **buffers, rawptr *ptrs, u32 count, u8 th VkDevice device = renderer.vk.device; VkQueue queue = renderer.vk.queues.transfer_queue; VmaAllocator alloc = renderer.vk.alloc; - rawptr mapped_buffers[16] = {}; - RenderBuffer staging_buffers[16] = {}; + rawptr mapped_buffers[16] = {0}; + RenderBuffer staging_buffers[16] = {0}; u32 copy_count = 0; diff --git a/src/tests.c b/src/tests.c index 2688695..9e5cf00 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1,5 +1,48 @@ void RunTests() { - + TestFreeListAlloc(); +} + +void TestFreeListAlloc() +{ + FLAlloc alloc = {0}; + usize alloc_size = KB(256); + FreeListInit(&alloc, alloc_size); + u8 *value = (u8 *)(uintptr(alloc.lists[0]->data) + uintptr(alloc_size-sizeof(FreeList)-2)); + *value = 255; + Assert(*value == 255, "data set is invalid"); + + u32 u32_count = 2000; + u32 f64_count = 3000; + + u32 *u32_arr = FreeListAlloc(&alloc, sizeof(u32) * u32_count); + f64 *f64_arr = FreeListAlloc(&alloc, sizeof(f64) * f64_count); + + for (u32 i = 0; i < u32_count; i++) + { + u32_arr[i] = 3 * i; + } + + for (u32 i = 0; i < f64_count; i++) + { + f64_arr[i] = f64(i); + } + + for (u32 i = 0; i < u32_count; i++) + { + Assert(u32_arr[i] == 3 * i, "u32 memory incorrect"); + } + + for (u32 i = 0; i < f64_count; i++) + { + Assert(f64_arr[i] == f64(i), "f64 memory incorrect"); + } + + FreeListFree(&alloc, u32_arr); + + for (u32 i = 0; i < f64_count; i++) + { + Assert(f64_arr[i] == f64(i), "f64 memory incorrect post free"); + } } diff --git a/src/tests.h b/src/tests.h index ad3af62..99807b7 100644 --- a/src/tests.h +++ b/src/tests.h @@ -1,3 +1,5 @@ #pragma once void RunTests(); +void TestFreeListAlloc(); + diff --git a/src/util.h b/src/util.h index 1312bac..641e80f 100644 --- a/src/util.h +++ b/src/util.h @@ -24,6 +24,31 @@ typedef struct Arena Arena; #define Str8L(x) (Str8){ .len = StrLen(x), .value = (u8 *)x } #define MakeString(x) #x +#define i8(x) ((i8)(x)) +#define i16(x) ((i16)(x)) +#define i32(x) ((i32)(x)) +#define i64(x) ((i64)(x)) + +#define u8(x) ((u8)(x)) +#define u16(x) ((u16)(x)) +#define u32(x) ((u32)(x)) +#define u64(x) ((u64)(x)) + +#define c8(x) ((c8)(x)) +#define c8ptr(x) ((c8 *)(x)) +#define u8ptr(x) ((u8 *)(x)) +#define i8ptr(x) ((i8 *)(x)) + +#define intptr(x) ((intptr)(x)) +#define uintptr(x) ((uintptr)(x)) + +#define f32(x) ((f32)(x)) +#define f64(x) ((f64)(x)) + +#define rawptr(x) ((rawptr)(x)) + +#define cast(T, x) ((T)(x)) + // ::Util::Defines::Header:: #define HM_MAX_SYMBOLS 256