From e391faf5749c9a4ad2d4350dd6add04215dff174 Mon Sep 17 00:00:00 2001 From: MysterD Date: Fri, 12 May 2023 13:19:10 -0700 Subject: [PATCH] WIP: start making memory management better --- data/dynos_misc.cpp | 23 +++++----- src/engine/level_script.c | 23 ++++++---- src/game/memory.c | 66 +--------------------------- src/game/memory.h | 19 +++++--- src/game/memory_dynamic.c | 48 ++++++++++++++++++++ src/game/rendering_graph_node.c | 10 ++--- src/pc/lua/utils/smlua_model_utils.c | 7 ++- 7 files changed, 97 insertions(+), 99 deletions(-) create mode 100644 src/game/memory_dynamic.c diff --git a/data/dynos_misc.cpp b/data/dynos_misc.cpp index a1bb0ec4..05fd7c61 100644 --- a/data/dynos_misc.cpp +++ b/data/dynos_misc.cpp @@ -139,6 +139,8 @@ static void _RelocateGraphNodePointers(struct GraphNode *aHead, u64 aOffset) { static Array> sLoadedGraphNodes = {}; +// DO NOT COMMIT: +// need to separate pools into one that will be free'd and one that wont be and when void *DynOS_Geo_GetGraphNode(const void *aGeoLayout, bool aKeepInMemory) { if (aKeepInMemory) { s32 _LoadedGraphNodeIndex = sLoadedGraphNodes.FindIf([&aGeoLayout](const Pair &aLoadedGraphNode) { return aLoadedGraphNode.first == aGeoLayout; }); @@ -148,31 +150,28 @@ void *DynOS_Geo_GetGraphNode(const void *aGeoLayout, bool aKeepInMemory) { } // Process the geo layout on a large pool of memory (16 MB) - struct AllocOnlyPool *_Pool = (struct AllocOnlyPool *) calloc(1, 0x1000000); - _Pool->totalSpace = 0x1000000 - sizeof(struct AllocOnlyPool); - _Pool->usedSpace = 0; - _Pool->startPtr = (u8 *) _Pool + sizeof(struct AllocOnlyPool); - _Pool->freePtr = (u8 *) _Pool + sizeof(struct AllocOnlyPool); + struct AllocOnlyPool *_Pool = alloc_only_pool_init(); void *_Processed = process_geo_layout(_Pool, (void *) aGeoLayout); // Copy the graph node data to the minimum amount of memory needed if (_Processed && _Pool->usedSpace != 0) { - struct GraphNode *_Node = (struct GraphNode *) calloc(1, _Pool->usedSpace); + /*struct GraphNode *_Node = (struct GraphNode *) calloc(1, _Pool->usedSpace); memcpy(_Node, _Pool->startPtr, _Pool->usedSpace); // Relocate all graph pointers u64 _Offset = (u64) _Node - (u64) _Pool->startPtr; - _RelocateGraphNodePointers(_Node, _Offset); + _RelocateGraphNodePointers(_Node, _Offset);*/ // Add it to loaded graph nodes - if (aKeepInMemory) { - sLoadedGraphNodes.Add({ (void *) aGeoLayout, (void *) _Node }); + if (aKeepInMemory || true) { // DO NOT COMMIT + //sLoadedGraphNodes.Add({ (void *) aGeoLayout, (void *) _Node }); + sLoadedGraphNodes.Add({ (void *) aGeoLayout, (void *) _Processed }); } - free(_Pool); - return _Node; + return _Processed; + } else { + alloc_only_pool_free(_Pool); } - free(_Pool); return NULL; } diff --git a/src/engine/level_script.c b/src/engine/level_script.c index 55c2ae62..be186698 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -107,8 +107,7 @@ static s32 eval_script_op(s8 op, s32 arg) { struct ObjectWarpNode *area_create_warp_node(u8 id, u8 destLevel, u8 destArea, u8 destNode, u8 checkpoint, struct Object *o) { if (sCurrAreaIndex != -1) { - struct ObjectWarpNode *warpNode = - alloc_only_pool_alloc(sLevelPool, sizeof(struct ObjectWarpNode)); + struct ObjectWarpNode *warpNode = alloc_only_pool_alloc(sLevelPool, sizeof(struct ObjectWarpNode)); warpNode->node.id = id; warpNode->node.destLevel = destLevel + checkpoint; @@ -395,9 +394,15 @@ static void level_cmd_alloc_level_pool(void) { } } + // free previous level pool + if (sLevelPool != NULL) { + alloc_only_pool_free(sLevelPool); + sLevelPool = NULL; + } + + // allocate new level pool if (sLevelPool == NULL) { - sLevelPool = alloc_only_pool_init(main_pool_available() - sizeof(struct AllocOnlyPool), - MEMORY_POOL_LEFT); + sLevelPool = alloc_only_pool_init(); } sCurrentCmd = CMD_NEXT; @@ -406,8 +411,11 @@ static void level_cmd_alloc_level_pool(void) { static void level_cmd_free_level_pool(void) { s32 i; - alloc_only_pool_resize(sLevelPool, sLevelPool->usedSpace); - sLevelPool = NULL; + if (!sFinishedLoadingPerm) { + sFinishedLoadingPerm = true; + // make sure we don't free the pool with the permanent models + sLevelPool = NULL; + } for (i = 0; i < 8; i++) { if (gAreaData[i].terrainData != NULL) { @@ -472,9 +480,6 @@ static void level_cmd_load_model_from_geo(void) { gLoadedGraphNodes[arg0] = process_geo_layout(sLevelPool, arg1); if (sFinishedLoadingPerm) { sLevelOwnedGraphNodes[arg0] = true; } smlua_model_util_remember(arg0, LAYER_OPAQUE, arg1, 0); - if (arg0 == MODEL_ERROR_MODEL) { - sFinishedLoadingPerm = true; - } } sCurrentCmd = CMD_NEXT; diff --git a/src/game/memory.c b/src/game/memory.c index 40510826..71df74d9 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -218,6 +218,7 @@ u32 main_pool_push_state(void) { * amount of free space left in the pool. */ u32 main_pool_pop_state(void) { + if (!gMainPoolState) { return sPoolFreeSpace; } sPoolFreeSpace = gMainPoolState->freeSpace; sPoolListHeadL = gMainPoolState->listHeadL; sPoolListHeadR = gMainPoolState->listHeadR; @@ -248,71 +249,6 @@ static void *dynamic_dma_read(u8 *srcStart, u8 *srcEnd, u32 side) { return dest; } -/** - * Allocate an allocation-only pool from the main pool. This pool doesn't - * support freeing allocated memory. - * Return NULL if there is not enough space in the main pool. - */ -struct AllocOnlyPool *alloc_only_pool_init(u32 size, u32 side) { - void *addr; - struct AllocOnlyPool *subPool = NULL; - - size = ALIGN4(size); - addr = main_pool_alloc(size + sizeof(struct AllocOnlyPool), side); - if (addr != NULL) { - subPool = (struct AllocOnlyPool *) addr; - subPool->totalSpace = size; - subPool->usedSpace = 0; - subPool->startPtr = (u8 *) addr + sizeof(struct AllocOnlyPool); - subPool->freePtr = (u8 *) addr + sizeof(struct AllocOnlyPool); - } - if (addr == NULL) { - LOG_ERROR("Allocate only pool failed to initalize memory of size 0x%X on side %d.", size, side); - } - return subPool; -} - -/** - * Allocate from an allocation-only pool. - * Return NULL if there is not enough space. - */ -void *alloc_only_pool_alloc(struct AllocOnlyPool *pool, s32 size) { - void *addr = NULL; - - size = ALIGN4(size); - if (size > 0 && pool->usedSpace + size <= pool->totalSpace) { - addr = pool->freePtr; - pool->freePtr += size; - pool->usedSpace += size; - } - if (addr == NULL) { - LOG_ERROR("Allocate only pool failed to allocate memory of size 0x%X on at pool %p.", size, pool); - } else { - memset(addr, 0, size); - } - return addr; -} - -/** - * Resize an allocation-only pool. - * If the pool is increasing in size, the pool must be the last thing allocated - * from the left end of the main pool. - * The pool does not move. - */ -struct AllocOnlyPool *alloc_only_pool_resize(struct AllocOnlyPool *pool, u32 size) { - struct AllocOnlyPool *newPool; - - size = ALIGN4(size); - newPool = main_pool_realloc(pool, size + sizeof(struct AllocOnlyPool)); - if (newPool != NULL) { - pool->totalSpace = size; - } - if (newPool == NULL) { - LOG_ERROR("Allocate only pool failed to reallocate memory of size 0x%X on at pool %p.", size, pool); - } - return newPool; -} - /** * Allocate a memory pool from the main pool. This pool supports arbitrary * order for allocation/freeing. diff --git a/src/game/memory.h b/src/game/memory.h index 4579c18c..2b69bfc9 100644 --- a/src/game/memory.h +++ b/src/game/memory.h @@ -13,10 +13,14 @@ struct AllocOnlyPool { - s32 totalSpace; - s32 usedSpace; - u8 *startPtr; - u8 *freePtr; + u32 usedSpace; + struct AllocOnlyNode* tail; +}; + +struct AllocOnlyNode +{ + void* ptr; + struct AllocOnlyNode* prev; }; struct MemoryPool; @@ -50,9 +54,10 @@ u32 main_pool_pop_state(void); #define load_segment_decompress_heap(...) #define load_engine_code_segment(...) -struct AllocOnlyPool *alloc_only_pool_init(u32 size, u32 side); -void *alloc_only_pool_alloc(struct AllocOnlyPool *pool, s32 size); -struct AllocOnlyPool *alloc_only_pool_resize(struct AllocOnlyPool *pool, u32 size); +struct AllocOnlyPool* alloc_only_pool_init(void); +void* alloc_only_pool_alloc(struct AllocOnlyPool *pool, u32 size); +struct AllocOnlyPool* alloc_only_pool_resize(struct AllocOnlyPool *pool, u32 size); +void alloc_only_pool_free(struct AllocOnlyPool *pool); struct MemoryPool *mem_pool_init(u32 size, u32 side); void *mem_pool_alloc(struct MemoryPool *pool, u32 size); diff --git a/src/game/memory_dynamic.c b/src/game/memory_dynamic.c new file mode 100644 index 00000000..109c35fc --- /dev/null +++ b/src/game/memory_dynamic.c @@ -0,0 +1,48 @@ +#include +#include + +#include "sm64.h" + +#define INCLUDED_FROM_MEMORY_C + +#include "buffers/buffers.h" +#include "decompress.h" +#include "game_init.h" +#include "main.h" +#include "memory.h" +#include "segment_symbols.h" +#include "segments.h" +#include "pc/debuglog.h" + +struct AllocOnlyPool* alloc_only_pool_init(void) { + struct AllocOnlyPool* pool = calloc(1, sizeof(struct AllocOnlyPool)); + pool->usedSpace = 0; + pool->tail = NULL; + return pool; +} + +void* alloc_only_pool_alloc(struct AllocOnlyPool *pool, u32 size) { + struct AllocOnlyNode* node = calloc(1, sizeof(struct AllocOnlyNode)); + node->ptr = calloc(1, size); + node->prev = pool->tail; + + pool->tail = node; + pool->usedSpace += size; + + return node->ptr; +} + +struct AllocOnlyPool* alloc_only_pool_resize(UNUSED struct AllocOnlyPool* pool, UNUSED u32 size) { + return NULL; +} + +void alloc_only_pool_free(struct AllocOnlyPool *pool) { + struct AllocOnlyNode* node = pool->tail; + while (node) { + struct AllocOnlyNode* prev = node->prev; + free(node->ptr); + free(node); + node = prev; + } + free(pool); +} \ No newline at end of file diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 4527cf51..20912e4f 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -1623,7 +1623,7 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) Vp *viewport = alloc_display_list(sizeof(*viewport)); if (viewport == NULL) { return; } - gDisplayListHeap = alloc_only_pool_init(main_pool_available() - sizeof(struct AllocOnlyPool), MEMORY_POOL_LEFT); + gDisplayListHeap = alloc_only_pool_init(); Mtx *initialMatrix = alloc_display_list(sizeof(*initialMatrix)); if (initialMatrix == NULL) { return; } @@ -1665,9 +1665,9 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) geo_process_node_and_siblings(node->node.children); } gCurGraphNodeRoot = NULL; - if (gShowDebugText) { - print_text_fmt_int(180, 36, "MEM %d", gDisplayListHeap->totalSpace - gDisplayListHeap->usedSpace); - } - main_pool_free(gDisplayListHeap); + //if (gShowDebugText) { + // print_text_fmt_int(180, 36, "MEM %d", gDisplayListHeap->totalSpace - gDisplayListHeap->usedSpace); + //} + alloc_only_pool_free(gDisplayListHeap); } } \ No newline at end of file diff --git a/src/pc/lua/utils/smlua_model_utils.c b/src/pc/lua/utils/smlua_model_utils.c index 2a045a20..57961007 100644 --- a/src/pc/lua/utils/smlua_model_utils.c +++ b/src/pc/lua/utils/smlua_model_utils.c @@ -548,6 +548,11 @@ void smlua_model_util_clear(void) { //LOG_INFO("Cleared runtime model cache."); } +// DO NOT COMMIT +// smlua_model_util_load_with_pool_and_cache_id() needs to be reworked to use dynamic pools correctly +// DO NOT COMMIT + + u16 smlua_model_util_load_with_pool_and_cache_id(enum ModelExtendedId extId, struct AllocOnlyPool* pool, u16 loadedId) { if (extId == E_MODEL_NONE) { return MODEL_NONE; } if (extId >= (u16)(E_MODEL_MAX + sCustomModelsCount)) { @@ -593,7 +598,7 @@ u16 smlua_model_util_load_with_pool_and_cache_id(enum ModelExtendedId extId, str // load bool resizePool = false; if (pool == NULL) { - pool = alloc_only_pool_init(main_pool_available() - sizeof(struct AllocOnlyPool), MEMORY_POOL_LEFT); + pool = alloc_only_pool_init(); resizePool = true; } info->shouldFreeAsset = false;