From abac85d32432a3afbac67decccd6de6760c2c35b Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 7 May 2025 16:57:36 -0500 Subject: [PATCH] shader hot reloading --- build.c | 24 +--- {src => res}/shaders/grid.hlsl | 0 {src => res}/shaders/triangle.hlsl | 0 src/font.c | 4 +- src/inc.c | 10 +- src/inc.h | 2 - src/memory.h | 5 +- src/renderer_d3d11.c | 203 +++++++++++++++++++---------- src/resource.c | 71 ++++++---- src/resource.h | 34 +++-- src/scratch.h | 15 ++- src/sim_ent.c | 2 - src/sound.c | 4 +- src/sprite.c | 16 ++- src/sys_win32.c | 7 +- 15 files changed, 240 insertions(+), 157 deletions(-) rename {src => res}/shaders/grid.hlsl (100%) rename {src => res}/shaders/triangle.hlsl (100%) diff --git a/build.c b/build.c index 095ebf70..2cfe065a 100644 --- a/build.c +++ b/build.c @@ -416,7 +416,6 @@ void OnBuild(StringList cli_args) D_Tag executable_file = D_TagFromPath(&perm, StringF(&perm, Lit("%F/PowerPlay.exe"), FmtStr(out_bin_dir_path)), D_TagKind_File); D_Tag res_dir = D_TagFromPath(&perm, Lit("res"), D_TagKind_Dir); - D_Tag shaders_dir = D_TagFromPath(&perm, Lit("src/shaders"), D_TagKind_Dir); D_Tag icon_file = D_TagFromPath(&perm, Lit("icon.ico"), D_TagKind_File); D_Tag inc_src_file = D_TagFromPath(&perm, Lit("src/inc.c"), D_TagKind_File); @@ -658,11 +657,9 @@ void OnBuild(StringList cli_args) AddSyncPoint(); D_TagList tar_input_dirs = { 0 }; - { - D_TagListAppend(&perm, &tar_input_dirs, shaders_dir); - if (should_embed_res_dir) { - D_TagListAppend(&perm, &tar_input_dirs, res_dir); - } + + if (should_embed_res_dir) { + D_TagListAppend(&perm, &tar_input_dirs, res_dir); } for (D_TagListNode *n = tar_input_dirs.first; n; n = n->next) { @@ -694,23 +691,16 @@ void OnBuild(StringList cli_args) D_Tag rc_input_file = D_TagFromPath(&perm, StringF(&perm, Lit("%F/rc.rc"), FmtStr(out_inc_dir_path)), D_TagKind_File); { - D_Tag shaders_tar_file = D_TagFromPath(&perm, StringF(&perm, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(shaders_dir))), D_TagKind_File); D_Tag res_tar_file = D_TagFromPath(&perm, StringF(&perm, Lit("%F/%F.tar"), FmtStr(out_inc_dir_path), FmtStr(D_GetName(res_dir))), D_TagKind_File); D_AddDependency(&store, rc_input_file, icon_file); - if (should_embed_in_rc) { - D_AddDependency(&store, rc_input_file, shaders_tar_file); - if (should_embed_res_dir) { - D_AddDependency(&store, rc_input_file, res_tar_file); - } + if (should_embed_in_rc && should_embed_res_dir) { + D_AddDependency(&store, rc_input_file, res_tar_file); } if (IsDirty(rc_input_file)) { D_ClearWrite(rc_input_file, Lit("")); D_AppendWrite(rc_input_file, StringF(&perm, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(icon_file)), FmtStr(Lit("ICON")), FmtStr(D_GetName(icon_file)))); - if (should_embed_in_rc) { - D_AppendWrite(rc_input_file, StringF(&perm, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(shaders_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(shaders_tar_file)))); - if (should_embed_res_dir) { - D_AppendWrite(rc_input_file, StringF(&perm, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(res_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(res_tar_file)))); - } + if (should_embed_in_rc && should_embed_res_dir) { + D_AppendWrite(rc_input_file, StringF(&perm, Lit("%F %F DISCARDABLE %F\n"), FmtStr(D_GetName(res_tar_file)), FmtStr(Lit("RCDATA")), FmtStr(D_GetName(res_tar_file)))); } } } diff --git a/src/shaders/grid.hlsl b/res/shaders/grid.hlsl similarity index 100% rename from src/shaders/grid.hlsl rename to res/shaders/grid.hlsl diff --git a/src/shaders/triangle.hlsl b/res/shaders/triangle.hlsl similarity index 100% rename from src/shaders/triangle.hlsl rename to res/shaders/triangle.hlsl diff --git a/src/font.c b/src/font.c index 84c28b42..9d790982 100644 --- a/src/font.c +++ b/src/font.c @@ -116,8 +116,8 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) /* Decode */ struct resource res = resource_open(path); - struct ttf_decode_result result = ttf_decode(scratch.arena, res.data, point_size, g_font_codes, ARRAY_COUNT(g_font_codes)); - resource_close(res); + struct ttf_decode_result result = ttf_decode(scratch.arena, resource_get_data(&res), point_size, g_font_codes, ARRAY_COUNT(g_font_codes)); + resource_close(&res); /* Send texture to GPU */ struct renderer_texture texture = renderer_texture_alloc(RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, V2I32(result.image_data.width, result.image_data.height), result.image_data.pixels); diff --git a/src/inc.c b/src/inc.c index 8b733799..21a4664b 100644 --- a/src/inc.c +++ b/src/inc.c @@ -3,8 +3,8 @@ /* This is the file that actually includes binary data meant to be embedded in * the executable. Embedded files should be added as dependencies to this source - * file via the build system to ensure this unit is recompiled upon changes to - * an embedded file. */ + * file via the build system to ensure this translation unit is recompiled upon + * changes to an embedded file. */ #if RESOURCES_EMBEDDED INCBIN_INCLUDE(res_tar, INCBIN_DIR "res.tar"); @@ -13,9 +13,3 @@ struct string inc_res_tar(void) return INCBIN_GET(res_tar); } #endif - -INCBIN_INCLUDE(shaders_tar, INCBIN_DIR "shaders.tar"); -struct string inc_shaders_tar(void) -{ - return INCBIN_GET(shaders_tar); -} diff --git a/src/inc.h b/src/inc.h index 62bc1ea9..8cba4b5a 100644 --- a/src/inc.h +++ b/src/inc.h @@ -5,6 +5,4 @@ struct string inc_res_tar(void); #endif -struct string inc_shaders_tar(void); - #endif diff --git a/src/memory.h b/src/memory.h index df204576..28a3999a 100644 --- a/src/memory.h +++ b/src/memory.h @@ -8,12 +8,11 @@ #define MEMCPY_STRUCT(ptr_dst, ptr_src) MEMCPY((ptr_dst), (ptr_src), sizeof(*(ptr_dst))) #define MEMCPY(dst, src, count) memcpy((dst), (src), (count)) -#define MEMCMP_STRUCT(p1, p2) MEMCMP((p1), (p2), sizeof(*p1)) -#define MEMCMP(p1, p2, n) memcmp((p1), (p2), (n)) - #define MEMEQ_STRUCT(p1, p2) MEMEQ((p1), (p2), sizeof(*p1)) #define MEMEQ(p1, p2, n) (MEMCMP((p1), (p2), (n)) == 0) +#define MEMCMP(p1, p2, n) memcmp((p1), (p2), (n)) + #define MEMSET(ptr, val, count) memset((ptr), (val), (count)) #if CRTLIB diff --git a/src/renderer_d3d11.c b/src/renderer_d3d11.c index 6ac1ac11..885cc04f 100644 --- a/src/renderer_d3d11.c +++ b/src/renderer_d3d11.c @@ -1,4 +1,5 @@ #include "renderer.h" +#include "resource.h" #include "sys.h" #include "memory.h" #include "arena.h" @@ -6,7 +7,6 @@ #include "string.h" #include "math.h" #include "inc.h" -#include "tar.h" #include "sprite.h" #include "log.h" @@ -35,10 +35,15 @@ struct dx11_shader { enum shader_kind kind; + b32 valid; /* Is this shader allocated */ u32 vertex_size; ID3D11InputLayout *input_layout; ID3D11VertexShader *vs; ID3D11PixelShader *ps; + +#if RESOURCE_RELOADING + struct sys_datetime last_modified_load_attempt; /* The last modified time of the shader src file that a load has been attempted on */ +#endif }; struct dx11_constant_buffer_data { @@ -127,6 +132,7 @@ struct handle_store { }; struct dx11_shader_desc { + enum shader_kind kind; char *name_cstr; u32 vertex_size; D3D11_INPUT_ELEMENT_DESC input_layout_desc[64]; /* NULL terminated array */ @@ -134,7 +140,6 @@ struct dx11_shader_desc { GLOBAL struct { struct arena arena; - struct tar_archive shaders_archive; /* Tar archive including shader sources */ ID3D11Device *dev; ID3D11DeviceContext *devcon; @@ -192,26 +197,14 @@ INTERNAL void send_constant_buffer_data(ID3D11Buffer *buffer, struct mat4x4 vp) * Shader * ========================== */ - /* TODO: don't do fatal error, just don't use shader */ -INTERNAL void process_shader_compilation_error(ID3DBlob *error_blob) -{ - struct temp_arena scratch = scratch_begin_no_conflict(); - struct string error_prefix = string_copy(scratch.arena, LIT("Failed to compile shader:\n")); - if (error_blob) { - char *compile_error_cstr = (char *)ID3D10Blob_GetBufferPointer(error_blob); - struct string error_msg = string_cat(scratch.arena, error_prefix, string_from_cstr_no_limit(compile_error_cstr)); - sys_panic(error_msg); - } - scratch_end(scratch); -} - INTERNAL void init_shader_table(void) { MEMZERO_ARRAY(G.shader_info); /* Triangle shader layout */ G.shader_info[SHADER_TRIANGLE] = (struct dx11_shader_desc) { - "shaders/triangle.hlsl", + SHADER_TRIANGLE, + "res/shaders/triangle.hlsl", sizeof(struct triangle_shader_vertex), { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, @@ -222,7 +215,8 @@ INTERNAL void init_shader_table(void) /* Grid shader layout */ G.shader_info[SHADER_GRID] = (struct dx11_shader_desc) { - "shaders/grid.hlsl", + SHADER_GRID, + "res/shaders/grid.hlsl", sizeof(struct grid_shader_vertex), { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, @@ -234,16 +228,14 @@ INTERNAL void init_shader_table(void) }; } -INTERNAL void shader_init(struct dx11_shader *shader, enum shader_kind kind) +/* If shader compilation fails, then error string is returned allocated on `arena` */ +INTERNAL struct string shader_alloc(struct arena *arena, struct dx11_shader *shader, struct dx11_shader_desc *shader_desc, struct resource *src_res) { __prof; - MEMZERO_STRUCT(shader); + struct temp_arena scratch = scratch_begin(arena); + struct string error_str = ZI; - struct temp_arena scratch = scratch_begin_no_conflict(); - const struct dx11_shader_desc *shader_desc = &G.shader_info[kind]; - struct string name = string_from_cstr_no_limit(shader_desc->name_cstr); - - shader->kind = kind; + shader->kind = shader_desc->kind; shader->vertex_size = shader_desc->vertex_size; u32 flags = D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; @@ -254,50 +246,126 @@ INTERNAL void shader_init(struct dx11_shader *shader, enum shader_kind kind) #endif /* Compile shader */ - ID3DBlob *vs_blob, *ps_blob; + ID3DBlob *vs_blob = NULL; + ID3DBlob *ps_blob = NULL; + ID3DBlob *error_blob = NULL; + b32 success = false; { - struct tar_entry *tar_entry = tar_get(&G.shaders_archive, name); - if (!tar_entry) { - sys_panic(string_format(scratch.arena, - LIT("Could not find shader \"%F\""), - FMT_STR(name))); - } - struct string shader_src = tar_entry->data; - - - logf_info("Compiling shader \"%F\"", FMT_STR(name)); + struct string shader_src = resource_get_data(src_res); + logf_info("Compiling shader \"%F\"", FMT_STR(resource_get_name(src_res))); /* Compile shader */ /* TODO: pre-compile shaders w/ FXC? */ - ID3DBlob *error_blob; - HRESULT v_res = D3DCompile(shader_src.text, shader_src.len, NULL, NULL, NULL, "vs_main", "vs_5_0", flags, 0, &vs_blob, &error_blob); - if (FAILED(v_res)) { - process_shader_compilation_error(error_blob); - } - HRESULT p_res = D3DCompile(shader_src.text, shader_src.len, NULL, NULL, NULL, "ps_main", "ps_5_0", flags, 0, &ps_blob, &error_blob); - if (FAILED(p_res)) { - process_shader_compilation_error(error_blob); + HRESULT hr = D3DCompile(shader_src.text, shader_src.len, NULL, NULL, NULL, "vs_main", "vs_5_0", flags, 0, &vs_blob, &error_blob); + if (SUCCEEDED(hr)) { + ID3D11Device_CreateVertexShader(G.dev, ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), NULL, &shader->vs); + hr = D3DCompile(shader_src.text, shader_src.len, NULL, NULL, NULL, "ps_main", "ps_5_0", flags, 0, &ps_blob, &error_blob); + if (SUCCEEDED(hr)) { + ID3D11Device_CreatePixelShader(G.dev, ID3D10Blob_GetBufferPointer(ps_blob), ID3D10Blob_GetBufferSize(ps_blob), NULL, &shader->ps); + success = true; + } } } - /* Get number of device layout elements from NULL terminated array */ - u32 elem_count = 0; - for (; elem_count < ARRAY_COUNT(shader_desc->input_layout_desc); ++elem_count) { - const D3D11_INPUT_ELEMENT_DESC *d = &shader_desc->input_layout_desc[elem_count]; - if (d->SemanticName == NULL) { - break; + if (success && !error_blob) { + /* Get number of device layout elements from NULL terminated array */ + u32 elem_count = 0; + for (; elem_count < ARRAY_COUNT(shader_desc->input_layout_desc); ++elem_count) { + const D3D11_INPUT_ELEMENT_DESC *d = &shader_desc->input_layout_desc[elem_count]; + if (d->SemanticName == NULL) { + break; + } + } + + /* Create device layout */ + ID3D11Device_CreateInputLayout(G.dev, shader_desc->input_layout_desc, elem_count, ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), &shader->input_layout); + } else { + error_str = LIT("Unknown error"); + if (error_blob) { + u64 error_cstr_len = ID3D10Blob_GetBufferSize(error_blob); + char *error_cstr = (char *)ID3D10Blob_GetBufferPointer(error_blob); + error_str = string_copy(arena, string_from_cstr(error_cstr, error_cstr_len)); } } - /* Create device layout */ - ID3D11Device_CreateInputLayout(G.dev, shader_desc->input_layout_desc, elem_count, ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), &shader->input_layout); + if (vs_blob) { + ID3D10Blob_Release(vs_blob); + } + if (ps_blob) { + ID3D10Blob_Release(ps_blob); + } + if (error_blob) { + ID3D10Blob_Release(error_blob); + } - /* Create shader */ - ID3D11Device_CreateVertexShader(G.dev, ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), NULL, &shader->vs); - ID3D11Device_CreatePixelShader(G.dev, ID3D10Blob_GetBufferPointer(ps_blob), ID3D10Blob_GetBufferSize(ps_blob), NULL, &shader->ps); + shader->valid = true; - ID3D10Blob_Release(vs_blob); - ID3D10Blob_Release(ps_blob); + scratch_end(scratch); + return error_str; +} +INTERNAL void shader_release(struct dx11_shader *shader) +{ + __prof; + if (shader->vs) { + ID3D11VertexShader_Release(shader->vs); + } + if (shader->ps) { + ID3D11PixelShader_Release(shader->ps); + } + if (shader->input_layout) { + ID3D11InputLayout_Release(shader->input_layout); + } +} + +INTERNAL void reload_shaders(void) +{ + __prof; + struct temp_arena scratch = scratch_begin_no_conflict(); + for (u32 i = SHADER_NONE + 1; i < NUM_SHADERS; ++i) { + struct dx11_shader_desc *desc = &G.shader_info[i]; + struct string name = string_from_cstr_no_limit(desc->name_cstr); + if (!resource_exists(name)) { + sys_panic(string_format(scratch.arena, LIT("Could not find shader \"%F\""), FMT_STR(name))); + } + struct resource src_res = resource_open(name); + { + struct dx11_shader *old_shader = &G.shaders[i]; + b32 should_load = !old_shader->valid; +#if RESOURCE_RELOADING + struct sys_datetime last_modified = resource_get_time(&src_res).modified; + if (!MEMEQ_STRUCT(&last_modified, &old_shader->last_modified_load_attempt)) { + should_load = true; + } + old_shader->last_modified_load_attempt = last_modified; +#endif + if (should_load) { + struct dx11_shader new_shader = ZI; + struct string error = shader_alloc(scratch.arena, &new_shader, desc, &src_res); +#if RESOURCE_RELOADING + new_shader.last_modified_load_attempt = last_modified; +#endif + if (error.len == 0) { + if (old_shader->valid) { + shader_release(old_shader); + } + *old_shader = new_shader; + } else { + struct string error_msg = string_format(scratch.arena, + LIT("Failed to compile shader \"%F\":\n\n%F"), + FMT_STR(name), + FMT_STR(error)); + if (old_shader->valid) { + log_error(error_msg); + } else { + sys_panic(error_msg); + } + shader_release(&new_shader); + } + } + } + resource_close(&src_res); + + } scratch_end(scratch); } @@ -315,12 +383,6 @@ struct renderer_startup_receipt renderer_startup(struct sys_window *window) G.textures_mutex = sys_mutex_alloc(); G.textures_arena = arena_alloc(GIGABYTE(64)); - /* Load shader archive */ - struct string embedded_data = inc_shaders_tar(); - if (embedded_data.len > 0) { - G.shaders_archive = tar_parse(&G.arena, embedded_data, LIT("shaders/")); - } - /* Initialize shader table */ init_shader_table(); @@ -518,10 +580,7 @@ struct renderer_startup_receipt renderer_startup(struct sys_window *window) /* Init shaders */ logf_info("Compiling shaders"); - for (u32 i = SHADER_NONE + 1; i < NUM_SHADERS; ++i) { - /* Create shader */ - shader_init(&G.shaders[i], i); - } + reload_shaders(); logf_info("Finished compiling shaders"); return (struct renderer_startup_receipt) { 0 }; @@ -849,6 +908,18 @@ void renderer_backbuffer_present(i32 vsync) IDXGISwapChain1_Present(G.swapchain, vsync, 0); __profframe(0); } + +#if RESOURCE_RELOADING + { + i64 now_ns = sys_time_ns(); + const i64 reload_interval_ns = NS_FROM_SECONDS(0.1); + static f32 last_reload_ns = 0; + if (now_ns >= (last_reload_ns + reload_interval_ns)) { + reload_shaders(); + last_reload_ns = now_ns; + } + } +#endif } /* ========================== * diff --git a/src/resource.c b/src/resource.c index 55c06207..e5a4f352 100644 --- a/src/resource.c +++ b/src/resource.c @@ -34,6 +34,49 @@ struct resource_startup_receipt resource_startup(void) return (struct resource_startup_receipt) { 0 }; } +struct resource resource_open(struct string path) +{ + __prof; +#if RESOURCES_EMBEDDED + struct resource res = ZI; + struct tar_entry *entry = tar_get(&G.archive, path); + if (entry) { + res._data = entry->data; + res._file_name = entry->file_name; + } + return res; +#else + struct resource res = ZI; + if (path.len < ARRAY_COUNT(res._file_name_text)) { + struct sys_file file = sys_file_open_read_wait(path); + struct sys_file_map file_map = sys_file_map_open_read(file); + struct string data = sys_file_map_data(file_map); + + res._data = data; + res._file = file; + res._file_map = file_map; + res._file_name_len = path.len; + MEMCPY(res._file_name_text, path.text, path.len); + } else { + ASSERT(false); + } + return res; +#endif +} + +#if !RESOURCES_EMBEDDED +void resource_close(struct resource *res_ptr) +{ + sys_file_map_close(res_ptr->_file_map); + sys_file_close(res_ptr->_file); +} + +struct sys_file_time resource_get_time(struct resource *res_ptr) +{ + return sys_file_get_time(res_ptr->_file); +} +#endif + b32 resource_exists(struct string path) { __prof; @@ -44,31 +87,3 @@ b32 resource_exists(struct string path) return sys_is_file(path); #endif } - -struct resource resource_open(struct string path) -{ - __prof; -#if RESOURCES_EMBEDDED - struct tar_entry *entry = tar_get(&G.archive, path); - return (struct resource) { - .data = entry ? entry->data : STRING(0, 0) - }; -#else - struct sys_file file = sys_file_open_read_wait(path); - struct sys_file_map file_map = sys_file_map_open_read(file); - struct string data = sys_file_map_data(file_map); - return (struct resource) { - .data = data, - .file = file, - .file_map = file_map - }; -#endif -} - -#if !RESOURCES_EMBEDDED -void resource_close(struct resource res) -{ - sys_file_map_close(res.file_map); - sys_file_close(res.file); -} -#endif diff --git a/src/resource.h b/src/resource.h index 9fbc3b40..1a02703c 100644 --- a/src/resource.h +++ b/src/resource.h @@ -3,28 +3,38 @@ #include "sys.h" -/* Represents raw bytes that can back a resource. This can be file data or embedded - * data in the executable. */ +/* A resource contains data that can be retrieved globally by name. + * If enabled during compilation, resource data is embedded in the + * executable. Otherwise each resource represents a file on disk. */ struct resource { - struct string data; - - /* Internal */ -#if !RESOURCES_EMBEDDED - struct sys_file file; - struct sys_file_map file_map; + struct string _data; +#if RESOURCES_EMBEDDED + struct string _file_name; +#else + struct sys_file _file; + struct sys_file_map _file_map; + u8 _file_name_text[256]; + u8 _file_name_len; #endif }; struct resource_startup_receipt { i32 _; }; struct resource_startup_receipt resource_startup(void); -b32 resource_exists(struct string path); + struct resource resource_open(struct string path); +#define resource_get_data(res_ptr) (res_ptr)->_data + #if RESOURCES_EMBEDDED -/* Embedded resources don't need to be closed */ -#define resource_close(res) (UNUSED)res + #define resource_close(res_ptr) (UNUSED)res_ptr + #define resource_get_time(res_ptr) ((UNUSED)res_ptr, (struct sys_file_time) ZI) + #define resource_get_name(res_ptr) (res_ptr)->_file_name #else -void resource_close(struct resource res); + void resource_close(struct resource *res_ptr); + struct sys_file_time resource_get_time(struct resource *res_ptr); + #define resource_get_name(res_ptr) STRING((res_ptr)->_file_name_len, (res_ptr)->_file_name_text) #endif +b32 resource_exists(struct string path); + #endif diff --git a/src/scratch.h b/src/scratch.h index 66b35b0d..6c7659bd 100644 --- a/src/scratch.h +++ b/src/scratch.h @@ -42,14 +42,15 @@ INLINE void scratch_dbg_push(struct scratch_ctx *ctx, struct temp_arena *temp) #endif } -/* Any arena parameters in the calling function's context should be passed into this - * function as a potential `conflict`. This is to prevent friction when the - * context's arena is itself a scratch arena (since parameterized arenas are - * often used to allocate persistent results for the caller). +/* Any arena parameters in the calling function's scope should be passed into this + * function as a potential "conflict". This is to prevent friction in case the + * passed arena is itself a scratch arena from another scope (since + * parameterized arenas are often used to allocate persistent results for the + * caller). * * Use `scratch_begin_no_conflict` instead if there is no arena in the current - * context that could potentially be a scratch arena. */ -#define scratch_begin(c) _scratch_begin(c) + * scope that could potentially be a scratch arena from another scope. */ +#define scratch_begin(potential_conflict) _scratch_begin(potential_conflict) INLINE struct temp_arena _scratch_begin(struct arena *potential_conflict) { @@ -72,7 +73,7 @@ INLINE struct temp_arena _scratch_begin(struct arena *potential_conflict) /* This macro declares an unused "arena" variable that will error if an existing "arena" * variable is present (due to shadowing). This is for catching obvious cases of * `scratch_begin_no_conflict` getting called when an `arena` variable already - * exists in the caller's context (`scratch_begin(arena)` should be called + * exists in the caller's scope (`scratch_begin(arena)` should be called * instead). */ #define scratch_begin_no_conflict() \ _scratch_begin_no_conflict(); \ diff --git a/src/sim_ent.c b/src/sim_ent.c index 1fac6f04..5faad343 100644 --- a/src/sim_ent.c +++ b/src/sim_ent.c @@ -533,7 +533,6 @@ void sim_ent_apply_torque(struct sim_ent *ent, f32 torque) struct string sim_ent_get_tile_chunk_data(struct sim_ent *ent) { - DEBUGBREAKABLE; (UNUSED)ent; struct string res = ZI; return res; @@ -541,7 +540,6 @@ struct string sim_ent_get_tile_chunk_data(struct sim_ent *ent) void sim_ent_set_tile_chunk_data(struct sim_ent *ent, struct string data) { - DEBUGBREAKABLE; (UNUSED)ent; (UNUSED)data; } diff --git a/src/sound.c b/src/sound.c index 90b1471c..0d614329 100644 --- a/src/sound.c +++ b/src/sound.c @@ -105,8 +105,8 @@ INTERNAL WORK_TASK_FUNC_DEF(sound_load_asset_task, vparams) /* Decode */ struct resource sound_rs = resource_open(path); - struct mp3_decode_result decoded = mp3_decode(scratch.arena, sound_rs.data, decode_flags); - resource_close(sound_rs); + struct mp3_decode_result decoded = mp3_decode(scratch.arena, resource_get_data(&sound_rs), decode_flags); + resource_close(&sound_rs); if (!decoded.success) { success = false; diff --git a/src/sprite.c b/src/sprite.c index 2673ddc7..691007c4 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -356,11 +356,11 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta struct ase_decode_image_result decoded = ZI; if (resource_exists(path)) { struct resource texture_rs = resource_open(path); - decoded = ase_decode_image(scratch.arena, texture_rs.data); + decoded = ase_decode_image(scratch.arena, resource_get_data(&texture_rs)); #if RESOURCE_RELOADING - n->initial_resource_file_modified_time = sys_file_get_time(texture_rs.file).modified; + n->initial_resource_file_modified_time = resource_get_time(&texture_rs).modified; #endif - resource_close(texture_rs); + resource_close(&texture_rs); /* Initialize */ n->texture = arena_push(&n->arena, struct sprite_texture); @@ -660,11 +660,11 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag) struct ase_decode_sheet_result decoded = ZI; if (resource_exists(path)) { struct resource sheet_rs = resource_open(path); - decoded = ase_decode_sheet(scratch.arena, sheet_rs.data); + decoded = ase_decode_sheet(scratch.arena, resource_get_data(&sheet_rs)); #if RESOURCE_RELOADING - n->initial_resource_file_modified_time = sys_file_get_time(sheet_rs.file).modified; + n->initial_resource_file_modified_time = resource_get_time(&sheet_rs).modified; #endif - resource_close(sheet_rs); + resource_close(&sheet_rs); /* Initialize */ n->sheet = arena_push(&n->arena, struct sprite_sheet); @@ -904,6 +904,8 @@ INTERNAL void *data_from_tag_internal(struct sprite_scope *scope, struct sprite_ } } + /* FIXME: Spinlock until resource loaded if async */ + return res; } @@ -1085,7 +1087,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg) current_file_time = sys_file_get_time(file).modified; sys_file_close(file); } - file_changed = MEMCMP_STRUCT(&n->initial_resource_file_modified_time, ¤t_file_time) != 0; + file_changed = !MEMEQ_STRUCT(&n->initial_resource_file_modified_time, ¤t_file_time); if (file_changed) { switch (n->kind) { case CACHE_NODE_KIND_TEXTURE: { diff --git a/src/sys_win32.c b/src/sys_win32.c index 99863616..f0c06881 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -1882,8 +1882,8 @@ void sys_panic(struct string msg) { if (atomic_i32_eval_compare_exchange(&G.panicking, 0, 1) == 0) { log_panic(msg); - ASSERT(false); + /* FIXME: Atomic panic str */ wchar_t *wstr = G.panic_wstr; u64 wstr_len = 0; @@ -1911,6 +1911,11 @@ void sys_panic(struct string msg) wstr[wstr_len] = 0; +#if RTC + MessageBoxExW(NULL, wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); + ASSERT(false); +#endif + WRITE_BARRIER(); SetEvent(G.panic_event);