sprite: use new notify reloading & allow reloading while out-of-date node is referenced

This commit is contained in:
jacob 2025-05-13 03:38:08 -05:00
parent 86a696a70a
commit 9fd87d9675
5 changed files with 138 additions and 84 deletions

View File

@ -206,30 +206,28 @@ INTERNAL void init_shader_table(void)
/* Triangle shader layout */ /* Triangle shader layout */
G.shader_info[SHADER_TRIANGLE] = (struct dx11_shader_desc) { G.shader_info[SHADER_TRIANGLE] = (struct dx11_shader_desc) {
SHADER_TRIANGLE, .kind = SHADER_TRIANGLE,
"res/shaders/triangle.hlsl", .name_cstr = "res/shaders/triangle.hlsl",
sizeof(struct triangle_shader_vertex), .vertex_size = sizeof(struct triangle_shader_vertex),
{ .input_layout_desc = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
}, }
{ 0 }
}; };
/* Grid shader layout */ /* Grid shader layout */
G.shader_info[SHADER_GRID] = (struct dx11_shader_desc) { G.shader_info[SHADER_GRID] = (struct dx11_shader_desc) {
SHADER_GRID, .kind = SHADER_GRID,
"res/shaders/grid.hlsl", .name_cstr = "res/shaders/grid.hlsl",
sizeof(struct grid_shader_vertex), .vertex_size = sizeof(struct grid_shader_vertex),
{ .input_layout_desc = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "THICKNESS", 0, DXGI_FORMAT_R32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "THICKNESS", 0, DXGI_FORMAT_R32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "SPACING", 0, DXGI_FORMAT_R32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "SPACING", 0, DXGI_FORMAT_R32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "OFFSET", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } { "OFFSET", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
}, }
{ 0 }
}; };
G.shader_info_lookup = fixed_dict_init(&G.arena, SHADER_INFO_LOOKUP_BINS); G.shader_info_lookup = fixed_dict_init(&G.arena, SHADER_INFO_LOOKUP_BINS);
@ -371,7 +369,7 @@ INTERNAL void reload_shader(struct dx11_shader *old_shader, struct dx11_shader_d
} }
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_DEF(shader_resource_watch_callback, info) INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(shader_resource_watch_callback, info)
{ {
struct string name = info->name; struct string name = info->name;
struct dx11_shader_desc *desc = (struct dx11_shader_desc *)fixed_dict_get(&G.shader_info_lookup, name); struct dx11_shader_desc *desc = (struct dx11_shader_desc *)fixed_dict_get(&G.shader_info_lookup, name);

View File

@ -123,13 +123,6 @@ b32 resource_exists(struct string path)
#endif #endif
} }
#if !RESOURCES_EMBEDDED
struct sys_file_time resource_get_time(struct resource *res_ptr)
{
return sys_file_get_time(res_ptr->_file);
}
#endif
/* ========================== * /* ========================== *
* Watch * Watch
* ========================== */ * ========================== */

View File

@ -33,20 +33,14 @@ b32 resource_exists(struct string path);
#define resource_get_data(res_ptr) (res_ptr)->_data #define resource_get_data(res_ptr) (res_ptr)->_data
#if RESOURCES_EMBEDDED
#define resource_get_time(res_ptr) (struct sys_file_time) ZI
#else
struct sys_file_time resource_get_time(struct resource *res_ptr);
#endif
#if RESOURCES_EMBEDDED #if RESOURCES_EMBEDDED
#define resource_get_name(res_ptr) (res_ptr)->_file_name #define resource_get_name(res_ptr) (res_ptr)->_file_name
#else #else
#define resource_get_name(res_ptr) STRING((res_ptr)->_file_name_len, (res_ptr)->_file_name_text) #define resource_get_name(res_ptr) STRING((res_ptr)->_file_name_len, (res_ptr)->_file_name_text)
#endif #endif
#define RESOURCE_WATCH_CALLBACK_DEF(func_name, arg_info) void func_name(struct sys_watch_info *arg_info) #define RESOURCE_WATCH_CALLBACK_FUNC_DEF(func_name, arg_info) void func_name(struct sys_watch_info *arg_info)
typedef RESOURCE_WATCH_CALLBACK_DEF(resource_watch_callback, info); typedef RESOURCE_WATCH_CALLBACK_FUNC_DEF(resource_watch_callback, info);
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
void resource_register_watch_callback(resource_watch_callback *callback); void resource_register_watch_callback(resource_watch_callback *callback);

View File

@ -12,6 +12,7 @@
#include "app.h" #include "app.h"
#include "renderer.h" #include "renderer.h"
#include "math.h" #include "math.h"
#include "rand.h"
#define CACHE_MEMORY_BUDGET (MEGABYTE(256)) #define CACHE_MEMORY_BUDGET (MEGABYTE(256))
#define CACHE_BINS_COUNT 1024 #define CACHE_BINS_COUNT 1024
@ -50,7 +51,9 @@ struct load_cmd {
enum cache_node_kind { enum cache_node_kind {
CACHE_NODE_KIND_TEXTURE, CACHE_NODE_KIND_TEXTURE,
CACHE_NODE_KIND_SHEET CACHE_NODE_KIND_SHEET,
NUM_CACHE_NODE_KINDS
}; };
enum cache_node_state { enum cache_node_state {
@ -83,14 +86,14 @@ struct cache_node {
struct sprite_sheet *sheet; struct sprite_sheet *sheet;
/* Hash list */ /* Hash list */
struct cache_node *next_hash; struct cache_node *next_in_bin;
struct cache_node *prev_hash; struct cache_node *prev_in_bin;
/* Free list */ /* Free list */
struct cache_node *next_free; struct cache_node *next_free;
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
struct sys_datetime initial_resource_file_modified_time; struct atomic_i32 out_of_date; /* Has the resource changed since this node was loaded */
u64 tag_path_len; u64 tag_path_len;
u8 tag_path[4096]; u8 tag_path[4096];
#endif #endif
@ -111,7 +114,7 @@ struct cache {
struct sprite_scope_reference { struct sprite_scope_reference {
struct cache_node *cache_node; struct cache_node *cache_node;
struct sprite_scope_reference *next_hash; struct sprite_scope_reference *next_in_bin;
struct sprite_scope_reference *next_free; struct sprite_scope_reference *next_free;
}; };
@ -151,12 +154,18 @@ struct sprite_tctx {
struct arena arena; struct arena arena;
struct sprite_scope *first_free_scope; struct sprite_scope *first_free_scope;
struct sprite_scope_reference *first_free_reference; struct sprite_scope_reference *first_free_reference;
#if RTC
u32 thread_id;
#endif
}; };
INTERNAL THREAD_LOCAL_VAR_ALLOC_FUNC_DEF(sprite_tctx_alloc, vtctx) INTERNAL THREAD_LOCAL_VAR_ALLOC_FUNC_DEF(sprite_tctx_alloc, vtctx)
{ {
struct sprite_tctx *tctx = (struct sprite_tctx *)vtctx; struct sprite_tctx *tctx = (struct sprite_tctx *)vtctx;
tctx->arena = arena_alloc(MEGABYTE(64)); tctx->arena = arena_alloc(MEGABYTE(64));
#if RTC
tctx->thread_id = sys_thread_id();
#endif
} }
INTERNAL THREAD_LOCAL_VAR_RELEASE_FUNC_DEF(sprite_tctx_release, vtctx) INTERNAL THREAD_LOCAL_VAR_RELEASE_FUNC_DEF(sprite_tctx_release, vtctx)
@ -213,6 +222,10 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown);
INTERNAL WORK_TASK_FUNC_DEF(sprite_load_task, 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);
#if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info);
#endif
struct sprite_startup_receipt sprite_startup(struct renderer_startup_receipt *renderer_sr, struct sprite_startup_receipt sprite_startup(struct renderer_startup_receipt *renderer_sr,
struct resource_startup_receipt *resource_sr) struct resource_startup_receipt *resource_sr)
{ {
@ -262,6 +275,7 @@ struct sprite_startup_receipt sprite_startup(struct renderer_startup_receipt *re
G.evictor_thread = sys_thread_alloc(sprite_evictor_thread_entry_point, NULL, LIT("[P2] Sprite evictor")); G.evictor_thread = sys_thread_alloc(sprite_evictor_thread_entry_point, NULL, LIT("[P2] Sprite evictor"));
app_register_exit_callback(&sprite_shutdown); app_register_exit_callback(&sprite_shutdown);
resource_register_watch_callback(&sprite_resource_watch_callback);
return (struct sprite_startup_receipt) { 0 }; return (struct sprite_startup_receipt) { 0 };
} }
@ -357,9 +371,6 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta
if (resource_exists(path)) { if (resource_exists(path)) {
struct resource texture_rs = resource_open(path); struct resource texture_rs = resource_open(path);
decoded = ase_decode_image(scratch.arena, resource_get_data(&texture_rs)); decoded = ase_decode_image(scratch.arena, resource_get_data(&texture_rs));
#if RESOURCE_RELOADING
n->initial_resource_file_modified_time = resource_get_time(&texture_rs).modified;
#endif
resource_close(&texture_rs); resource_close(&texture_rs);
/* Initialize */ /* Initialize */
@ -661,9 +672,6 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag)
if (resource_exists(path)) { if (resource_exists(path)) {
struct resource sheet_rs = resource_open(path); struct resource sheet_rs = resource_open(path);
decoded = ase_decode_sheet(scratch.arena, resource_get_data(&sheet_rs)); decoded = ase_decode_sheet(scratch.arena, resource_get_data(&sheet_rs));
#if RESOURCE_RELOADING
n->initial_resource_file_modified_time = resource_get_time(&sheet_rs).modified;
#endif
resource_close(&sheet_rs); resource_close(&sheet_rs);
/* Initialize */ /* Initialize */
@ -700,36 +708,44 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag)
* Scope * Scope
* ========================== */ * ========================== */
INTERNAL void scope_ensure_reference(struct sprite_scope *scope, struct cache_node *cache_node, u64 cache_bin_index) /* Returns the slot at which the reference pointer should exist in the sprite scope.
* If the pointed to slot points to NULL, then the reference does not exist in the scope for the node. */
INTERNAL struct sprite_scope_reference **scope_get_reference_slot(struct sprite_scope *scope, struct cache_node *cache_node, u64 cache_bin_index)
{ {
__prof; sys_thread_assert(scope->tctx->thread_id);
struct sprite_scope_reference **ref_next = &scope->reference_bins[cache_bin_index];
struct sprite_scope_reference *ref = *ref_next; struct sprite_scope_reference **ref_slot = &scope->reference_bins[cache_bin_index];
while (ref) { while (*ref_slot) {
if (ref->cache_node == cache_node) { if ((*ref_slot)->cache_node == cache_node) {
/* Scope already references node */ /* Found reference in scope */
break; break;
} else { } else {
ref_next = &ref->next_hash; ref_slot = &(*ref_slot)->next_in_bin;
ref = *ref_next;
} }
} }
return ref_slot;
}
if (!ref) { INTERNAL struct sprite_scope_reference *scope_reference_alloc(struct sprite_scope *scope, struct cache_node *cache_node)
/* Increment refcount */ {
node_refcount_add(cache_node, 1); sys_thread_assert(scope->tctx->thread_id);
/* Add reference to scope */
struct sprite_tctx *tctx = thread_local_var_eval(&tl_sprite_tctx); /* Increment refcount */
if (tctx->first_free_reference) { node_refcount_add(cache_node, 1);
ref = tctx->first_free_reference;
tctx->first_free_reference = ref->next_free; /* Add reference to scope */
MEMZERO_STRUCT(ref); struct sprite_tctx *tctx = scope->tctx;
} else { struct sprite_scope_reference *ref;
ref = arena_push_zero(&tctx->arena, struct sprite_scope_reference); if (tctx->first_free_reference) {
} ref = tctx->first_free_reference;
ref->cache_node = cache_node; tctx->first_free_reference = ref->next_free;
*ref_next = ref; MEMZERO_STRUCT(ref);
} else {
ref = arena_push_zero(&tctx->arena, struct sprite_scope_reference);
} }
ref->cache_node = cache_node;
return ref;
} }
struct sprite_scope *sprite_scope_begin(void) struct sprite_scope *sprite_scope_begin(void)
@ -748,13 +764,15 @@ struct sprite_scope *sprite_scope_begin(void)
res = arena_push_zero(&tctx->arena, struct sprite_scope); res = arena_push_zero(&tctx->arena, struct sprite_scope);
res->reference_bins = arena_push_array_zero(&tctx->arena, struct sprite_scope_reference *, CACHE_BINS_COUNT); res->reference_bins = arena_push_array_zero(&tctx->arena, struct sprite_scope_reference *, CACHE_BINS_COUNT);
} }
res->tctx = tctx;
return res; return res;
} }
void sprite_scope_end(struct sprite_scope *scope) void sprite_scope_end(struct sprite_scope *scope)
{ {
struct sprite_tctx *tctx = thread_local_var_eval(&tl_sprite_tctx); sys_thread_assert(scope->tctx->thread_id);
struct sprite_tctx *tctx = scope->tctx;
for (u64 i = 0; i < CACHE_BINS_COUNT; ++i) { for (u64 i = 0; i < CACHE_BINS_COUNT; ++i) {
struct sprite_scope_reference *ref = scope->reference_bins[i]; struct sprite_scope_reference *ref = scope->reference_bins[i];
while (ref) { while (ref) {
@ -763,7 +781,7 @@ void sprite_scope_end(struct sprite_scope *scope)
/* Add reference to free list */ /* Add reference to free list */
ref->next_free = tctx->first_free_reference; ref->next_free = tctx->first_free_reference;
tctx->first_free_reference = ref; tctx->first_free_reference = ref;
ref = ref->next_hash; ref = ref->next_in_bin;
} }
} }
scope->next_free = tctx->first_free_scope; scope->next_free = tctx->first_free_scope;
@ -793,12 +811,33 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct
nonmatching_next = &bin->first; nonmatching_next = &bin->first;
n = *nonmatching_next; n = *nonmatching_next;
while (n) { while (n) {
b32 match = false;
if (n->hash.v == hash.v) { if (n->hash.v == hash.v) {
scope_ensure_reference(scope, n, cache_bin_index); struct sprite_scope_reference **ref_slot = scope_get_reference_slot(scope, n, cache_bin_index);
#if RESOURCE_RELOADING
if (*ref_slot) {
match = true;
} else {
if (atomic_i32_eval(&n->out_of_date)) {
/* If node is out of date and the scope doesn't already hold a reference to it, then ignore node */
} else {
match = true;
*ref_slot = scope_reference_alloc(scope, n);
}
}
#else
if (!(*ref_slot)) {
*ref_slot = scope_reference_alloc(scope, n);
}
match = true;
#endif
}
if (match) {
break; break;
} else { } else {
nonmatching = n; nonmatching = n;
nonmatching_next = &nonmatching->next_hash; nonmatching_next = &nonmatching->next_in_bin;
n = *nonmatching_next; n = *nonmatching_next;
} }
} }
@ -822,12 +861,16 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct
} }
sys_mutex_unlock(&pool_lock); sys_mutex_unlock(&pool_lock);
} }
/* Init node and add to bin */ /* Init node and add to bin */
scope_ensure_reference(scope, n, cache_bin_index); struct sprite_scope_reference **ref_slot = scope_get_reference_slot(scope, n, cache_bin_index);
if (!(*ref_slot)) {
*ref_slot = scope_reference_alloc(scope, n);
}
*nonmatching_next = n; *nonmatching_next = n;
if (nonmatching) { if (nonmatching) {
nonmatching->next_hash = n; nonmatching->next_in_bin = n;
n->prev_hash = nonmatching; n->prev_in_bin = nonmatching;
} }
n->hash = cache_node_hash_from_tag_hash(tag.hash, kind); n->hash = cache_node_hash_from_tag_hash(tag.hash, kind);
n->kind = kind; n->kind = kind;
@ -847,6 +890,7 @@ INTERNAL void *data_from_tag_internal(struct sprite_scope *scope, struct sprite_
switch (kind) { switch (kind) {
case CACHE_NODE_KIND_TEXTURE: { res = G.loading_texture; } break; case CACHE_NODE_KIND_TEXTURE: { res = G.loading_texture; } break;
case CACHE_NODE_KIND_SHEET: { res = G.loading_sheet; } break; case CACHE_NODE_KIND_SHEET: { res = G.loading_sheet; } break;
default: { sys_panic(LIT("Unknown sprite cache node kind")); } break;
} }
struct cache_node *n = node_lookup_touch(scope, tag, kind); struct cache_node *n = node_lookup_touch(scope, tag, kind);
@ -856,6 +900,7 @@ INTERNAL void *data_from_tag_internal(struct sprite_scope *scope, struct sprite_
switch (kind) { switch (kind) {
case CACHE_NODE_KIND_TEXTURE: { res = n->texture; } break; case CACHE_NODE_KIND_TEXTURE: { res = n->texture; } break;
case CACHE_NODE_KIND_SHEET: { res = n->sheet; } break; case CACHE_NODE_KIND_SHEET: { res = n->sheet; } break;
default: { sys_panic(LIT("Unknown sprite cache node kind")); } break;
} }
} else if (state == CACHE_NODE_STATE_NONE) { } else if (state == CACHE_NODE_STATE_NONE) {
if (atomic_u32_eval_compare_exchange(&n->state, CACHE_NODE_STATE_NONE, CACHE_NODE_STATE_QUEUED) == CACHE_NODE_STATE_NONE) { if (atomic_u32_eval_compare_exchange(&n->state, CACHE_NODE_STATE_NONE, CACHE_NODE_STATE_QUEUED) == CACHE_NODE_STATE_NONE) {
@ -870,6 +915,7 @@ INTERNAL void *data_from_tag_internal(struct sprite_scope *scope, struct sprite_
cache_node_load_sheet(n, tag); cache_node_load_sheet(n, tag);
res = n->sheet; res = n->sheet;
} break; } break;
default: { sys_panic(LIT("Unknown sprite cache node kind")); } break;
} }
} else { } else {
struct sys_lock lock = sys_mutex_lock_e(&G.load_cmds_mutex); struct sys_lock lock = sys_mutex_lock_e(&G.load_cmds_mutex);
@ -1021,6 +1067,7 @@ INTERNAL WORK_TASK_FUNC_DEF(sprite_load_task, arg)
case CACHE_NODE_KIND_SHEET: { case CACHE_NODE_KIND_SHEET: {
cache_node_load_sheet(n, cmd->tag); cache_node_load_sheet(n, cmd->tag);
} break; } break;
default: { sys_panic(LIT("Unknown sprite cache node kind")); } break;
} }
/* Free cmd */ /* Free cmd */
@ -1033,6 +1080,34 @@ INTERNAL WORK_TASK_FUNC_DEF(sprite_load_task, arg)
} }
} }
/* ========================== *
* Resource watch
* ========================== */
#if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info)
{
struct string name = info->name;
struct sprite_tag tag = sprite_tag_from_path(name);
for (u64 kind = 0; kind < NUM_CACHE_NODE_KINDS; ++kind) {
struct cache_node_hash hash = cache_node_hash_from_tag_hash(tag.hash, kind);
u64 cache_bin_index = hash.v % CACHE_BINS_COUNT;
struct cache_bin *bin = &G.cache.bins[cache_bin_index];
struct sys_lock lock = sys_mutex_lock_s(&bin->mutex);
{
for (struct cache_node *n = bin->first; n; n = n->next_in_bin) {
if (n->hash.v == hash.v) {
atomic_i32_eval_exchange(&n->out_of_date, 1);
}
}
}
sys_mutex_unlock(&lock);
}
}
#endif
/* ========================== * /* ========================== *
* Evictor thread * Evictor thread
* ========================== */ * ========================== */
@ -1080,15 +1155,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
/* Check if file changed for resource reloading */ /* Check if file changed for resource reloading */
if (!consider_for_eviction) { if (!consider_for_eviction) {
struct string path = STRING(n->tag_path_len, n->tag_path); struct string path = STRING(n->tag_path_len, n->tag_path);
b32 file_changed = false; if (atomic_i32_eval(&n->out_of_date)) {
struct sys_datetime current_file_time;
{
struct sys_file file = sys_file_open_read(path);
current_file_time = sys_file_get_time(file).modified;
sys_file_close(file);
}
file_changed = !MEMEQ_STRUCT(&n->initial_resource_file_modified_time, &current_file_time);
if (file_changed) {
switch (n->kind) { switch (n->kind) {
case CACHE_NODE_KIND_TEXTURE: { case CACHE_NODE_KIND_TEXTURE: {
logf_info("Resource file for sprite texture \"%F\" has changed. Evicting to allow for reloading.", FMT_STR(path)); logf_info("Resource file for sprite texture \"%F\" has changed. Evicting to allow for reloading.", FMT_STR(path));
@ -1096,6 +1163,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
case CACHE_NODE_KIND_SHEET: { case CACHE_NODE_KIND_SHEET: {
logf_info("Resource file for sprite sheet \"%F\" has changed. Evicting to allow for reloading.", FMT_STR(path)); logf_info("Resource file for sprite sheet \"%F\" has changed. Evicting to allow for reloading.", FMT_STR(path));
} break; } break;
default: { sys_panic(LIT("Unknown sprite cache node kind")); } break;
} }
consider_for_eviction = true; consider_for_eviction = true;
force_evict = true; force_evict = true;
@ -1124,7 +1192,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
head_consider = evict_node; head_consider = evict_node;
} }
n = n->next_hash; n = n->next_in_bin;
} }
} }
sys_mutex_unlock(&bin_lock); sys_mutex_unlock(&bin_lock);
@ -1166,13 +1234,13 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
/* Cache node has been referenced since scan, skip eviction. */ /* Cache node has been referenced since scan, skip eviction. */
} else if (atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET || en->force_evict) { } else if (atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET || en->force_evict) {
/* Remove from cache bin */ /* Remove from cache bin */
if (n->prev_hash) { if (n->prev_in_bin) {
n->prev_hash->next_hash = n->next_hash; n->prev_in_bin->next_in_bin = n->next_in_bin;
} else { } else {
bin->first = n->next_hash; bin->first = n->next_in_bin;
} }
if (n->next_hash) { if (n->next_in_bin) {
n->next_hash->prev_hash = n->prev_hash; n->next_in_bin->prev_in_bin = n->prev_in_bin;
} }
atomic_u64_eval_add_i64(&G.cache.memory_usage, -((i64)n->memory_usage)); atomic_u64_eval_add_i64(&G.cache.memory_usage, -((i64)n->memory_usage));
/* Add to evicted list */ /* Add to evicted list */

View File

@ -32,6 +32,7 @@ b32 sprite_tag_eq(struct sprite_tag t1, struct sprite_tag t2);
* ========================== */ * ========================== */
struct sprite_scope { struct sprite_scope {
struct sprite_tctx *tctx;
struct sprite_scope_reference **reference_bins; struct sprite_scope_reference **reference_bins;
struct sprite_scope *next_free; struct sprite_scope *next_free;
}; };