Keep the previous dynamic pool in memory

Due to sm64 weirdness, I can't reliably free memory at certain points
The hacky solution is to keep the previous dynamic pool in memory,
essentially requiring two frees to actually clear all memory from it
This commit is contained in:
MysterD 2023-05-17 22:33:14 -07:00
parent c126bf82b3
commit f53ffcd491
6 changed files with 19 additions and 29 deletions

View file

@ -21,18 +21,12 @@ struct ModelInfo {
enum ModelPool modelPool;
};
struct ScheduledFreePool {
struct DynamicPool* pool;
};
static struct DynamicPool* sModelPools[MODEL_POOL_MAX] = { 0 };
static std::map<void*, struct ModelInfo> sAssetMap[MODEL_POOL_MAX];
static std::map<u32, std::vector<struct ModelInfo>> sIdMap;
static std::map<u32, u32> sOverwriteMap;
static std::vector<struct ScheduledFreePool> sPoolsToFree;
static u32 find_empty_id() {
u32 id = 256;
while (true) {
@ -168,12 +162,7 @@ void DynOS_Model_ClearPool(enum ModelPool aModelPool) {
if (!sModelPools[aModelPool]) { return; }
// schedule pool to be freed
sPoolsToFree.push_back({
.pool = sModelPools[aModelPool],
});
// clear pointer
sModelPools[aModelPool] = NULL;
dynamic_pool_free_pool(sModelPools[aModelPool]);
// clear overwrite
if (aModelPool == MODEL_POOL_LEVEL) {
@ -202,12 +191,4 @@ void DynOS_Model_ClearPool(enum ModelPool aModelPool) {
void DynOS_Model_Update() {
// only free a pool when we've scheduled at least 3
// this is required because the way that sm64 loads areas is actually insane
// if we free immediately, the camera graph node is incorrect on the star selection screen
if (sPoolsToFree.size() <= 2) { return; }
auto& it = sPoolsToFree[0];
dynamic_pool_free_pool(it.pool);
sPoolsToFree.erase(sPoolsToFree.begin());
}

View file

@ -366,7 +366,6 @@ static void level_reset_globals(void) {
// free previous level pool
if (gLevelPool != NULL) {
dynamic_pool_free_pool(gLevelPool);
gLevelPool = NULL;
}
// reset envfx

View file

@ -156,11 +156,8 @@ void envfx_update_snowflake_count(s32 mode, Vec3s marioPos) {
* Deallocate the buffer storing snow particles and set the environment effect
* to none.
*/
void envfx_cleanup_snow(void *snowParticleArray) {
void envfx_cleanup_snow(UNUSED void *snowParticleArray) {
if (gEnvFxMode) {
if (snowParticleArray) {
dynamic_pool_free(gLevelPool, snowParticleArray);
}
gEnvFxMode = ENVFX_MODE_NONE;
}
}

View file

@ -16,6 +16,7 @@ struct DynamicPool* dynamic_pool_init(void) {
struct DynamicPool* pool = calloc(1, sizeof(struct DynamicPool));
pool->usedSpace = 0;
pool->tail = NULL;
pool->nextFree = NULL;
return pool;
}
@ -75,14 +76,19 @@ bool dynamic_pool_contains(struct DynamicPool *pool, void* ptr) {
void dynamic_pool_free_pool(struct DynamicPool *pool) {
if (!pool) { return; }
struct DynamicPoolNode* node = pool->tail;
struct DynamicPoolNode* node = pool->nextFree;
while (node) {
struct DynamicPoolNode* prev = node->prev;
free(node->ptr);
free(node);
node = prev;
}
free(pool);
// schedule current pool to be free'd on the next call
pool->nextFree = pool->tail;
pool->tail = NULL;
pool->usedSpace = 0;
}
//////////////////

View file

@ -14,6 +14,7 @@
struct DynamicPool
{
u32 usedSpace;
struct DynamicPoolNode* nextFree;
struct DynamicPoolNode* tail;
};

View file

@ -1526,8 +1526,14 @@ Gfx *display_painting_rippling(struct Painting *painting) {
}
// The mesh data is freed every frame.
dynamic_pool_free(gLevelPool, painting->ripples.paintingMesh);
dynamic_pool_free(gLevelPool, painting->ripples.paintingTriNorms);
if (painting->ripples.paintingMesh) {
dynamic_pool_free(gLevelPool, painting->ripples.paintingMesh);
painting->ripples.paintingMesh = NULL;
}
if (painting->ripples.paintingTriNorms) {
dynamic_pool_free(gLevelPool, painting->ripples.paintingTriNorms);
painting->ripples.paintingTriNorms = NULL;
}
return dlist;
}