fix resource watch list merging & deduplication

This commit is contained in:
jacob 2025-05-13 06:49:33 -05:00
parent 726ad90784
commit d8f1d646da
6 changed files with 29 additions and 26 deletions

BIN
res/graphics/tim.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -369,9 +369,8 @@ INTERNAL void reload_shader(struct dx11_shader *old_shader, struct dx11_shader_d
}
#if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(shader_resource_watch_callback, info)
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(shader_resource_watch_callback, name)
{
struct string name = info->name;
struct dx11_shader_desc *desc = (struct dx11_shader_desc *)fixed_dict_get(&G.shader_info_lookup, name);
if (desc) {
logf_info("Shader source file \"%F\" has changed", FMT_STR(name));

View File

@ -183,7 +183,14 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(resource_watch_monitor_thread_entry_poi
struct sys_watch_info_list res = sys_watch_wait(temp.arena, &watch);
struct sys_lock lock = sys_mutex_lock_e(&G.watch_dispatcher_mutex);
{
G.watch_dispatcher_info_list = sys_watch_info_copy(&G.watch_dispatcher_info_arena, res);
struct sys_watch_info_list list_part = sys_watch_info_copy(&G.watch_dispatcher_info_arena, res);
if (G.watch_dispatcher_info_list.last) {
G.watch_dispatcher_info_list.last->next = list_part.first;
list_part.first->prev = G.watch_dispatcher_info_list.last;
G.watch_dispatcher_info_list.last = list_part.last;
} else {
G.watch_dispatcher_info_list = list_part;
}
}
sys_mutex_unlock(&lock);
sys_condition_variable_broadcast(&G.watch_dispatcher_cv);
@ -199,7 +206,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(resource_watch_monitor_thread_entry_poi
* the dispatch of these callbacks, allowing for deduplication of file
* modification notifications. */
#define WATCH_DISPATCHER_DELAY_SECONDS 0.100
#define WATCH_DISPATCHER_DELAY_SECONDS 0.050
#define WATCH_DISPATCHER_DEDUP_DICT_BINS 128
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(resource_watch_dispatcher_thread_entry_point, _)
@ -221,6 +228,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(resource_watch_dispatcher_thread_entry_
/* Pull watch info from queue */
struct sys_watch_info_list watch_info_list = sys_watch_info_copy(temp.arena, G.watch_dispatcher_info_list);
MEMZERO_STRUCT(&G.watch_dispatcher_info_list);
arena_reset(&G.watch_dispatcher_info_arena);
/* Unlock and run callbacks */
@ -228,20 +236,18 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(resource_watch_dispatcher_thread_entry_
{
struct fixed_dict dedup_dict = fixed_dict_init(temp.arena, WATCH_DISPATCHER_DEDUP_DICT_BINS);
for (struct sys_watch_info *info = watch_info_list.first; info; info = info->next) {
/* Do not run callbacks for the same file more than once */
b32 skip = false;
if (info->kind == SYS_WATCH_INFO_KIND_MODIFIED) {
/* Skip modified notifications for the same file */
if ((u64)fixed_dict_get(&dedup_dict, info->name) != 1) {
fixed_dict_set(temp.arena, &dedup_dict, info->name, (void *)1);
} else {
skip = true;
}
if ((u64)fixed_dict_get(&dedup_dict, info->name) == 1) {
skip = true;
} else {
fixed_dict_set(temp.arena, &dedup_dict, info->name, (void *)1);
}
if (!skip) {
struct sys_lock callbacks_lock = sys_mutex_lock_s(&G.watch_callbacks_mutex);
for (u64 i = 0; i < G.num_watch_callbacks; ++i) {
resource_watch_callback *callback = G.watch_callbacks[i];
callback(info);
callback(info->name);
}
sys_mutex_unlock(&callbacks_lock);
}

View File

@ -39,8 +39,8 @@ b32 resource_exists(struct string path);
#define resource_get_name(res_ptr) STRING((res_ptr)->_file_name_len, (res_ptr)->_file_name_text)
#endif
#define RESOURCE_WATCH_CALLBACK_FUNC_DEF(func_name, arg_info) void func_name(struct sys_watch_info *arg_info)
typedef RESOURCE_WATCH_CALLBACK_FUNC_DEF(resource_watch_callback, info);
#define RESOURCE_WATCH_CALLBACK_FUNC_DEF(func_name, arg_name) void func_name(struct string arg_name)
typedef RESOURCE_WATCH_CALLBACK_FUNC_DEF(resource_watch_callback, name);
#if RESOURCE_RELOADING
void resource_register_watch_callback(resource_watch_callback *callback);

View File

@ -655,7 +655,6 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag)
logf_info("Loading sprite sheet [%F] \"%F\"", FMT_HEX(n->hash.v), FMT_STR(path));
i64 start_ns = sys_time_ns();
//ASSERT(string_ends_with(path, LIT(".ase")));
ASSERT(n->kind == CACHE_NODE_KIND_SHEET);
/* TODO: Replace arena allocs w/ buddy allocator */
@ -1076,9 +1075,8 @@ INTERNAL WORK_TASK_FUNC_DEF(sprite_load_task, arg)
#if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info)
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, name)
{
struct string name = info->name;
struct sprite_tag tag = sprite_tag_from_path(name);
for (enum cache_node_kind kind = 0; kind < NUM_CACHE_NODE_KINDS; ++kind) {
struct cache_node_hash hash = cache_node_hash_from_tag_hash(tag.hash, kind);
@ -1088,6 +1086,7 @@ INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info)
{
for (struct cache_node *n = bin->first; n; n = n->next_in_bin) {
if (n->hash.v == hash.v) {
logf_info("Sprite resource file \"%F\" has changed and will be reloaded.", FMT_STR(name));
atomic_i32_eval_exchange(&n->out_of_date, 1);
}
}
@ -1162,13 +1161,10 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
struct cache_node_refcount refcount = *(struct cache_node_refcount *)&refcount_uncast;
if (refcount.count <= 0) {
#if RESOURCE_RELOADING
/* Check if file changed for resource reloading */
if (!consider_for_eviction) {
if (atomic_i32_eval(&n->out_of_date)) {
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;
}
/* Force evict out-of-date sprites */
if (atomic_i32_eval(&n->out_of_date)) {
consider_for_eviction = true;
force_evict = true;
}
#endif

View File

@ -786,6 +786,7 @@ struct sys_watch_info_list sys_watch_wait(struct arena *arena, struct sys_watch
list.last = info;
} else {
list.first = info;
list.last = info;
}
struct string16 name16 = ZI;
@ -857,6 +858,7 @@ struct sys_watch_info_list sys_watch_info_copy(struct arena *arena, struct sys_w
dst_list.last = dst;
} else {
dst_list.first = dst;
dst_list.last = dst;
}
}
return dst_list;