replace per-tick allocations in push_text with an arena/bump allocator
This commit is contained in:
		| @@ -37,13 +37,8 @@ static void title_tick(State *state) { | |||||||
|         }, |         }, | ||||||
|         (Color) { 0, 0, 0, 255 } |         (Color) { 0, 0, 0, 255 } | ||||||
|     ); |     ); | ||||||
|     push_text( |     push_text(text_str, (Vec2){ 0, 0 }, text_h, (Color) { 255, 255, 255, 255 }, font); | ||||||
|         text_str, |  | ||||||
|         (Vec2){ 0, 0 }, |  | ||||||
|         text_h, |  | ||||||
|         (Color) { 255, 255, 255, 255 }, |  | ||||||
|         font |  | ||||||
|     ); |  | ||||||
|     free(text_str); |     free(text_str); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,13 +22,7 @@ Matrix4 camera_look_at_matrix; | |||||||
|  |  | ||||||
|  |  | ||||||
| void render_queue_clear(void) { | void render_queue_clear(void) { | ||||||
|     /* this doesn't even _deserve_ a TODO */ |     text_cache_reset_arena(&ctx.text_cache); | ||||||
|     /* 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); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     /* since i don't intend to free the queues, */ |     /* since i don't intend to free the queues, */ | ||||||
|     /* it's faster and simpler to just "start over" */ |     /* it's faster and simpler to just "start over" */ | ||||||
|   | |||||||
| @@ -154,6 +154,8 @@ void text_cache_init(TextCache *cache); | |||||||
|  |  | ||||||
| void text_cache_deinit(TextCache *cache); | void text_cache_deinit(TextCache *cache); | ||||||
|  |  | ||||||
|  | void text_cache_reset_arena(TextCache *cache); | ||||||
|  |  | ||||||
| /* vertex buffer */ | /* vertex buffer */ | ||||||
|  |  | ||||||
| VertexBuffer create_vertex_buffer(void); | VertexBuffer create_vertex_buffer(void); | ||||||
|   | |||||||
| @@ -11,6 +11,88 @@ | |||||||
| #define ASCII_END 128 | #define ASCII_END 128 | ||||||
| #define NUM_DISPLAY_ASCII ((ASCII_END - ASCII_START) + 1) | #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) { | static FontData *text_load_font_data(const char *path, int height_px) { | ||||||
|     FontData *font_data = ccalloc(1, sizeof *font_data); |     FontData *font_data = ccalloc(1, sizeof *font_data); | ||||||
| @@ -146,6 +228,7 @@ void render_text(const TextPrimitive *text) { | |||||||
|  |  | ||||||
| void text_cache_init(TextCache *cache) { | void text_cache_init(TextCache *cache) { | ||||||
|     arrsetlen(cache->data, 0); |     arrsetlen(cache->data, 0); | ||||||
|  |     string_arena_init(&string_arena); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -155,6 +238,13 @@ void text_cache_deinit(TextCache *cache) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     arrfree(cache->data); |     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); |     ensure_font_cache(font_path, height_px); | ||||||
|  |  | ||||||
|     /* the original string might not be around by the time it's used, so copy it */ |     /* the original string might not be around by the time it's used, so copy it */ | ||||||
|     /* TODO: arena */ |     size_t str_length = SDL_strlen(string) + 1; | ||||||
|     char *dup_string = SDL_strdup(string); |     char *dup_string = string_arena_alloc(&string_arena, str_length); | ||||||
|  |     SDL_strlcpy(dup_string, string, str_length); | ||||||
|  |  | ||||||
|     TextPrimitive text = { |     TextPrimitive text = { | ||||||
|         .color = color, |         .color = color, | ||||||
|   | |||||||
| @@ -372,18 +372,11 @@ static void clean_up(void) { | |||||||
|     */ |     */ | ||||||
|  |  | ||||||
|     input_state_deinit(&ctx.game.input);     |     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); |     text_cache_deinit(&ctx.text_cache); | ||||||
|     textures_cache_deinit(&ctx.texture_cache); |     textures_cache_deinit(&ctx.texture_cache); | ||||||
|  |  | ||||||
|  |     arrfree(ctx.render_queue_2d); | ||||||
|  |  | ||||||
|     PHYSFS_deinit(); |     PHYSFS_deinit(); | ||||||
|     SDL_Quit(); |     SDL_Quit(); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user