Introduce temp memory to free memory leaks

This commit is contained in:
Doyle Thai 2016-11-27 17:26:23 +11:00
parent 3729ddf164
commit ad14d6d822
11 changed files with 104 additions and 216 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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--;
}

View File

@ -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;
}

View File

@ -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};

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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