sprite: use new notify reloading & allow reloading while out-of-date node is referenced
This commit is contained in:
parent
86a696a70a
commit
9fd87d9675
@ -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);
|
||||||
|
|||||||
@ -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
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
180
src/sprite.c
180
src/sprite.c
@ -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, ¤t_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 */
|
||||||
|
|||||||
@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user