From d13bf27ab7167e15b94cea1b632e2b6db0bd4395 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 5 May 2025 06:00:45 -0700 Subject: [PATCH] shift theme pattern cache from a per-frame cache to a permanent cache; use to animate (ui_key -> color) --- src/ui/ui_core.c | 87 ++++++++++++++++++++++++++++++++++++++++++------ src/ui/ui_core.h | 16 +++++++-- 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 239ccdeb..f6e8c5e6 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -435,6 +435,8 @@ ui_state_alloc(void) ui->box_table = push_array(arena, UI_BoxHashSlot, ui->box_table_size); ui->anim_slots_count = 4096; ui->anim_slots = push_array(arena, UI_AnimSlot, ui->anim_slots_count); + ui->theme_pattern_cache_slots_count = 1024; + ui->theme_pattern_cache_slots = push_array(arena, UI_ThemePatternCacheSlot, ui->theme_pattern_cache_slots_count); UI_InitStackNils(ui); return ui; } @@ -809,8 +811,6 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U ui_state->tags_key_stack_top = ui_state->tags_key_stack_free = 0; ui_state->tags_cache_slots_count = 512; ui_state->tags_cache_slots = push_array(ui_build_arena(), UI_TagsCacheSlot, ui_state->tags_cache_slots_count); - ui_state->theme_pattern_cache_slots_count = 512; - ui_state->theme_pattern_cache_slots = push_array(ui_build_arena(), UI_ThemePatternCacheSlot, ui_state->theme_pattern_cache_slots_count); } //- rjf: prune unused animation nodes @@ -834,6 +834,27 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U } } + //- rjf: prune unused theme pattern cache nodes + ProfScope("ui prune unused theme pattern cache") + { + for(UI_ThemePatternCacheNode *n = ui_state->lru_theme_pattern_cache_node, *next = 0; n != 0; n = next) + { + next = n->lru_next; + if(n->last_build_index_accessed+2 < ui_state->build_index) + { + U64 slot_idx = n->key.u64[0]%ui_state->theme_pattern_cache_slots_count; + UI_ThemePatternCacheSlot *slot = &ui_state->theme_pattern_cache_slots[slot_idx]; + DLLRemove_NP(slot->first, slot->last, n, slot_next, slot_prev); + DLLRemove_NP(ui_state->lru_theme_pattern_cache_node, ui_state->mru_theme_pattern_cache_node, n, lru_next, lru_prev); + SLLStackPush_N(ui_state->theme_pattern_cache_node_free, n, slot_next); + } + else + { + break; + } + } + } + //- rjf: detect mouse-moves for(UI_EventNode *n = events->first; n != 0; n = n->next) { @@ -1366,6 +1387,19 @@ ui_end_build(void) } F32 fast_rate = ui_state->default_animation_rate; F32 slow_rate = 1 - pow_f32(2, (-30.f * ui_state->animation_dt)); + for(U64 slot_idx = 0; slot_idx < ui_state->theme_pattern_cache_slots_count; slot_idx += 1) + { + for(UI_ThemePatternCacheNode *n = ui_state->theme_pattern_cache_slots[slot_idx].first; + n != 0; + n = n->slot_next) + { + for EachIndex(idx, 4) + { + n->current_rgba.v[idx] += (n->target_rgba.v[idx] - n->current_rgba.v[idx]) * slow_rate; + ui_state->is_animating = (ui_state->is_animating || abs_f32(n->target_rgba.v[idx] - n->current_rgba.v[idx]) > 0.001f); + } + } + } ui_state->ctx_menu_open_t += ((F32)!!ui_state->ctx_menu_open - ui_state->ctx_menu_open_t) * (ui_state->animation_info.flags & UI_AnimationInfoFlag_ContextMenuAnimations ? fast_rate : 1); ui_state->is_animating = (ui_state->is_animating || abs_f32((F32)!!ui_state->ctx_menu_open - ui_state->ctx_menu_open_t) > 0.01f); if(ui_state->ctx_menu_open_t >= 0.99f && ui_state->ctx_menu_open) @@ -2239,7 +2273,7 @@ ui_color_from_tags_key_extras(UI_Key key, String8Array extras) UI_ThemePatternCacheNode *node = 0; for(UI_ThemePatternCacheNode *n = slot->first; n != 0; - n = n->next) + n = n->slot_next) { if(ui_key_match(n->key, final_key)) { @@ -2247,8 +2281,8 @@ ui_color_from_tags_key_extras(UI_Key key, String8Array extras) } } - //- rjf: no node? create - if(node == 0) + //- rjf: no node, or this node is stale? create and/or update + if(node == 0 || node->last_build_index_accessed < ui_state->build_index) { // rjf: map tags_key (without name) -> full list of tags String8Array tags = {0}; @@ -2310,16 +2344,47 @@ ui_color_from_tags_key_extras(UI_Key key, String8Array extras) } // rjf: store in (key, name) -> (pattern) cache - node = push_array(ui_build_arena(), UI_ThemePatternCacheNode, 1); - SLLQueuePush(slot->first, slot->last, node); - node->key = final_key; - node->pattern = pattern; + B32 node_is_new = 0; + if(node == 0) + { + node_is_new = 1; + node = ui_state->theme_pattern_cache_node_free; + if(node != 0) + { + SLLStackPop_N(ui_state->theme_pattern_cache_node_free, slot_next); + } + else + { + node = push_array(ui_state->arena, UI_ThemePatternCacheNode, 1); + } + DLLPushBack_NP(slot->first, slot->last, node, slot_next, slot_prev); + DLLPushBack_NP(ui_state->lru_theme_pattern_cache_node, ui_state->mru_theme_pattern_cache_node, node, lru_next, lru_prev); + node->key = final_key; + } + + // rjf: update node's target color + if(pattern != 0) + { + node->target_rgba = pattern->linear; + if(node_is_new) + { + node->current_rgba = node->target_rgba; + } + } + } + + //- rjf: mark this node as most-recently-used + if(node != 0 && node->last_build_index_accessed < ui_state->build_index) + { + node->last_build_index_accessed = ui_state->build_index; + DLLRemove_NP(ui_state->lru_theme_pattern_cache_node, ui_state->mru_theme_pattern_cache_node, node, lru_next, lru_prev); + DLLPushBack_NP(ui_state->lru_theme_pattern_cache_node, ui_state->mru_theme_pattern_cache_node, node, lru_next, lru_prev); } //- rjf: grab resultant color - if(node != 0 && node->pattern != 0) + if(node != 0) { - result = node->pattern->linear; + result = node->current_rgba; } } return result; diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 18d99706..7c9a8a94 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -620,14 +620,19 @@ struct UI_TagsKeyStackNode UI_Key key; }; -//- rjf: cache for mapping 64-bit key * string -> theme pattern +//- rjf: cache for mapping 64-bit key -> theme pattern typedef struct UI_ThemePatternCacheNode UI_ThemePatternCacheNode; struct UI_ThemePatternCacheNode { - UI_ThemePatternCacheNode *next; + UI_ThemePatternCacheNode *slot_next; + UI_ThemePatternCacheNode *slot_prev; + UI_ThemePatternCacheNode *lru_next; + UI_ThemePatternCacheNode *lru_prev; + U64 last_build_index_accessed; UI_Key key; - UI_ThemePattern *pattern; + Vec4F32 target_rgba; + Vec4F32 current_rgba; }; typedef struct UI_ThemePatternCacheSlot UI_ThemePatternCacheSlot; @@ -683,8 +688,13 @@ struct UI_State UI_TagsKeyStackNode *tags_key_stack_free; U64 tags_cache_slots_count; UI_TagsCacheSlot *tags_cache_slots; + + //- rjf: theme pattern cache U64 theme_pattern_cache_slots_count; UI_ThemePatternCacheSlot *theme_pattern_cache_slots; + UI_ThemePatternCacheNode *theme_pattern_cache_node_free; + UI_ThemePatternCacheNode *lru_theme_pattern_cache_node; + UI_ThemePatternCacheNode *mru_theme_pattern_cache_node; //- rjf: build phase output UI_Box *root;