use work system for sprite loading

This commit is contained in:
jacob 2024-06-21 14:27:35 -05:00
parent afea5ea512
commit 0b3e191bb2

View File

@ -35,10 +35,8 @@
* Loader cmd structs * Loader cmd structs
* ========================== */ * ========================== */
struct loader_cmd { struct load_cmd {
struct loader_cmd *next; struct load_cmd *next_free;
struct loader_cmd *next_free;
struct cache_node *cache_node; struct cache_node *cache_node;
struct sprite_tag tag; struct sprite_tag tag;
u8 tag_path_buff[512]; u8 tag_path_buff[512];
@ -129,16 +127,10 @@ GLOBAL struct {
/* Cache */ /* Cache */
struct cache cache; struct cache cache;
/* Loader threads */ /* Load cmds */
b32 loaders_shutdown; struct sys_mutex load_cmds_mutex;
struct sys_mutex loaders_mutex; struct arena load_cmds_arena;
struct sys_condition_variable loaders_cv; struct load_cmd *first_free_load_cmd;
struct arena loader_cmd_arena;
struct loader_cmd *first_free_loader_cmd;
struct loader_cmd *first_loader_cmd;
struct loader_cmd *last_loader_cmd;
u64 loader_threads_count;
struct sys_thread loader_threads[MAX_LOADER_THREADS];
/* Evictor thread */ /* Evictor thread */
struct atomic_u32 evictor_cycle; struct atomic_u32 evictor_cycle;
@ -216,7 +208,7 @@ INTERNAL struct image_rgba generate_purple_black_image(struct arena *arena, u32
* ========================== */ * ========================== */
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown); INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown);
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_loader_thread_entry_point, arg); INTERNAL WORK_TASK_FUNC_DEF(sprite_load_task, arg);
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg); INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg);
struct sprite_startup_receipt sprite_startup(struct renderer_startup_receipt *renderer_sr, struct sprite_startup_receipt sprite_startup(struct renderer_startup_receipt *renderer_sr,
@ -253,24 +245,12 @@ struct sprite_startup_receipt sprite_startup(struct renderer_startup_receipt *re
G.cache.buckets[i].rw_mutex = sys_rw_mutex_alloc(); G.cache.buckets[i].rw_mutex = sys_rw_mutex_alloc();
} }
G.loader_cmd_arena = arena_alloc(GIGABYTE(64)); G.load_cmds_arena = arena_alloc(GIGABYTE(64));
G.loaders_mutex = sys_mutex_alloc(); G.load_cmds_mutex = sys_mutex_alloc();
G.loaders_cv = sys_condition_variable_alloc();
G.evictor_mutex = sys_mutex_alloc(); G.evictor_mutex = sys_mutex_alloc();
G.evictor_cv = sys_condition_variable_alloc(); G.evictor_cv = sys_condition_variable_alloc();
{
struct temp_arena scratch = scratch_begin_no_conflict();
G.loader_threads_count = clamp_i64(1, MAX_LOADER_THREADS, sys_num_logical_processors() - 1);
for (u64 i = 0; i < G.loader_threads_count; ++i) {
struct string thread_name = string_format(scratch.arena,
STR("[P0] Sprite loader %F"),
FMT_UINT(i));
G.loader_threads[i] = sys_thread_alloc(sprite_loader_thread_entry_point, NULL, thread_name);
}
scratch_end(scratch);
}
G.evictor_thread = sys_thread_alloc(sprite_evictor_thread_entry_point, NULL, STR("[P0] Sprite evictor")); G.evictor_thread = sys_thread_alloc(sprite_evictor_thread_entry_point, NULL, STR("[P0] Sprite evictor"));
app_register_exit_callback(&sprite_shutdown); app_register_exit_callback(&sprite_shutdown);
@ -282,14 +262,6 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown)
{ {
__prof; __prof;
/* Signal loaders shutdown */
sys_mutex_lock(&G.loaders_mutex);
{
G.loaders_shutdown = true;
sys_condition_variable_broadcast(&G.loaders_cv);
}
sys_mutex_unlock(&G.loaders_mutex);
/* Signal evictor shutdown */ /* Signal evictor shutdown */
sys_mutex_lock(&G.evictor_mutex); sys_mutex_lock(&G.evictor_mutex);
{ {
@ -297,12 +269,6 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown)
sys_condition_variable_broadcast(&G.evictor_cv); sys_condition_variable_broadcast(&G.evictor_cv);
} }
sys_mutex_unlock(&G.evictor_mutex); sys_mutex_unlock(&G.evictor_mutex);
/* Wait on threads */
for (u64 i = 0; i < G.loader_threads_count; ++i) {
sys_thread_wait_release(&G.loader_threads[i]);
}
sys_thread_wait_release(&G.evictor_thread); sys_thread_wait_release(&G.evictor_thread);
} }
@ -691,16 +657,16 @@ INTERNAL void *data_from_tag_internal(struct sprite_scope *scope, struct sprite_
} break; } break;
} }
} else { } else {
sys_mutex_lock(&G.loaders_mutex); sys_mutex_lock(&G.load_cmds_mutex);
{ {
/* Allocate cmd */ /* Allocate cmd */
struct loader_cmd *cmd = NULL; struct load_cmd *cmd = NULL;
if (G.first_free_loader_cmd) { if (G.first_free_load_cmd) {
cmd = G.first_free_loader_cmd; cmd = G.first_free_load_cmd;
G.first_free_loader_cmd = cmd->next_free; G.first_free_load_cmd = cmd->next_free;
MEMZERO_STRUCT(cmd); MEMZERO_STRUCT(cmd);
} else { } else {
cmd = arena_push_zero(&G.loader_cmd_arena, struct loader_cmd); cmd = arena_push_zero(&G.load_cmds_arena, struct load_cmd);
} }
/* Initialize cmd */ /* Initialize cmd */
@ -712,17 +678,13 @@ INTERNAL void *data_from_tag_internal(struct sprite_scope *scope, struct sprite_
MEMCPY(cmd->tag.path.text, tag.path.text, copy_len); MEMCPY(cmd->tag.path.text, tag.path.text, copy_len);
} }
/* Add cmd to queue */
*(G.last_loader_cmd ? &G.last_loader_cmd->next : &G.first_loader_cmd) = cmd;
G.last_loader_cmd = cmd;
/* Cmd holds reference to node */ /* Cmd holds reference to node */
node_refcount_add(n, 1); node_refcount_add(n, 1);
/* Signal work ready */ /* Push work */
sys_condition_variable_signal(&G.loaders_cv); work_push_task(&sprite_load_task, cmd, WORK_PRIORITY_NORMAL);
} }
sys_mutex_unlock(&G.loaders_mutex); sys_mutex_unlock(&G.load_cmds_mutex);
} }
} }
@ -792,53 +754,32 @@ struct sprite_sheet_frame sprite_sheet_get_frame(struct sprite_sheet *sheet, u32
} }
/* ========================== * /* ========================== *
* Loader thread * Load task
* ========================== */ * ========================== */
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_loader_thread_entry_point, arg) INTERNAL WORK_TASK_FUNC_DEF(sprite_load_task, arg)
{ {
__prof; __prof;
(UNUSED)arg; struct load_cmd *cmd = (struct load_cmd *)arg;
sys_mutex_lock(&G.loaders_mutex); struct cache_node *n = cmd->cache_node;
{ switch (n->kind) {
while (!G.loaders_shutdown) { case CACHE_NODE_KIND_TEXTURE: {
struct loader_cmd *cmd = G.first_loader_cmd; cache_node_load_texture(n, cmd->tag);
if (cmd) { } break;
/* Pop cmd from queue */ case CACHE_NODE_KIND_SHEET: {
G.first_loader_cmd = cmd->next; cache_node_load_sheet(n, cmd->tag);
if (G.last_loader_cmd == cmd) { } break;
G.last_loader_cmd = NULL;
}
/* Do work (temporarily unlock) */
sys_mutex_unlock(&G.loaders_mutex);
{
struct cache_node *n = cmd->cache_node;
switch (n->kind) {
case CACHE_NODE_KIND_TEXTURE: {
cache_node_load_texture(n, cmd->tag);
} break;
case CACHE_NODE_KIND_SHEET: {
cache_node_load_sheet(n, cmd->tag);
} break;
}
}
sys_mutex_lock(&G.loaders_mutex);
/* Free cmd */
cmd->next_free = G.first_free_loader_cmd;
G.first_free_loader_cmd = cmd;
/* Cmd no longer references node */
node_refcount_add(cmd->cache_node, -1);
} else {
/* Wait for work */
sys_condition_variable_wait(&G.loaders_cv, &G.loaders_mutex);
}
}
} }
sys_mutex_unlock(&G.loaders_mutex);
/* Free cmd */
node_refcount_add(n, -1);
sys_mutex_lock(&G.load_cmds_mutex);
{
cmd->next_free = G.first_free_load_cmd;
G.first_free_load_cmd = cmd;
}
sys_mutex_unlock(&G.load_cmds_mutex);
} }
/* ========================== * /* ========================== *