fix sprite force evict sorting
This commit is contained in:
parent
79ce7a9d6e
commit
726ad90784
BIN
res/graphics/tim.ase
(Stored with Git LFS)
BIN
res/graphics/tim.ase
(Stored with Git LFS)
Binary file not shown.
99
src/sprite.c
99
src/sprite.c
@ -1107,12 +1107,31 @@ struct evict_node {
|
||||
struct cache_node_refcount refcount;
|
||||
struct cache_node *cache_node;
|
||||
struct cache_bin *cache_bin;
|
||||
struct evict_node *next_consider;
|
||||
struct evict_node *next_consider_lru;
|
||||
struct evict_node *next_evicted;
|
||||
|
||||
struct evict_node *next_evicted;
|
||||
};
|
||||
|
||||
INTERNAL SORT_COMPARE_FUNC_DEF(evict_sort, arg_a, arg_b, udata)
|
||||
{
|
||||
(UNUSED)udata;
|
||||
struct evict_node *a = arg_a;
|
||||
struct evict_node *b = arg_b;
|
||||
|
||||
u64 refcount_uncast_a = atomic_u64_eval(&a->cache_node->refcount_struct);
|
||||
u64 refcount_uncast_b = atomic_u64_eval(&b->cache_node->refcount_struct);
|
||||
u32 cycle_a = ((struct cache_node_refcount *)&refcount_uncast_a)->last_modified_cycle;
|
||||
u32 cycle_b = ((struct cache_node_refcount *)&refcount_uncast_b)->last_modified_cycle;
|
||||
|
||||
i32 res = (cycle_b > cycle_a) - (cycle_a > cycle_b);
|
||||
res += ((a->force_evict > b->force_evict) - (a->force_evict < b->force_evict)) * 2;
|
||||
|
||||
if (a->force_evict != b->force_evict) {
|
||||
DEBUGBREAKABLE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
||||
{
|
||||
(UNUSED)arg;
|
||||
@ -1120,9 +1139,10 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
||||
struct sys_lock evictor_lock = sys_mutex_lock_e(&G.evictor_mutex);
|
||||
while (!G.evictor_shutdown) {
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
struct evict_node *head_consider = NULL;
|
||||
struct evict_node *head_consider_lru = NULL;
|
||||
struct evict_node *head_evicted = NULL;
|
||||
|
||||
u64 evict_array_count = 0;
|
||||
struct evict_node *evict_array = arena_dry_push(scratch.arena, struct evict_node);
|
||||
|
||||
if (!G.evictor_shutdown) {
|
||||
u32 cur_cycle = *atomic_u32_raw(&G.evictor_cycle);
|
||||
|
||||
@ -1145,15 +1165,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
||||
/* Check if file changed for resource reloading */
|
||||
if (!consider_for_eviction) {
|
||||
if (atomic_i32_eval(&n->out_of_date)) {
|
||||
switch (n->kind) {
|
||||
case CACHE_NODE_KIND_TEXTURE: {
|
||||
logf_info("Resource file for sprite texture [%F] has changed. Evicting to allow for reloading.", FMT_HEX(n->hash.v));
|
||||
} break;
|
||||
case CACHE_NODE_KIND_SHEET: {
|
||||
logf_info("Resource file for sprite sheet [%F] has changed. Evicting to allow for reloading.", FMT_HEX(n->hash.v));
|
||||
} break;
|
||||
default: { sys_panic(LIT("Unknown sprite cache node kind")); } break;
|
||||
}
|
||||
logf_info("Resource file for sprite texture/sheet [%F] has changed. Evicting to allow for reloading.", FMT_HEX(n->hash.v));
|
||||
consider_for_eviction = true;
|
||||
force_evict = true;
|
||||
}
|
||||
@ -1161,24 +1173,24 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
||||
#endif
|
||||
|
||||
/* Check usage time */
|
||||
if (cache_over_budget) {
|
||||
u32 last_used_cycle = refcount.last_modified_cycle;
|
||||
i64 time_since_use_ns = ((i64)cur_cycle - (i64)last_used_cycle) * EVICTOR_CYCLE_INTERVAL_NS;
|
||||
if (time_since_use_ns > EVICTOR_GRACE_PERIOD_NS) {
|
||||
/* Cache is over budget and node hasn't been referenced in a while */
|
||||
consider_for_eviction = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Add node to evict list */
|
||||
if (consider_for_eviction) {
|
||||
struct evict_node *evict_node = arena_push_zero(scratch.arena, struct evict_node);
|
||||
evict_node->cache_node = n;
|
||||
evict_node->cache_bin = bin;
|
||||
evict_node->refcount = refcount;
|
||||
evict_node->force_evict = force_evict;
|
||||
evict_node->next_consider = head_consider;
|
||||
head_consider = evict_node;
|
||||
struct evict_node *en = arena_push_zero(scratch.arena, struct evict_node);
|
||||
en->cache_node = n;
|
||||
en->cache_bin = bin;
|
||||
en->refcount = refcount;
|
||||
en->force_evict = force_evict;
|
||||
++evict_array_count;
|
||||
}
|
||||
|
||||
n = n->next_in_bin;
|
||||
@ -1188,32 +1200,22 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort evict nodes by usage time */
|
||||
if (head_consider) {
|
||||
/* TODO: Optimize sort if necessary. Currently O(n^2). */
|
||||
/* Scratch arena should only contain evict array at this point */
|
||||
ASSERT(scratch.arena->pos == (sizeof(*evict_array) * evict_array_count));
|
||||
|
||||
/* Sort evict nodes */
|
||||
{
|
||||
__profscope(eviction_sort);
|
||||
for (struct evict_node *en = head_consider; en; en = en->next_consider) {
|
||||
u32 last_modified_cycle = en->refcount.last_modified_cycle;
|
||||
struct evict_node *prev = NULL;
|
||||
struct evict_node *next = head_consider_lru;
|
||||
while (next && !(last_modified_cycle <= next->refcount.last_modified_cycle || en->force_evict)) {
|
||||
prev = next;
|
||||
next = next->next_consider_lru;
|
||||
}
|
||||
if (prev) {
|
||||
prev->next_consider_lru = en;
|
||||
} else {
|
||||
head_consider_lru = en;
|
||||
}
|
||||
en->next_consider_lru = next;
|
||||
}
|
||||
merge_sort(evict_array, evict_array_count, sizeof(*evict_array), evict_sort, NULL);
|
||||
}
|
||||
|
||||
/* Remove evictable nodes from cache table until under budget */
|
||||
if (head_consider_lru) {
|
||||
struct evict_node *first_evicted = NULL;
|
||||
{
|
||||
__profscope(eviction_cache_removal);
|
||||
b32 stop_evicting = false;
|
||||
for (struct evict_node *en = head_consider_lru; en && !stop_evicting; en = en->next_consider_lru) {
|
||||
for (u64 i = 0; i < evict_array_count && !stop_evicting; ++i) {
|
||||
struct evict_node *en = &evict_array[i];
|
||||
struct cache_bin *bin = en->cache_bin;
|
||||
struct cache_node *n = en->cache_node;
|
||||
struct sys_lock bin_lock = sys_mutex_lock_e(&bin->mutex);
|
||||
@ -1232,9 +1234,10 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
||||
n->next_in_bin->prev_in_bin = n->prev_in_bin;
|
||||
}
|
||||
atomic_u64_eval_add_i64(&G.cache.memory_usage, -((i64)n->memory_usage));
|
||||
|
||||
/* Add to evicted list */
|
||||
en->next_evicted = head_evicted;
|
||||
head_evicted = en;
|
||||
en->next_evicted = first_evicted;
|
||||
first_evicted = en;
|
||||
} else {
|
||||
/* Cache is no longer over budget or force evicting, stop iteration */
|
||||
stop_evicting = true;
|
||||
@ -1244,11 +1247,11 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
||||
}
|
||||
}
|
||||
|
||||
if (head_evicted) {
|
||||
if (first_evicted) {
|
||||
/* Release evicted node memory */
|
||||
{
|
||||
__profscope(eviction_memory_release);
|
||||
for (struct evict_node *en = head_evicted; en; en = en->next_evicted) {
|
||||
for (struct evict_node *en = first_evicted; en; en = en->next_evicted) {
|
||||
struct cache_node *n = en->cache_node;
|
||||
if (n->kind == CACHE_NODE_KIND_TEXTURE && n->texture->valid) {
|
||||
renderer_texture_release(n->texture->texture);
|
||||
@ -1261,7 +1264,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
||||
{
|
||||
__profscope(eviction_free_list_append);
|
||||
struct sys_lock pool_lock = sys_mutex_lock_e(&G.cache.node_pool_mutex);
|
||||
for (struct evict_node *en = head_evicted; en; en = en->next_evicted) {
|
||||
for (struct evict_node *en = first_evicted; en; en = en->next_evicted) {
|
||||
struct cache_node *n = en->cache_node;
|
||||
n->next_free = G.cache.node_pool_first_free;
|
||||
G.cache.node_pool_first_free = n;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user