Draft impl. of malloc to memstack for obj loading

This commit is contained in:
Doyle Thai 2017-05-26 18:33:13 +10:00
parent 96ac39724d
commit 254d80749b
4 changed files with 185 additions and 38 deletions

View File

@ -89,18 +89,18 @@ FILE_SCOPE void AssetDqnArrayMemAPICallback(DqnMemAPICallbackInfo info, DqnMemAP
stack->block->used -= info.oldSize; 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 // Otherwise, not enough space or, allocation is not the last
// allocated, so can't expand inplace. // allocated, so can't expand inplace.
DqnMemStackBlock *newBlock = DqnMemStackBlock *newBlock =
DqnMemStack_AllocateCompatibleBlock(stack, info.newRequestSize); DqnMemStack_AllocateCompatibleBlock(stack, info.newRequestSize);
if (DqnMemStack_AttachBlock(stack, newBlock)) if (DqnMemStack_AttachBlock(stack, newBlock))
{ {
// 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.
void *newPtr = DqnMemStack_Push(stack, info.newRequestSize); void *newPtr = DqnMemStack_Push(stack, info.newRequestSize);
MemcopyInternal((u8 *)newPtr, (u8 *)info.oldMemPtr, info.oldSize); MemcopyInternal((u8 *)newPtr, (u8 *)info.oldMemPtr, info.oldSize);
@ -118,7 +118,7 @@ FILE_SCOPE void AssetDqnArrayMemAPICallback(DqnMemAPICallbackInfo info, DqnMemAP
FILE_SCOPE bool WavefModelInit(DTRWavefModel *const obj, FILE_SCOPE bool WavefModelInit(DTRWavefModel *const obj,
DqnMemAPI memAPI = DqnMemAPI_DefaultUseCalloc(), DqnMemAPI memAPI = DqnMemAPI_DefaultUseCalloc(),
const i32 vertexInitCapacity = 100, const i32 faceInitCapacity = 100) const i32 vertexInitCapacity = 1000, const i32 faceInitCapacity = 1000)
{ {
if (!obj) return false; if (!obj) return false;
@ -144,9 +144,9 @@ FILE_SCOPE inline DTRWavefModelFace
WavefModelFaceInit(i32 capacity = 3, DqnMemAPI memAPI = DqnMemAPI_DefaultUseCalloc()) WavefModelFaceInit(i32 capacity = 3, DqnMemAPI memAPI = DqnMemAPI_DefaultUseCalloc())
{ {
DTRWavefModelFace result = {}; DTRWavefModelFace result = {};
DQN_ASSERT(DqnArray_Init(&result.vertexIndexArray, capacity)); DQN_ASSERT(DqnArray_Init(&result.vertexIndexArray, capacity, memAPI));
DQN_ASSERT(DqnArray_Init(&result.textureIndexArray, capacity)); DQN_ASSERT(DqnArray_Init(&result.textureIndexArray, capacity, memAPI));
DQN_ASSERT(DqnArray_Init(&result.normalIndexArray, capacity)); DQN_ASSERT(DqnArray_Init(&result.normalIndexArray, capacity, memAPI));
return result; return result;
} }
@ -162,6 +162,8 @@ bool DTRAsset_WavefModelLoad(const PlatformAPI api, PlatformMemory *const memory
// TODO(doyle): Make arrays use given memory not malloc // TODO(doyle): Make arrays use given memory not malloc
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->tempStack); DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->tempStack);
DqnTempMemStack tmpAssetRegion = DqnMemStack_BeginTempRegion(&memory->assetStack);
u8 *rawBytes = (u8 *)DqnMemStack_Push(&memory->tempStack, file.size); u8 *rawBytes = (u8 *)DqnMemStack_Push(&memory->tempStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size); size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
size_t fileSize = file.size; size_t fileSize = file.size;
@ -184,7 +186,7 @@ bool DTRAsset_WavefModelLoad(const PlatformAPI api, PlatformMemory *const memory
memAPI.callback = AssetDqnArrayMemAPICallback; memAPI.callback = AssetDqnArrayMemAPICallback;
memAPI.userContext = &memory->assetStack; memAPI.userContext = &memory->assetStack;
if (!WavefModelInit(obj)) if (!WavefModelInit(obj, memAPI))
{ {
DqnMemStack_EndTempRegion(tmpMemRegion); DqnMemStack_EndTempRegion(tmpMemRegion);
return false; return false;
@ -307,7 +309,7 @@ bool DTRAsset_WavefModelLoad(const PlatformAPI api, PlatformMemory *const memory
while (scan && (*scan == ' ' || *scan == '\n')) scan++; while (scan && (*scan == ' ' || *scan == '\n')) scan++;
if (!scan) continue; if (!scan) continue;
DTRWavefModelFace face = WavefModelFaceInit(); DTRWavefModelFace face = WavefModelFaceInit(3, memAPI);
i32 numVertexesParsed = 0; i32 numVertexesParsed = 0;
bool moreVertexesToParse = true; bool moreVertexesToParse = true;
while (moreVertexesToParse) while (moreVertexesToParse)
@ -455,9 +457,121 @@ bool DTRAsset_WavefModelLoad(const PlatformAPI api, PlatformMemory *const memory
} }
} }
DqnMemStack_EndTempRegion(tmpMemRegion); ////////////////////////////////////////////////////////////////////////////
// Recompact Allocations
////////////////////////////////////////////////////////////////////////////
u8 *geometryPtr = (u8 *)obj->geometryArray.data;
u8 *texturePtr = (u8 *)obj->textureArray.data;
u8 *normalPtr = (u8 *)obj->normalArray.data;
size_t geometrySize = sizeof(obj->geometryArray.data[0]) * obj->geometryArray.count;
size_t textureSize = sizeof(obj->textureArray.data[0]) * obj->textureArray.count;
size_t normalSize = sizeof(obj->normalArray.data[0]) * obj->normalArray.count;
u8 *facePtr = (u8 *)obj->faces.data;
size_t faceSize = sizeof(obj->faces.data[0]) * obj->faces.count;
size_t totalModelSize = geometrySize + textureSize + normalSize + faceSize;
size_t vertIndexItemSize = sizeof(obj->faces.data[0].vertexIndexArray.data[0]);
size_t texIndexItemSize = sizeof(obj->faces.data[0].textureIndexArray.data[0]);
size_t normIndexItemSize = sizeof(obj->faces.data[0].normalIndexArray.data[0]);
{
for (i32 i = 0; i < obj->faces.count; i++)
{
DTRWavefModelFace *face = &obj->faces.data[i];
size_t vertIndexSize = face->vertexIndexArray.count * vertIndexItemSize;
size_t texIndexSize = face->textureIndexArray.count * texIndexItemSize;
size_t normIndexSize = face->normalIndexArray.count * normIndexItemSize;
totalModelSize += (vertIndexSize + texIndexSize + normIndexSize);
}
}
// IMPORTANT(doyle): We always allocate a new block, so each assets owns
// their own memory block.
DqnMemStackBlock *modelBlock =
DqnMemStack_AllocateCompatibleBlock(&memory->assetStack, totalModelSize);
if (modelBlock)
{
if (DqnMemStack_AttachBlock(&memory->assetStack, modelBlock))
{
u8 *newGeometryPtr = (u8 *)DqnMemStack_Push(&memory->assetStack, geometrySize);
u8 *newTexturePtr = (u8 *)DqnMemStack_Push(&memory->assetStack, textureSize);
u8 *newNormalPtr = (u8 *)DqnMemStack_Push(&memory->assetStack, normalSize);
u8 *newFacePtr = (u8 *)DqnMemStack_Push(&memory->assetStack, faceSize);
MemcopyInternal(newGeometryPtr, geometryPtr, geometrySize);
MemcopyInternal(newTexturePtr, texturePtr, textureSize);
MemcopyInternal(newNormalPtr, normalPtr, normalSize);
MemcopyInternal(newFacePtr, facePtr, faceSize);
obj->geometryArray.data = (DqnV4 *)newGeometryPtr;
obj->normalArray.data = (DqnV3 *)newNormalPtr;
obj->textureArray.data = (DqnV3 *)newTexturePtr;
obj->faces.data = (DTRWavefModelFace *)newFacePtr;
obj->geometryArray.capacity = obj->geometryArray.count;
obj->normalArray.capacity = obj->normalArray.count;
obj->textureArray.capacity = obj->textureArray.count;
obj->faces.capacity = obj->faces.count;
for (i32 i = 0; i < obj->faces.count; i++)
{
DTRWavefModelFace *face = &obj->faces.data[i];
size_t vertIndexSize = face->vertexIndexArray.count * vertIndexItemSize;
size_t texIndexSize = face->textureIndexArray.count * texIndexItemSize;
size_t normIndexSize = face->normalIndexArray.count * normIndexItemSize;
u8 *newVertIndexPtr = (u8 *)DqnMemStack_Push(&memory->assetStack, vertIndexSize);
u8 *newTexIndexPtr = (u8 *)DqnMemStack_Push(&memory->assetStack, texIndexSize);
u8 *newNormIndexPtr = (u8 *)DqnMemStack_Push(&memory->assetStack, normIndexSize);
MemcopyInternal(newVertIndexPtr, (u8 *)face->vertexIndexArray.data, vertIndexSize);
MemcopyInternal(newTexIndexPtr, (u8 *)face->textureIndexArray.data, texIndexSize);
MemcopyInternal(newNormIndexPtr, (u8 *)face->normalIndexArray.data, normIndexSize);
face->vertexIndexArray.data = (i32 *)newVertIndexPtr;
face->textureIndexArray.data = (i32 *)newTexIndexPtr;
face->normalIndexArray.data = (i32 *)newNormIndexPtr;
face->vertexIndexArray.capacity = face->vertexIndexArray.count;
face->textureIndexArray.capacity = face->textureIndexArray.count;
face->normalIndexArray.capacity = face->normalIndexArray.count;
}
// NOTE: Detach the block, because the stack is in a temp region.
// End the temp region and reattach the compact model block.
DqnMemStack_DetachBlock(&memory->assetStack, modelBlock);
}
else
{
// TODO(doyle): Stack can't attach block, i.e. invalid args or
// stack is configured to be nonexpandable
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
}
else
{
// TODO(doyle): Out of memory error
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
DqnMemStack_EndTempRegion(tmpMemRegion);
DqnMemStack_EndTempRegion(tmpAssetRegion);
DqnMemStack_ClearCurrBlock(&memory->assetStack, true);
if (modelBlock)
{
DqnMemStackBlock *firstBlock = memory->assetStack.block;
DqnMemStack_DetachBlock(&memory->assetStack, memory->assetStack.block);
DqnMemStack_AttachBlock(&memory->assetStack, modelBlock);
DqnMemStack_AttachBlock(&memory->assetStack, firstBlock);
return true; return true;
}
else
{
return false;
}
} }
bool DTRAsset_FontToBitmapLoad(const PlatformAPI api, PlatformMemory *const memory, bool DTRAsset_FontToBitmapLoad(const PlatformAPI api, PlatformMemory *const memory,
@ -605,7 +719,6 @@ FILE_SCOPE void *STBImageMalloc(size_t size)
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h" #include "external/stb_image.h"
// TODO(doyle): Uses malloc
bool DTRAsset_BitmapLoad(const PlatformAPI api, DqnMemStack *const bitmapMemStack, bool DTRAsset_BitmapLoad(const PlatformAPI api, DqnMemStack *const bitmapMemStack,
DqnMemStack *const tempStack, DTRBitmap *bitmap, DqnMemStack *const tempStack, DTRBitmap *bitmap,
const char *const path) const char *const path)

View File

@ -128,9 +128,15 @@ typedef struct PlatformInput
typedef struct PlatformMemory typedef struct PlatformMemory
{ {
union {
struct
{
DqnMemStack mainStack; DqnMemStack mainStack;
DqnMemStack tempStack; DqnMemStack tempStack;
DqnMemStack assetStack; DqnMemStack assetStack;
};
DqnMemStack stacks[3];
};
bool isInit; bool isInit;
void *context; void *context;
} PlatformMemory; } PlatformMemory;

View File

@ -273,20 +273,22 @@ FILE_SCOPE void Win32HandleMenuMessages(HWND window, MSG msg,
case Win32Menu_FileFlushMemory: case Win32Menu_FileFlushMemory:
{ {
for (i32 i = 0; i < DQN_ARRAY_COUNT(globalPlatformMemory.stacks); i++)
{
while (globalPlatformMemory.stacks[i].block->prevBlock)
DqnMemStack_FreeLastBlock(&globalPlatformMemory.stacks[i]);
DqnMemStack_ClearCurrBlock(&globalPlatformMemory.stacks[i], true);
}
DqnMemStack mainStack = globalPlatformMemory.mainStack; DqnMemStack mainStack = globalPlatformMemory.mainStack;
DqnMemStack assetStack = globalPlatformMemory.assetStack;
DqnMemStack tempStack = globalPlatformMemory.tempStack; DqnMemStack tempStack = globalPlatformMemory.tempStack;
while (mainStack.block->prevBlock)
DqnMemStack_FreeLastBlock(&mainStack);
while (tempStack.block->prevBlock)
DqnMemStack_FreeLastBlock(&tempStack);
DqnMemStack_ClearCurrBlock(&tempStack, true);
DqnMemStack_ClearCurrBlock(&mainStack, true);
PlatformMemory empty = {}; PlatformMemory empty = {};
globalPlatformMemory = empty; globalPlatformMemory = empty;
globalPlatformMemory.mainStack = mainStack; globalPlatformMemory.mainStack = mainStack;
globalPlatformMemory.assetStack = assetStack;
globalPlatformMemory.tempStack = tempStack; globalPlatformMemory.tempStack = tempStack;
} }
break; break;

View File

@ -160,6 +160,7 @@ typedef struct DqnMemStackBlock
// allowed to have new blocks. // allowed to have new blocks.
DQN_FILE_SCOPE DqnMemStackBlock *DqnMemStack_AllocateCompatibleBlock(const DqnMemStack *const stack, size_t size); DQN_FILE_SCOPE DqnMemStackBlock *DqnMemStack_AllocateCompatibleBlock(const DqnMemStack *const stack, size_t size);
DQN_FILE_SCOPE bool DqnMemStack_AttachBlock (DqnMemStack *const stack, DqnMemStackBlock *const newBlock); DQN_FILE_SCOPE bool DqnMemStack_AttachBlock (DqnMemStack *const stack, DqnMemStackBlock *const newBlock);
DQN_FILE_SCOPE bool DqnMemStack_DetachBlock (DqnMemStack *const stack, DqnMemStackBlock *const detachBlock);
// (IMPORTANT) Should only be used to free blocks that haven't been attached! // (IMPORTANT) Should only be used to free blocks that haven't been attached!
// Attached blocks should be freed using FreeStackBlock(). // Attached blocks should be freed using FreeStackBlock().
@ -1401,6 +1402,31 @@ DQN_FILE_SCOPE bool DqnMemStack_AttachBlock(DqnMemStack *const stack,
return true; return true;
} }
DQN_FILE_SCOPE bool DqnMemStack_DetachBlock(DqnMemStack *const stack,
DqnMemStackBlock *const detachBlock)
{
if (!stack || !detachBlock) return false;
if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser) return false;
if (stack->flags & DqnMemStackFlag_IsNotExpandable) return false;
DqnMemStackBlock **blockPtr = &stack->block;
while (*blockPtr && *blockPtr != detachBlock)
blockPtr = &((*blockPtr)->prevBlock);
if (*blockPtr)
{
*blockPtr = detachBlock->prevBlock;
detachBlock->prevBlock = NULL;
}
else
{
return false;
}
return true;
}
DQN_FILE_SCOPE void DqnMemStack_FreeBlock(DqnMemStackBlock *block) DQN_FILE_SCOPE void DqnMemStack_FreeBlock(DqnMemStackBlock *block)
{ {
if (!block) return; if (!block) return;