From 96ac39724d6099e984879e13ae78700fdf596a57 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Fri, 26 May 2017 13:31:01 +1000 Subject: [PATCH] Add asset array memory api stubs --- src/DTRenderer.cpp | 28 ++++---- src/DTRendererAsset.cpp | 151 ++++++++++++++++++++++++++++++++------- src/DTRendererDebug.cpp | 14 ++-- src/DTRendererPlatform.h | 5 +- src/Win32DTRenderer.cpp | 26 +++---- src/dqn.h | 41 ++++++----- 6 files changed, 190 insertions(+), 75 deletions(-) diff --git a/src/DTRenderer.cpp b/src/DTRenderer.cpp index 09d3e82..ad0b2c9 100644 --- a/src/DTRenderer.cpp +++ b/src/DTRenderer.cpp @@ -962,33 +962,35 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer, DTRAsset_InitGlobalState(); memory->isInit = true; - memory->context = DqnMemStack_Push(&memory->permMemStack, sizeof(DTRState)); - DQN_ASSERT(memory->context); + memory->context = DqnMemStack_Push(&memory->mainStack, sizeof(DTRState)); + DqnMemStack *const assetStack = &memory->assetStack; + DqnMemStack *const tempStack = &memory->tempStack; + DQN_ASSERT(memory->context); state = (DTRState *)memory->context; DTRAsset_FontToBitmapLoad(input->api, memory, &state->font, "Roboto-bold.ttf", DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), 12); - DTRAsset_BitmapLoad(input->api, &memory->permMemStack, - &memory->transMemStack, &state->bitmap, "tree00.bmp"); + DTRAsset_BitmapLoad(input->api, assetStack, + tempStack, &state->bitmap, "tree00.bmp"); if (DTR_DEBUG) { DTRBitmap test = {}; - DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->transMemStack); - DTRAsset_BitmapLoad(input->api, &memory->permMemStack, &memory->transMemStack, &test, "byte_read_check.bmp"); + DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->tempStack); + DTRAsset_BitmapLoad(input->api, assetStack, &memory->tempStack, &test, "byte_read_check.bmp"); DqnMemStack_EndTempRegion(tmp); } if (DTRAsset_WavefModelLoad(input->api, memory, &state->obj, "african_head.obj")) { - DTRAsset_BitmapLoad(input->api, &memory->permMemStack, &memory->transMemStack, - &state->objTex, "african_head_diffuse.tga"); + DTRAsset_BitmapLoad(input->api, assetStack, tempStack, &state->objTex, + "african_head_diffuse.tga"); } DTRDebug_TestWavefFaceAndVertexParser(&state->obj); } - DqnTempMemStack transMemTmpRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack); + DqnTempMemStack transMemTmpRegion = DqnMemStack_BeginTempRegion(&memory->tempStack); DTRRenderBuffer renderBuffer = {}; renderBuffer.width = platformRenderBuffer->width; @@ -997,7 +999,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer, renderBuffer.memory = (u8 *)platformRenderBuffer->memory; u32 zBufferSize = platformRenderBuffer->width * platformRenderBuffer->height; - renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(&memory->transMemStack, + renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(&memory->tempStack, zBufferSize * sizeof(*renderBuffer.zBuffer)); for (u32 i = 0; i < zBufferSize; i++) renderBuffer.zBuffer[i] = DQN_F32_MIN; @@ -1153,8 +1155,8 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer, // End Update //////////////////////////////////////////////////////////////////////////// DqnMemStack_EndTempRegion(transMemTmpRegion); - DqnMemStack_ClearCurrBlock(&memory->transMemStack, true); + DqnMemStack_ClearCurrBlock(&memory->tempStack, true); - DQN_ASSERT(memory->transMemStack.tempStackCount == 0); - DQN_ASSERT(memory->permMemStack.tempStackCount == 0); + DQN_ASSERT(memory->tempStack.tempStackCount == 0); + DQN_ASSERT(memory->mainStack.tempStackCount == 0); } diff --git a/src/DTRendererAsset.cpp b/src/DTRendererAsset.cpp index a177e63..5d96fef 100644 --- a/src/DTRendererAsset.cpp +++ b/src/DTRendererAsset.cpp @@ -17,17 +17,117 @@ void DTRAsset_InitGlobalState() stbi_set_flip_vertically_on_load(true); } -FILE_SCOPE bool WavefModelInit(DTRWavefModel *const obj, const i32 vertexInitCapacity = 100, - const i32 faceInitCapacity = 100) +FILE_SCOPE void MemcopyInternal(u8 *dest, u8 *src, size_t numBytes) +{ + if (!dest || !src || numBytes == 0) return; + for (size_t i = 0; i < numBytes; i++) + dest[i] = src[i]; +} + +FILE_SCOPE void AssetDqnArrayMemAPICallback(DqnMemAPICallbackInfo info, DqnMemAPICallbackResult *result) +{ + DQN_ASSERT(info.type != DqnMemAPICallbackType_Invalid); + DqnMemStack *stack = static_cast(info.userContext); + switch (info.type) + { + case DqnMemAPICallbackType_Alloc: + { + void *ptr = DqnMemStack_Push(stack, info.requestSize); + result->newMemPtr = ptr; + result->type = DqnMemAPICallbackType_Alloc; + } + break; + + case DqnMemAPICallbackType_Free: + { + DqnMemStackBlock **blockPtr = &stack->block; + while (*blockPtr && (*blockPtr)->memory != info.ptrToFree) + { + // NOTE(doyle): Ensure that the base ptr of each block is always + // actually aligned so we don't ever miss finding the block if + // the allocator had to realign the pointer from the base + // address. + if (DTR_DEBUG) + { + size_t memBaseAddr = (size_t)((*blockPtr)->memory); + DQN_ASSERT(DQN_ALIGN_POW_N(memBaseAddr, stack->byteAlign) == + memBaseAddr); + } + blockPtr = &((*blockPtr)->prevBlock); + } + + DQN_ASSERT(*blockPtr && (*blockPtr)->memory == info.ptrToFree); + DqnMemStackBlock *blockToFree = *blockPtr; + *blockPtr = blockToFree->prevBlock; + DqnMem_Free(blockToFree); + + } + break; + + case DqnMemAPICallbackType_Realloc: + { + result->type = DqnMemAPICallbackType_Realloc; + + // Check if the ptr is the last thing that was allocated. If so we + // can check if there's enough space in place for realloc and give + // them that. + u8 *currMemPtr = (u8 *)(stack->block->memory + stack->block->used); + u8 *checkPtr = currMemPtr - info.oldSize; + if (checkPtr == info.oldMemPtr) + { + if ((stack->block->used + info.newRequestSize) < stack->block->size) + { + stack->block->used += info.newRequestSize; + result->newMemPtr = info.oldMemPtr; + return; + } + + // The allocation was the last one allocated, but there's not + // enough space to realloc in the block. For book-keeping, + // "deallocate" the old mem ptr by reverting the usage of the + // memory stack. + stack->block->used -= info.oldSize; + } + + // NOTE(doyle): This leaves chunks of memory dead!!! But, we use + // this in our custom allocator, which its strategy is to load all + // the data, using as much re-allocations as required then after the + // fact, recompact the data by Memcopying the data together and free + // the extraneous blocks we've made. + + // Otherwise, not enough space or, allocation is not the last + // allocated, so can't expand inplace. + DqnMemStackBlock *newBlock = + DqnMemStack_AllocateCompatibleBlock(stack, info.newRequestSize); + if (DqnMemStack_AttachBlock(stack, newBlock)) + { + void *newPtr = DqnMemStack_Push(stack, info.newRequestSize); + MemcopyInternal((u8 *)newPtr, (u8 *)info.oldMemPtr, info.oldSize); + + result->newMemPtr = newPtr; + } + else + { + // TODO(doyle): Die out of memory + DQN_ASSERT(DQN_INVALID_CODE_PATH); + } + } + break; + } +} + +FILE_SCOPE bool WavefModelInit(DTRWavefModel *const obj, + DqnMemAPI memAPI = DqnMemAPI_DefaultUseCalloc(), + const i32 vertexInitCapacity = 100, const i32 faceInitCapacity = 100) { if (!obj) return false; bool initialised = false; - initialised |= DqnArray_Init(&obj->geometryArray, vertexInitCapacity); - initialised |= DqnArray_Init(&obj->textureArray, vertexInitCapacity); - initialised |= DqnArray_Init(&obj->normalArray, vertexInitCapacity); - initialised |= DqnArray_Init(&obj->faces, faceInitCapacity); + initialised |= DqnArray_Init(&obj->geometryArray, vertexInitCapacity, memAPI); + initialised |= DqnArray_Init(&obj->textureArray, vertexInitCapacity, memAPI); + initialised |= DqnArray_Init(&obj->normalArray, vertexInitCapacity, memAPI); + initialised |= DqnArray_Init(&obj->faces, faceInitCapacity, memAPI); if (!initialised) { @@ -40,7 +140,8 @@ FILE_SCOPE bool WavefModelInit(DTRWavefModel *const obj, const i32 vertexInitCap return initialised; } -FILE_SCOPE inline DTRWavefModelFace WavefModelFaceInit(i32 capacity = 3) +FILE_SCOPE inline DTRWavefModelFace +WavefModelFaceInit(i32 capacity = 3, DqnMemAPI memAPI = DqnMemAPI_DefaultUseCalloc()) { DTRWavefModelFace result = {}; DQN_ASSERT(DqnArray_Init(&result.vertexIndexArray, capacity)); @@ -60,8 +161,8 @@ bool DTRAsset_WavefModelLoad(const PlatformAPI api, PlatformMemory *const memory return false; // TODO(doyle): Logging // TODO(doyle): Make arrays use given memory not malloc - DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack); - u8 *rawBytes = (u8 *)DqnMemStack_Push(&memory->transMemStack, file.size); + DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->tempStack); + u8 *rawBytes = (u8 *)DqnMemStack_Push(&memory->tempStack, file.size); size_t bytesRead = api.FileRead(&file, rawBytes, file.size); size_t fileSize = file.size; api.FileClose(&file); @@ -79,6 +180,10 @@ bool DTRAsset_WavefModelLoad(const PlatformAPI api, PlatformMemory *const memory WavefVertexType_Normal, }; + DqnMemAPI memAPI = {}; + memAPI.callback = AssetDqnArrayMemAPICallback; + memAPI.userContext = &memory->assetStack; + if (!WavefModelInit(obj)) { DqnMemStack_EndTempRegion(tmpMemRegion); @@ -223,6 +328,9 @@ bool DTRAsset_WavefModelLoad(const PlatformAPI api, PlatformMemory *const memory // so offset by -1 to make it zero-based indexes. i32 vertIndex = (i32)Dqn_StrToI64(numStartPtr, numLen) - 1; + // TODO(doyle): Does not supprot relative vertexes yet + DQN_ASSERT(vertIndex >= 0); + if (type == WavefVertexType_Geometric) { DQN_ASSERT(DqnArray_Push(&face.vertexIndexArray, vertIndex)); @@ -288,7 +396,7 @@ bool DTRAsset_WavefModelLoad(const PlatformAPI api, PlatformMemory *const memory DQN_ASSERT(!obj->groupName[obj->groupNameIndex]); obj->groupName[obj->groupNameIndex++] = (char *)DqnMemStack_Push( - &memory->permMemStack, (nameLen + 1) * sizeof(char)); + &memory->mainStack, (nameLen + 1) * sizeof(char)); for (i32 i = 0; i < nameLen; i++) obj->groupName[obj->groupNameIndex - 1][i] = namePtr[i]; @@ -370,8 +478,8 @@ bool DTRAsset_FontToBitmapLoad(const PlatformAPI api, PlatformMemory *const memo if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly)) return false; // TODO(doyle): Logging - DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack); - u8 *fontBuf = (u8 *)DqnMemStack_Push(&memory->transMemStack, file.size); + DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->tempStack); + u8 *fontBuf = (u8 *)DqnMemStack_Push(&memory->tempStack, file.size); size_t bytesRead = api.FileRead(&file, fontBuf, file.size); api.FileClose(&file); if (bytesRead != file.size) @@ -393,7 +501,7 @@ bool DTRAsset_FontToBitmapLoad(const PlatformAPI api, PlatformMemory *const memo // Pack font data to bitmap //////////////////////////////////////////////////////////////////////////// loadedFont.bitmap = (u8 *)DqnMemStack_Push( - &memory->permMemStack, + &memory->mainStack, (size_t)(loadedFont.bitmapDim.w * loadedFont.bitmapDim.h)); stbtt_pack_context fontPackContext = {}; @@ -406,7 +514,7 @@ bool DTRAsset_FontToBitmapLoad(const PlatformAPI api, PlatformMemory *const memo (i32)((codepointRange.max + 1) - codepointRange.min); loadedFont.atlas = (stbtt_packedchar *)DqnMemStack_Push( - &memory->permMemStack, numCodepoints * sizeof(stbtt_packedchar)); + &memory->mainStack, numCodepoints * sizeof(stbtt_packedchar)); stbtt_PackFontRange(&fontPackContext, fontBuf, 0, STBTT_POINT_SIZE(sizeInPt), (i32)codepointRange.min, numCodepoints, loadedFont.atlas); @@ -456,13 +564,6 @@ bool DTRAsset_FontToBitmapLoad(const PlatformAPI api, PlatformMemory *const memo // TODO(doyle): Not threadsafe FILE_SCOPE DqnMemStack *globalSTBImageAllocator; -FILE_SCOPE void MemcopyInternal(u8 *dest, u8 *src, size_t numBytes) -{ - if (!dest || !src || numBytes == 0) return; - for (size_t i = 0; i < numBytes; i++) - dest[i] = src[i]; -} - FILE_SCOPE void *STBImageReallocSized(void *ptr, size_t oldSize, size_t newSize) { // TODO(doyle): Implement when needed. There's no easy way using our stack @@ -506,18 +607,18 @@ FILE_SCOPE void *STBImageMalloc(size_t size) // TODO(doyle): Uses malloc bool DTRAsset_BitmapLoad(const PlatformAPI api, DqnMemStack *const bitmapMemStack, - DqnMemStack *const transMemStack, DTRBitmap *bitmap, + DqnMemStack *const tempStack, DTRBitmap *bitmap, const char *const path) { - if (!bitmap || !bitmapMemStack || !transMemStack) return false; + if (!bitmap || !bitmapMemStack || !tempStack) return false; bool result = false; PlatformFile file = {}; if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly)) return result; - DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(transMemStack); - u8 *const rawData = (u8 *)DqnMemStack_Push (transMemStack, file.size); + DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack); + u8 *const rawData = (u8 *)DqnMemStack_Push (tempStack, file.size); size_t bytesRead = api.FileRead (&file, rawData, file.size); if (bytesRead != file.size) goto cleanup; diff --git a/src/DTRendererDebug.cpp b/src/DTRendererDebug.cpp index 2754958..ac6066a 100644 --- a/src/DTRendererDebug.cpp +++ b/src/DTRendererDebug.cpp @@ -46,7 +46,7 @@ void DTRDebug_TestWavefFaceAndVertexParser(DTRWavefModel *const obj) } } -void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *const transMemStack) +void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *const tempStack) { if (DTR_DEBUG) { @@ -64,10 +64,10 @@ void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *cons } } - DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(transMemStack); + DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack); size_t bufSize = DQN_MEGABYTE(16); - char *bufString = (char *)DqnMemStack_Push(transMemStack, bufSize); + char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize); char *bufPtr = bufString; for (i32 i = 0; i < renderBuffer->width * renderBuffer->height; i++) { @@ -149,6 +149,7 @@ FILE_SCOPE void PushMemStackText(const char *const name, const DqnMemStack *cons i32 numBlocks = 0; DqnMemStackBlock *blockPtr = stack->block; + size_t freeSizeOfCurrBlock = (blockPtr) ? blockPtr->size - blockPtr->used : 0; while (blockPtr) { totalUsed += blockPtr->used; @@ -159,7 +160,7 @@ FILE_SCOPE void PushMemStackText(const char *const name, const DqnMemStack *cons size_t totalUsedKb = totalUsed / 1024; size_t totalSizeKb = totalSize / 1024; - size_t totalWastedKb = totalWasted / 1024; + size_t totalWastedKb = (totalSize - totalUsed - freeSizeOfCurrBlock) / 1024; char str[128] = {}; Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld: wasted: %_$lld", name, numBlocks, @@ -194,8 +195,9 @@ void DTRDebug_Update(DTRState *const state, // memory { - PushMemStackText("PermBuffer", &memory->permMemStack); - PushMemStackText("TransBuffer", &memory->transMemStack); + PushMemStackText("MainStack", &memory->mainStack); + PushMemStackText("TempStack", &memory->tempStack); + PushMemStackText("AssetStack", &memory->assetStack); } DTRDebug_PushText("Mouse: %d, %d", input->mouse.x, input->mouse.y); diff --git a/src/DTRendererPlatform.h b/src/DTRendererPlatform.h index c2cd850..5be109d 100644 --- a/src/DTRendererPlatform.h +++ b/src/DTRendererPlatform.h @@ -128,8 +128,9 @@ typedef struct PlatformInput typedef struct PlatformMemory { - DqnMemStack permMemStack; - DqnMemStack transMemStack; + DqnMemStack mainStack; + DqnMemStack tempStack; + DqnMemStack assetStack; bool isInit; void *context; } PlatformMemory; diff --git a/src/Win32DTRenderer.cpp b/src/Win32DTRenderer.cpp index 1b59683..1f1ffbf 100644 --- a/src/Win32DTRenderer.cpp +++ b/src/Win32DTRenderer.cpp @@ -273,21 +273,21 @@ FILE_SCOPE void Win32HandleMenuMessages(HWND window, MSG msg, case Win32Menu_FileFlushMemory: { - DqnMemStack permMemStack = globalPlatformMemory.permMemStack; - DqnMemStack transMemStack = globalPlatformMemory.transMemStack; - while (permMemStack.block->prevBlock) - DqnMemStack_FreeLastBlock(&permMemStack); + DqnMemStack mainStack = globalPlatformMemory.mainStack; + DqnMemStack tempStack = globalPlatformMemory.tempStack; + while (mainStack.block->prevBlock) + DqnMemStack_FreeLastBlock(&mainStack); - while (transMemStack.block->prevBlock) - DqnMemStack_FreeLastBlock(&transMemStack); + while (tempStack.block->prevBlock) + DqnMemStack_FreeLastBlock(&tempStack); - DqnMemStack_ClearCurrBlock(&transMemStack, true); - DqnMemStack_ClearCurrBlock(&permMemStack, true); + DqnMemStack_ClearCurrBlock(&tempStack, true); + DqnMemStack_ClearCurrBlock(&mainStack, true); PlatformMemory empty = {}; globalPlatformMemory = empty; - globalPlatformMemory.permMemStack = permMemStack; - globalPlatformMemory.transMemStack = transMemStack; + globalPlatformMemory.mainStack = mainStack; + globalPlatformMemory.tempStack = tempStack; } break; @@ -546,8 +546,10 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, //////////////////////////////////////////////////////////////////////////// // Platform Data Pre-amble //////////////////////////////////////////////////////////////////////////// - DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.permMemStack, DQN_MEGABYTE(4), true, 4) && - DqnMemStack_Init(&globalPlatformMemory.transMemStack, DQN_MEGABYTE(4), true, 4)); + DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) && + DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) && + DqnMemStack_Init(&globalPlatformMemory.assetStack, DQN_MEGABYTE(4), true, 4) + ); PlatformAPI platformAPI = {}; platformAPI.FileOpen = Platform_FileOpen; diff --git a/src/dqn.h b/src/dqn.h index 8ecf064..07677a4 100644 --- a/src/dqn.h +++ b/src/dqn.h @@ -96,24 +96,18 @@ DQN_FILE_SCOPE void DqnMem_Free (void *memory); // BeginTempRegion and EndTempRegion functions. Specifically freeing // individual items is typically not generalisable in this scheme. -typedef struct DqnMemStackBlock -{ - u8 *memory; - size_t used; - size_t size; - - DqnMemStackBlock *prevBlock; -} DqnMemStackBlock; - enum DqnMemStackFlag { DqnMemStackFlag_IsNotExpandable = (1 << 0), DqnMemStackFlag_IsFixedMemoryFromUser = (1 << 1), // NOTE(doyle): Required to indicate we CAN'T free this memory when free is called. }; +//////////////////////////////////////////////////////////////////////////////// +// Advanced API Structs +//////////////////////////////////////////////////////////////////////////////// typedef struct DqnMemStack { - DqnMemStackBlock *block; + struct DqnMemStackBlock *block; u32 flags; i32 tempStackCount; @@ -122,8 +116,8 @@ typedef struct DqnMemStack typedef struct DqnTempMemStack { - DqnMemStack *stack; - DqnMemStackBlock *startingBlock; + DqnMemStack *stack; + struct DqnMemStackBlock *startingBlock; size_t used; } DqnTempMemStack; @@ -132,12 +126,12 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem (DqnMemStack *const stack, u8 * DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space DQN_FILE_SCOPE bool DqnMemStack_Init (DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out -DQN_FILE_SCOPE void *DqnMemStack_Push (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails -DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack -DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack -DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong +DQN_FILE_SCOPE void *DqnMemStack_Push (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails. +DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack. +DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack. +DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong, calls DqnMem_Free(). DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block. -DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0 +DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0. // TempMemStack is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original stack. // Upon EndTempRegion() the original stack will free any additional blocks it allocated during the temp region and revert to the original @@ -147,7 +141,20 @@ DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const DQN_FILE_SCOPE DqnTempMemStack DqnMemStack_BeginTempRegion(DqnMemStack *const stack); DQN_FILE_SCOPE void DqnMemStack_EndTempRegion (DqnTempMemStack tempstack); +//////////////////////////////////////////////////////////////////////////////// // (OPTIONAL) DqnMemStack Advanced API +// Blocks are freely modifiable if you want fine grained control. Size value and +// memory ptr should _NOT_ be modified directly, only indirectly through the +// regular API. +typedef struct DqnMemStackBlock +{ + u8 *memory; + size_t size; + size_t used; + + DqnMemStackBlock *prevBlock; +} DqnMemStackBlock; + // This is useful for forcing a new block to be used. AllocateCompatibleBlock // will fail if the supplied stack has flags set such that the stack is not // allowed to have new blocks.