replace per-tick allocations in push_text with an arena/bump allocator

This commit is contained in:
wanp 2024-09-27 15:02:24 -03:00
parent 0481962859
commit 078e68387b
5 changed files with 101 additions and 26 deletions

View File

@ -37,13 +37,8 @@ static void title_tick(State *state) {
},
(Color) { 0, 0, 0, 255 }
);
push_text(
text_str,
(Vec2){ 0, 0 },
text_h,
(Color) { 255, 255, 255, 255 },
font
);
push_text(text_str, (Vec2){ 0, 0 }, text_h, (Color) { 255, 255, 255, 255 }, font);
free(text_str);
}

View File

@ -22,13 +22,7 @@ Matrix4 camera_look_at_matrix;
void render_queue_clear(void) {
/* this doesn't even _deserve_ a TODO */
/* if you're gonna remove it, this is also being done in main.c */
for (size_t i = 0; i < arrlenu(ctx.render_queue_2d); ++i) {
if (ctx.render_queue_2d[i].type == PRIMITIVE_2D_TEXT) {
SDL_free(ctx.render_queue_2d[i].text.text);
}
}
text_cache_reset_arena(&ctx.text_cache);
/* since i don't intend to free the queues, */
/* it's faster and simpler to just "start over" */

View File

@ -154,6 +154,8 @@ void text_cache_init(TextCache *cache);
void text_cache_deinit(TextCache *cache);
void text_cache_reset_arena(TextCache *cache);
/* vertex buffer */
VertexBuffer create_vertex_buffer(void);

View File

@ -11,6 +11,88 @@
#define ASCII_END 128
#define NUM_DISPLAY_ASCII ((ASCII_END - ASCII_START) + 1)
/* should be large enough that there's virtually never more than one block */
#define STRING_ARENA_BLOCK_SIZE 512000
typedef struct StringArenaBlock {
struct StringArenaBlock *next;
char *buffer;
size_t used;
} StringArenaBlock;
typedef struct StringArena {
StringArenaBlock *head;
StringArenaBlock *current_block;
char *ptr;
} StringArena;
static StringArena string_arena;
static void string_arena_init(StringArena *arena) {
arena->head = cmalloc(sizeof *arena->head);
arena->current_block = arena->head;
arena->ptr = arena->current_block->buffer;
arena->current_block->next = NULL;
arena->current_block->buffer = cmalloc(STRING_ARENA_BLOCK_SIZE);
arena->current_block->used = 0;
}
static void string_arena_deinit(StringArena *arena) {
StringArenaBlock *p = arena->head;
while (p != NULL) {
StringArenaBlock *block = p;
p = block->next; /* need to keep this before freeing */
SDL_free(block->buffer);
SDL_free(block);
}
}
static void string_arena_reset(StringArena *arena) {
arena->current_block = arena->head;
arena->current_block->used = 0;
arena->ptr = arena->current_block->buffer;
}
static char *string_arena_alloc(StringArena *arena, size_t size) {
/* will never fit! */
if (size > STRING_ARENA_BLOCK_SIZE) {
/* is there a more graceful way to handle this without risking some sort of horror? */
CRY("String arena allocation failure", "Tried to allocate a size larger than the block size");
die_abruptly();
}
/* won't fit, we need a new block first */
if (arena->current_block->used + size > STRING_ARENA_BLOCK_SIZE) {
log_info("String arena block size exceeded, moving on to the next...");
/* only allocate if there wasn't one ready to go already */
if (arena->current_block->next == NULL) {
log_info("Allocating string arena block...");
arena->current_block->next = cmalloc(sizeof *arena->head);
arena->current_block->next->next = NULL;
arena->current_block->next->buffer = cmalloc(STRING_ARENA_BLOCK_SIZE);
}
arena->current_block = arena->current_block->next;
arena->current_block->used = 0;
arena->ptr = arena->current_block->buffer;
}
char *chunk = arena->ptr;
arena->ptr += size;
arena->current_block->used += size * (sizeof *arena->ptr);
return chunk;
}
static FontData *text_load_font_data(const char *path, int height_px) {
FontData *font_data = ccalloc(1, sizeof *font_data);
@ -146,6 +228,7 @@ void render_text(const TextPrimitive *text) {
void text_cache_init(TextCache *cache) {
arrsetlen(cache->data, 0);
string_arena_init(&string_arena);
}
@ -155,6 +238,13 @@ void text_cache_deinit(TextCache *cache) {
}
arrfree(cache->data);
string_arena_deinit(&string_arena);
}
void text_cache_reset_arena(TextCache *cache) {
(void)cache;
string_arena_reset(&string_arena);
}
@ -162,8 +252,9 @@ void push_text(char *string, Vec2 position, int height_px, Color color, const ch
ensure_font_cache(font_path, height_px);
/* the original string might not be around by the time it's used, so copy it */
/* TODO: arena */
char *dup_string = SDL_strdup(string);
size_t str_length = SDL_strlen(string) + 1;
char *dup_string = string_arena_alloc(&string_arena, str_length);
SDL_strlcpy(dup_string, string, str_length);
TextPrimitive text = {
.color = color,

View File

@ -372,18 +372,11 @@ static void clean_up(void) {
*/
input_state_deinit(&ctx.game.input);
/* if you're gonna remove this, it's also being done in rendering.c */
for (size_t i = 0; i < arrlenu(ctx.render_queue_2d); ++i) {
if (ctx.render_queue_2d[i].type == PRIMITIVE_2D_TEXT) {
SDL_free(ctx.render_queue_2d[i].text.text);
}
}
arrfree(ctx.render_queue_2d);
text_cache_deinit(&ctx.text_cache);
textures_cache_deinit(&ctx.texture_cache);
arrfree(ctx.render_queue_2d);
PHYSFS_deinit();
SDL_Quit();
}