From a6c1b2a3d1ec172332ebda46ff980c9a38afe58c Mon Sep 17 00:00:00 2001 From: PeachyPeach <72323920+PeachyPeachSM64@users.noreply.github.com> Date: Tue, 14 May 2024 01:08:51 +0200 Subject: [PATCH] Fix surface_load memory leaks and improve performance (#38) --- src/engine/surface_load.c | 32 +++++++-------------- src/game/memory.c | 58 +++++++++++++++++++++++++++++++++++++++ src/game/memory.h | 12 ++++++++ 3 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index eec3254d..3015b7b7 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -31,36 +31,24 @@ SpatialPartitionCell gDynamicSurfacePartition[NUM_CELLS][NUM_CELLS]; /** * Pools of data to contain either surface nodes or surfaces. */ -struct GrowingPool* sSurfaceNodePool = NULL; -struct GrowingPool* sSurfacePool = NULL; +static struct GrowingArray *sSurfaceNodePool = NULL; +static struct GrowingArray *sSurfacePool = NULL; /** * Allocate the part of the surface node pool to contain a surface node. */ -static struct SurfaceNode* alloc_surface_node(void) { - struct SurfaceNode* node = (struct SurfaceNode*)growing_pool_alloc(sSurfaceNodePool, sizeof(struct SurfaceNode)); - node->next = NULL; - - gSurfaceNodesAllocated++; - return node; +static struct SurfaceNode *alloc_surface_node(void) { + sSurfaceNodePool->count = gSurfaceNodesAllocated++; + return growing_array_alloc(sSurfaceNodePool, sizeof(struct SurfaceNode)); } /** * Allocate the part of the surface pool to contain a surface and * initialize the surface. */ -static struct Surface* alloc_surface(void) { - struct Surface* surface = (struct Surface*)growing_pool_alloc(sSurfacePool, sizeof(struct Surface)); - - surface->type = 0; - surface->force = 0; - surface->flags = 0; - surface->room = 0; - surface->object = NULL; - - gSurfacesAllocated++; - - return surface; +static struct Surface *alloc_surface(void) { + sSurfacePool->count = gSurfacesAllocated++; + return growing_array_alloc(sSurfacePool, sizeof(struct Surface)); } /** @@ -481,8 +469,8 @@ void alloc_surface_pools(void) { clear_static_surfaces(); clear_dynamic_surfaces(); - sSurfaceNodePool = growing_pool_init(sSurfaceNodePool, sizeof(struct SurfaceNode) * 1000); - sSurfacePool = growing_pool_init(sSurfacePool, sizeof(struct Surface) * 1000); + sSurfaceNodePool = growing_array_init(sSurfaceNodePool, 0x1000); + sSurfacePool = growing_array_init(sSurfacePool, 0x400); gEnvironmentRegions = NULL; gSurfaceNodesAllocated = 0; diff --git a/src/game/memory.c b/src/game/memory.c index 82c0bfc8..0d4bec3f 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -2,6 +2,7 @@ #include #include "memory.h" +#include "print.h" #include "pc/debuglog.h" #define ALIGN16(val) (((val) + 0xF) & ~0xF) @@ -180,6 +181,63 @@ void growing_pool_free_pool(struct GrowingPool *pool) { free(pool); } + /////////////////// + // growing array // +/////////////////// + +struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity) { + growing_array_free(&array); + array = calloc(1, sizeof(struct GrowingArray)); + array->buffer = calloc(capacity, sizeof(void *)); + array->capacity = capacity; + array->count = 0; + return array; +} + +void *growing_array_alloc(struct GrowingArray *array, u32 size) { + if (array && array->buffer) { + + // Increase capacity if needed + while (array->count >= array->capacity) { + u32 newCapacity = array->capacity * 2; + void **newBuffer = calloc(newCapacity, sizeof(void *)); + memcpy(newBuffer, array->buffer, array->capacity * sizeof(void *)); + free(array->buffer); + array->buffer = newBuffer; + array->capacity = newCapacity; + } + + // Alloc element if needed + void **elem = &array->buffer[array->count++]; + if (!*elem) { + *elem = malloc(size); + } + memset(*elem, 0, size); + return *elem; + } + return NULL; +} + +void growing_array_free(struct GrowingArray **array) { + if (*array) { + for (u32 i = 0; i != (*array)->capacity; ++i) { + if ((*array)->buffer[i]) { + free((*array)->buffer[i]); + } + } + free((*array)->buffer); + free(*array); + *array = NULL; + } +} + +void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y) { + char text[256]; + u32 allocated = 0; for (u32 i = 0; i != array->capacity; ++i) { allocated += (array->buffer[i] != NULL); } + snprintf(text, 256, "%-12s %5u/%5u/%5u", name, array->count, allocated, array->capacity); + print_text(x, y, text); +} + /////////////////// // display lists // /////////////////// diff --git a/src/game/memory.h b/src/game/memory.h index 9fc0d7a9..8c964c82 100644 --- a/src/game/memory.h +++ b/src/game/memory.h @@ -39,6 +39,13 @@ struct GrowingPoolNode struct GrowingPoolNode* prev; }; +struct GrowingArray +{ + void **buffer; + u32 count; + u32 capacity; +}; + struct MarioAnimation; struct Animation; @@ -63,6 +70,11 @@ struct GrowingPool* growing_pool_init(struct GrowingPool* pool, u32 nodeSize); void* growing_pool_alloc(struct GrowingPool *pool, u32 size); void growing_pool_free_pool(struct GrowingPool *pool); +struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity); +void *growing_array_alloc(struct GrowingArray *array, u32 size); +void growing_array_free(struct GrowingArray **array); +void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y); + void alloc_display_list_reset(void); void *alloc_display_list(u32 size);