From ad14d6d82219bcc9db024f10ba1057f88ad1dee6 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Sun, 27 Nov 2016 17:26:23 +1100 Subject: [PATCH] Introduce temp memory to free memory leaks --- src/AssetManager.c | 35 +++--- src/Asteroid.c | 30 ++--- src/Audio.c | 4 +- src/MemoryArena.c | 29 ++++- src/Platform.c | 2 +- src/Renderer.c | 12 +- src/UserInterface.c | 166 +++------------------------- src/dengine.c | 2 +- src/include/Dengine/AssetManager.h | 5 +- src/include/Dengine/MemoryArena.h | 11 ++ src/include/Dengine/UserInterface.h | 24 ---- 11 files changed, 104 insertions(+), 216 deletions(-) diff --git a/src/AssetManager.c b/src/AssetManager.c index cc40f38..17783f2 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -980,11 +980,15 @@ typedef struct GlyphBitmap i32 codepoint; } GlyphBitmap; -const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, - const char *filePath) +const i32 asset_loadTTFont(AssetManager *assetManager, + MemoryArena_ *persistentArena, + MemoryArena_ *transientArena, const char *filePath) { + TempMemory tempRegion = memory_begin_temporary_region(transientArena); + PlatformFileRead fontFileRead = {0}; - i32 result = platform_readFileToBuffer(arena, filePath, &fontFileRead); + i32 result = + platform_readFileToBuffer(transientArena, filePath, &fontFileRead); if (result) return result; stbtt_fontinfo fontInfo = {0}; @@ -1002,7 +1006,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, const i32 numGlyphs = CAST(i32)(codepointRange.y - codepointRange.x); GlyphBitmap *glyphBitmaps = - memory_pushBytes(arena, numGlyphs * sizeof(GlyphBitmap)); + memory_pushBytes(transientArena, numGlyphs * sizeof(GlyphBitmap)); v2 largestGlyphDimension = V2(0, 0); const f32 targetFontHeight = 15.0f; @@ -1018,7 +1022,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, font->metrics = CAST(FontMetrics){ascent, descent, lineGap}; font->charMetrics = - memory_pushBytes(arena, numGlyphs * sizeof(CharMetrics)); + memory_pushBytes(persistentArena, numGlyphs * sizeof(CharMetrics)); /* ************************************************************ @@ -1038,7 +1042,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, u8 *source = monoBitmap; u32 *colorBitmap = - memory_pushBytes(arena, width * height * sizeof(u32)); + memory_pushBytes(transientArena, width * height * sizeof(u32)); u32 *dest = colorBitmap; // NOTE(doyle): STB generates 1 byte per pixel bitmaps, we use 4bpp, so @@ -1114,7 +1118,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, #endif i32 bitmapSize = SQUARED(TARGET_TEXTURE_SIZE) * TARGET_BYTES_PER_PIXEL; - u32 *fontBitmap = memory_pushBytes(arena, bitmapSize * sizeof(u32)); + u32 *fontBitmap = + memory_pushBytes(transientArena, bitmapSize * sizeof(u32)); const i32 pitch = MAX_TEXTURE_SIZE * TARGET_BYTES_PER_PIXEL; // Check value to determine when a row of glyphs is completely printed @@ -1131,8 +1136,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, char charToEncode = CAST(char)codepointRange.x; i32 numSubTex = numGlyphs; - TexAtlas *fontAtlas = - asset_getFreeTexAtlasSlot(assetManager, arena, "font", numSubTex); + TexAtlas *fontAtlas = asset_getFreeTexAtlasSlot( + assetManager, persistentArena, "font", numSubTex); /* ********************************************************* @@ -1159,7 +1164,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, // all ascii characters, charToEncode represents the character // 1:1 const char key[2] = {charToEncode, 0}; - SubTexture *subTex = getFreeAtlasSubTexSlot(fontAtlas, arena, key); + SubTexture *subTex = + getFreeAtlasSubTexSlot(fontAtlas, persistentArena, key); subTex->rect = CAST(Rect){origin, font->maxSize}; charToEncode++; } @@ -1213,7 +1219,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, * Generate and store font bitmap to assets ******************************************* */ - Texture *tex = asset_getFreeTexSlot(assetManager, arena, "font"); + Texture *tex = asset_getFreeTexSlot(assetManager, persistentArena, "font"); *tex = texture_gen(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4, CAST(u8 *) fontBitmap); @@ -1238,14 +1244,9 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, i32 glyphBitmapSizeInBytes = CAST(i32) glyphBitmaps[i].dimensions.w * CAST(i32) glyphBitmaps[i].dimensions.h * sizeof(u32); - // TODO(doyle): Mem free - // PLATFORM_MEM_FREE(arena, glyphBitmaps[i].pixels, glyphBitmapSizeInBytes); } - // TODO(doyle): Mem free - // PLATFORM_MEM_FREE(arena, glyphBitmaps, numGlyphs * sizeof(GlyphBitmap)); - platform_closeFileRead(arena, &fontFileRead); - + memory_end_temporary_region(tempRegion); return 0; } diff --git a/src/Asteroid.c b/src/Asteroid.c index f03681d..5d8c1d6 100644 --- a/src/Asteroid.c +++ b/src/Asteroid.c @@ -27,8 +27,9 @@ void initAssetManager(GameState *state) Texture *tex = asset_getFreeTexSlot(assetManager, arena, "nullTex"); *tex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap)); - i32 result = asset_loadTTFont(assetManager, arena, - "C:/Windows/Fonts/Arialbd.ttf"); + i32 result = + asset_loadTTFont(assetManager, arena, &state->transientArena, + "C:/Windows/Fonts/Arialbd.ttf"); } { // Init shaders assets @@ -997,20 +998,23 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, Renderer *renderer = &state->renderer; InputBuffer *inputBuffer = &state->input; + renderer_rect(renderer, world->camera, V2(0, 0), renderer->size, + V2(0, 0), 0, NULL, V4(0, 0, 0, 0.5f), + renderflag_no_texture); + + v2 titleP = V2(20, renderer->size.h - 100); + renderer_staticString(renderer, transientArena, &assetManager->font, + "Asteroids", titleP, V2(0, 0), 0, V4(1, 0, 0, 1), + 0); + userInterface_beginState(uiState); - WindowState window = {0}; - window.id = userInterface_generateId(uiState); + Rect buttonRect = {V2(20, 20), V2(40, 40)}; - Rect windowRect = {0}; - windowRect.min = V2(200, 200); - windowRect.max = V2(500, 500); - - window.rect = windowRect; - -#if 0 - userInterface_window(uiState, transientArena, assetManager, renderer, - &assetManager->font, *inputBuffer, &window); +#if 1 + userInterface_button(uiState, transientArena, assetManager, renderer, + &assetManager->font, *inputBuffer, 0, buttonRect, + "test button"); #endif userInterface_endState(uiState, inputBuffer); diff --git a/src/Audio.c b/src/Audio.c index 65382fe..76f2f98 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -272,7 +272,7 @@ const i32 audio_playVorbis(MemoryArena_ *arena, AudioManager *audioManager, AudioRenderer *audioRenderer, AudioVorbis *vorbis, i32 numPlays) { - if(vorbis) return -1; + if (vorbis == NULL) return -1; i32 result = initRendererForPlayback(arena, audioManager, audioRenderer, vorbis, numPlays); @@ -304,7 +304,7 @@ const i32 audio_streamPlayVorbis(MemoryArena_ *arena, AudioManager *audioManager // TODO(doyle): Streaming leaks memory, we don't free the "copy audio" ASSERT(INVALID_CODE_PATH); - if(vorbis) return -1; + if (vorbis == NULL) return -1; i32 result = initRendererForPlayback(arena, audioManager, audioRenderer, vorbis, numPlays); diff --git a/src/MemoryArena.c b/src/MemoryArena.c index c498a7d..74d7fe1 100644 --- a/src/MemoryArena.c +++ b/src/MemoryArena.c @@ -2,7 +2,30 @@ void memory_arenaInit(MemoryArena_ *arena, void *base, size_t size) { - arena->size = size; - arena->used = 0; - arena->base = CAST(u8 *)base; + arena->size = size; + arena->used = 0; + arena->base = CAST(u8 *) base; + arena->tempMemoryCount = 0; +} + +TempMemory memory_begin_temporary_region(MemoryArena_ *arena) +{ + TempMemory result = {0}; + result.arena = arena; + result.used = arena->used; + + arena->tempMemoryCount++; + + return result; +} + +void memory_end_temporary_region(TempMemory tempMemory) +{ + MemoryArena_ *arena = tempMemory.arena; + ASSERT(arena->used > tempMemory.used) + + arena->used = tempMemory.used; + ASSERT(arena->tempMemoryCount > 0) + + arena->tempMemoryCount--; } diff --git a/src/Platform.c b/src/Platform.c index ce85ba2..6d05f8a 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -28,6 +28,7 @@ void *platform_memoryAlloc(MemoryArena_ *arena, size_t numBytes) return result; } +// TODO(doyle): If we use arena temporary memory this is not necessary void platform_closeFileRead(MemoryArena_ *arena, PlatformFileRead *file) { // TODO(doyle): Mem free @@ -178,4 +179,3 @@ b32 platform_queryKey(KeyState *key, enum ReadKeyType readType, return FALSE; } - diff --git a/src/Renderer.c b/src/Renderer.c index b697a6e..158b2d8 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -424,7 +424,11 @@ void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size, v2 posInCameraSpace = v2_sub(pos, camera.min); RenderTex emptyRenderTex = {0}; - if (!renderTex) renderTex = &emptyRenderTex; + if (!renderTex) + { + renderTex = &emptyRenderTex; + ASSERT(common_isSet(flags, renderflag_no_texture)); + } RenderQuad quad = createRenderQuad(renderer, posInCameraSpace, size, pivotPoint, rotate, *renderTex); @@ -496,7 +500,11 @@ void renderer_polygon(Renderer *const renderer, Rect camera, // TODO(doyle): Do something with render texture RenderTex emptyRenderTex = {0}; - if (!renderTex) renderTex = &emptyRenderTex; + if (!renderTex) + { + renderTex = &emptyRenderTex; + ASSERT(common_isSet(flags, renderflag_no_texture)); + } v2 triangulationBaseP = polygonPoints[0]; RenderVertex triangulationBaseVertex = {0}; diff --git a/src/UserInterface.c b/src/UserInterface.c index 38e75a6..22de67a 100644 --- a/src/UserInterface.c +++ b/src/UserInterface.c @@ -37,15 +37,7 @@ i32 userInterface_button(UiState *const uiState, MemoryArena_ *const arena, if (math_pointInRect(rect, input.mouseP)) { uiState->hotItem = id; - - // NOTE(doyle): UI windows are drawn first, they steal focus on mouse - // click since window logic is paired with the window rendering. If - // a UI element resides over our mouse, we allow the element to override - // the windows focus - // TODO(doyle): Make a window list to iterate over window ids - if (uiState->activeItem == uiState->statWindow.id || - uiState->activeItem == uiState->debugWindow.id || - uiState->activeItem == 0) + if (uiState->activeItem == 0) { if (common_isSet(input.keys[keycode_mouseLeft].flags, keystateflag_ended_down)) @@ -56,8 +48,6 @@ i32 userInterface_button(UiState *const uiState, MemoryArena_ *const arena, } - RenderTex renderTex = renderer_createNullRenderTex(assetManager); - #if 0 // Draw shadow renderer_staticRect(renderer, v2_add(V2(1, 1), rect.min), rect.size, @@ -65,23 +55,23 @@ i32 userInterface_button(UiState *const uiState, MemoryArena_ *const arena, #endif v2 buttonOffset = V2(0, 0); - v4 buttonColor = {0}; + v4 buttonColor = V4(1, 1, 1, 1); if (uiState->hotItem == id) { if (uiState->activeItem == id) { buttonOffset = V2(1, 1); - buttonColor = V4(1, 1, 1, 1); + buttonColor = V4(1.0f, 0, 0, 1); } else { // TODO(doyle): Optional add effect on button hover - buttonColor = V4(1, 1, 1, 1); + buttonColor = V4(1.0f, 0, 0, 1); } } else { - buttonColor = V4(0.5f, 0.5f, 0.5f, 1); + buttonColor = V4(1.0f, 0, 0, 1); } /* If no widget has keyboard focus, take it */ @@ -94,12 +84,12 @@ i32 userInterface_button(UiState *const uiState, MemoryArena_ *const arena, // Draw outline renderer_staticRect(renderer, v2_add(V2(-2, -2), v2_add(buttonOffset, rect.min)), - v2_add(V2(4, 4), rect.max), V2(0, 0), 0, &renderTex, - buttonColor, 0); + v2_add(V2(4, 4), rect.max), V2(0, 0), 0, NULL, + buttonColor, renderflag_no_texture); } renderer_staticRect(renderer, v2_add(buttonOffset, rect.min), rect.max, - V2(0, 0), 0, &renderTex, buttonColor, 0); + V2(0, 0), 0, NULL, buttonColor, renderflag_no_texture); if (label) { @@ -172,9 +162,7 @@ i32 userInterface_scrollbar(UiState *const uiState, if (math_pointInRect(scrollBarRect, input.mouseP)) { uiState->hotItem = id; - if (uiState->activeItem == uiState->statWindow.id || - uiState->activeItem == uiState->debugWindow.id || - uiState->activeItem == 0) + if (uiState->activeItem == 0) { if (common_isSet(input.keys[keycode_mouseLeft].flags, keystateflag_ended_down)) @@ -288,9 +276,7 @@ i32 userInterface_textField(UiState *const uiState, MemoryArena_ *const arena, if (math_pointInRect(rect, input.mouseP)) { uiState->hotItem = id; - if (uiState->activeItem == uiState->statWindow.id || - uiState->activeItem == uiState->debugWindow.id || - uiState->activeItem == 0) + if (uiState->activeItem == 0) { if (common_isSet(input.keys[keycode_mouseLeft].flags, keystateflag_ended_down)) @@ -304,29 +290,28 @@ i32 userInterface_textField(UiState *const uiState, MemoryArena_ *const arena, if (uiState->kbdItem == 0) uiState->kbdItem = id; - RenderTex renderTex = renderer_createNullRenderTex(assetManager); /* If we have keyboard focus, show it */ if (uiState->kbdItem == id) { // Draw outline renderer_staticRect(renderer, v2_add(V2(-2, -2), rect.min), v2_add(V2(4, 4), rect.max), V2(0, 0), 0, - &renderTex, V4(1.0f, 0, 0, 1), 0); + NULL, V4(1.0f, 0, 0, 1), 0); } // Render text field - renderer_staticRect(renderer, rect.min, rect.max, V2(0, 0), 0, - &renderTex, V4(0.75f, 0.5f, 0.5f, 1), 0); + renderer_staticRect(renderer, rect.min, rect.max, V2(0, 0), 0, NULL, + V4(0.75f, 0.5f, 0.5f, 1), 0); if (uiState->activeItem == id || uiState->hotItem == id) { renderer_staticRect(renderer, rect.min, rect.max, V2(0, 0), 0, - &renderTex, V4(0.75f, 0.75f, 0.0f, 1), 0); + NULL, V4(0.75f, 0.75f, 0.0f, 1), 0); } else { renderer_staticRect(renderer, rect.min, rect.max, V2(0, 0), 0, - &renderTex, V4(0.5f, 0.5f, 0.5f, 1), 0); + NULL, V4(0.5f, 0.5f, 0.5f, 1), 0); } v2 strPos = rect.min; @@ -377,124 +362,3 @@ i32 userInterface_textField(UiState *const uiState, MemoryArena_ *const arena, if (changed) return id; return 0; } - -i32 userInterface_window(UiState *const uiState, MemoryArena_ *const arena, - AssetManager *const assetManager, - Renderer *const renderer, Font *const font, - const InputBuffer input, WindowState *window) -{ - if (math_pointInRect(window->rect, input.mouseP)) - { - uiState->hotItem = window->id; - if (uiState->activeItem == 0 && - common_isSet(input.keys[keycode_mouseLeft].flags, - keystateflag_ended_down)) - uiState->activeItem = window->id; - } - - Rect rect = window->rect; - RenderTex nullRenderTex = renderer_createNullRenderTex(assetManager); - renderer_staticRect(renderer, rect.min, rect.max, V2(0, 0), 0, - &nullRenderTex, V4(0.25f, 0.25f, 0.5f, 0.5f), 0); - - v2 menuTitleP = v2_add(rect.min, V2(0, rect.max.h - 10)); - renderer_staticString(renderer, arena, font, window->title, menuTitleP, - V2(0, 0), 0, V4(0, 0, 0, 1), 0); - - /* Draw window elements */ - i32 firstActiveChildId = -1; - for (i32 i = 0; i < window->numChildUiItems; i++) - { - UiItem *childUi = &window->childUiItems[i]; - - // TODO(doyle): Redundant? If we can only have 1 active child at a time - // What about overlapping elements? - i32 getChildActiveState = -1; - switch(childUi->type) - { - case uitype_button: - // TODO(doyle): Bug in font rendering once button reaches 700-800+ - // pixels - getChildActiveState = userInterface_button( - uiState, arena, assetManager, renderer, font, input, - childUi->id, childUi->rect, childUi->label); - break; - - case uitype_scrollbar: - getChildActiveState = userInterface_scrollbar( - uiState, assetManager, renderer, input, childUi->id, - childUi->rect, &childUi->value, childUi->maxValue); - break; - - case uitype_textField: - getChildActiveState = userInterface_textField( - uiState, arena, assetManager, renderer, font, input, - childUi->id, childUi->rect, childUi->string); - break; - - default: - DEBUG_LOG( - "userInterface_window() warning: Enum uitype unrecognised"); - break; - } - - // NOTE(doyle): Capture only the first active id, but keep loop going to - // render the rest of the window ui - if (firstActiveChildId == -1 && getChildActiveState > 0) - firstActiveChildId = getChildActiveState; - } - - if (firstActiveChildId != -1) - return firstActiveChildId; - - // NOTE(doyle): activeItem captures mouse click within the UI bounds, but if - // the user drags the mouse outside the bounds quicker than the game updates - // then we use a second flag which only "unclicks" when the mouse is let go - if (uiState->activeItem == window->id) window->windowHeld = TRUE; - - if (window->windowHeld) - { - if (!common_isSet(input.keys[keycode_mouseLeft].flags, - keystateflag_ended_down)) - { - window->windowHeld = FALSE; - window->prevFrameWindowHeld = FALSE; - } - } - - if (window->windowHeld) - { - // NOTE(doyle): If this is the first window click we don't process - // movement and store the current position to delta from next cycle - if (window->prevFrameWindowHeld) - { - // NOTE(doyle): Window clicked and held - v2 deltaP = v2_sub(input.mouseP, window->prevMouseP); - - for (i32 i = 0; i < window->numChildUiItems; i++) - { - UiItem *childUi = &window->childUiItems[i]; - childUi->rect.min = v2_add(deltaP, childUi->rect.min); - } - - DEBUG_PUSH_VAR("Delta Pos %4.2f, %4.2f", deltaP, "v2"); - window->rect.min = v2_add(deltaP, window->rect.min); - } - else - { - window->prevFrameWindowHeld = TRUE; - } - - window->prevMouseP = input.mouseP; - } - - if (!common_isSet(input.keys[keycode_mouseLeft].flags, - keystateflag_ended_down) && - uiState->hotItem == window->id && uiState->activeItem == window->id) - { - return window->id; - } - - return 0; -} - diff --git a/src/dengine.c b/src/dengine.c index 016183e..905f732 100644 --- a/src/dengine.c +++ b/src/dengine.c @@ -165,7 +165,7 @@ i32 main(void) */ Memory memory = {0}; MemoryIndex persistentSize = MEGABYTES(32); - MemoryIndex transientSize = MEGABYTES(32); + MemoryIndex transientSize = MEGABYTES(64); memory.persistentSize = persistentSize; memory.persistent = PLATFORM_MEM_ALLOC_(NULL, persistentSize, u8); diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h index 193a7a9..f7938a5 100644 --- a/src/include/Dengine/AssetManager.h +++ b/src/include/Dengine/AssetManager.h @@ -78,8 +78,9 @@ const i32 asset_loadShaderFiles(AssetManager *assetManager, MemoryArena_ *arena, const char *const fragmentPath, const enum ShaderList type); -const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena_ *arena, - const char *filePath); +const i32 asset_loadTTFont(AssetManager *assetManager, + MemoryArena_ *persistentArena, + MemoryArena_ *transientArena, const char *filePath); const v2 asset_stringDimInPixels(const Font *const font, const char *const string); diff --git a/src/include/Dengine/MemoryArena.h b/src/include/Dengine/MemoryArena.h index 2e16a38..ec06b5f 100644 --- a/src/include/Dengine/MemoryArena.h +++ b/src/include/Dengine/MemoryArena.h @@ -8,6 +8,8 @@ typedef struct MemoryArena MemoryIndex size; MemoryIndex used; u8 *base; + + i32 tempMemoryCount; } MemoryArena_; typedef struct Memory @@ -21,6 +23,15 @@ typedef struct Memory b32 init; } Memory; +typedef struct TempMemory +{ + MemoryArena_ *arena; + MemoryIndex used; +} TempMemory; + +TempMemory memory_begin_temporary_region(MemoryArena_ *arena); +void memory_end_temporary_region(TempMemory tempMemory); + #define MEMORY_PUSH_STRUCT(arena, type) (type *)memory_pushBytes(arena, sizeof(type)) #define MEMORY_PUSH_ARRAY(arena, count, type) (type *)memory_pushBytes(arena, (count)*sizeof(type)) inline void *memory_pushBytes(MemoryArena_ *arena, MemoryIndex size) diff --git a/src/include/Dengine/UserInterface.h b/src/include/Dengine/UserInterface.h index 3ef16ee..a465f80 100644 --- a/src/include/Dengine/UserInterface.h +++ b/src/include/Dengine/UserInterface.h @@ -35,22 +35,6 @@ typedef struct UiItem char string[80]; } UiItem; -typedef struct WindowState -{ - char title[64]; - i32 id; - - UiItem childUiItems[16]; - i32 numChildUiItems; - - Rect rect; - // TODO(doyle): Store this in the input data not window? - v2 prevMouseP; - - b32 prevFrameWindowHeld; - b32 windowHeld; -} WindowState; - typedef struct UiState { i32 uniqueId; @@ -66,9 +50,6 @@ typedef struct UiState enum KeyCode keyEntered; enum KeyCode keyMod; enum KeyCode keyChar; - - WindowState statWindow; - WindowState debugWindow; } UiState; inline i32 userInterface_generateId(UiState *const uiState) @@ -97,9 +78,4 @@ i32 userInterface_scrollbar(UiState *const uiState, Renderer *const renderer, const InputBuffer input, const i32 id, const Rect scrollBarRect, i32 *const value, const i32 maxValue); - -i32 userInterface_window(UiState *const uiState, MemoryArena_ *const arena, - AssetManager *const assetManager, - Renderer *const renderer, Font *const font, - const InputBuffer input, WindowState *window); #endif