From 86b12bf909ea24765e41be385ceb0244ebd136e3 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 9 Jan 2026 15:37:23 -0600 Subject: [PATCH] tile sprite testing --- src/ase/ase.c | 4 - src/base/base.cgh | 8 +- src/base/base_string.c | 32 +++++ src/base/base_string.h | 8 ++ src/base/base_tweak.c | 2 +- src/base/base_util.h | 26 ---- src/glyph_cache/glyph_cache.h | 2 +- src/gpu/gpu_common.c | 51 ++++++- src/gpu/gpu_common.h | 12 +- src/gpu/gpu_core.h | 3 + src/gpu/gpu_dx12/gpu_dx12_core.c | 5 +- src/meta/meta.c | 3 +- src/pp/pp_res/sprite/tiles.ase | 3 + src/pp/pp_res/sprite/tiles_real.ase | 3 + src/pp/pp_vis/pp_vis_core.c | 40 +++--- src/pp/pp_vis/pp_vis_gpu.g | 67 +++++---- src/pp/pp_vis/pp_vis_shared.cgh | 3 +- src/sprite/sprite.c | 212 +++++++++++++++++++++++++++- src/sprite/sprite.h | 80 ++++++++++- src/sprite/sprite_shared.cgh | 10 +- src/ui/ui_core.c | 23 ++- src/ui/ui_core.h | 4 +- 22 files changed, 476 insertions(+), 125 deletions(-) create mode 100644 src/pp/pp_res/sprite/tiles.ase create mode 100644 src/pp/pp_res/sprite/tiles_real.ase diff --git a/src/ase/ase.c b/src/ase/ase.c index 9a8007dd..d72583bc 100644 --- a/src/ase/ase.c +++ b/src/ase/ase.c @@ -1,8 +1,4 @@ -// -// Aseprite (.ase) file parser -// // DEFLATE decoder based on Handmade Hero's png parser -// //////////////////////////////////////////////////////////// //~ Shared constants diff --git a/src/base/base.cgh b/src/base/base.cgh index a76a6c2a..86dc647b 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -769,14 +769,16 @@ u64 MixU64s(u64 seed_a, u64 seed_b) } #if IsLanguageC + #define Fnv64Basis 0xCBF29CE484222325 + // FNV-1a parameters for different hash sizes: // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters - Inline u64 HashFnv64(u64 seed, String s) + Inline u64 HashFnv64(u64 seed, String str) { u64 hash = seed; - for (u64 i = 0; i < s.len; ++i) + for (u64 i = 0; i < str.len; ++i) { - hash ^= (u8)s.text[i]; + hash ^= (u8)str.text[i]; hash *= 0x100000001B3; } return hash; diff --git a/src/base/base_string.c b/src/base/base_string.c index cb0eb222..16b1a143 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -497,6 +497,38 @@ String PathFromString(Arena *arena, String str, u8 path_delimiter) return result; } +//////////////////////////////////////////////////////////// +//~ Hash helpers + +u64 HashStringEx(u64 seed, String str) +{ + u64 result = HashFnv64(seed, str); + result = MixU64(result); + return result; +} + +u64 HashString(String str) +{ + return HashStringEx(Fnv64Basis, str); +} + +u64 HashF_(String fmt, ...) +{ + u64 result = 0; + TempArena scratch = BeginScratchNoConflict(); + { + va_list args; + va_start(args, fmt); + { + String str = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args)); + result = HashString(str); + } + va_end(args); + } + EndScratch(scratch); + return result; +} + //////////////////////////////////////////////////////////// //~ String list helpers diff --git a/src/base/base_string.h b/src/base/base_string.h index 7ffc08e2..55213546 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -102,6 +102,14 @@ b32 StringEndsWith(String str, String substring); String StringFromArray(Arena *arena, StringArray a); String PathFromString(Arena *arena, String str, u8 path_delimiter); +//////////////////////////////////////////////////////////// +//~ Hash helpers + +u64 HashStringEx(u64 seed, String str); +u64 HashString(String str); +u64 HashF_(String fmt, ...); +#define HashF(fmt_cstr, ...) HashF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) + //////////////////////////////////////////////////////////// //~ Trimming helpers diff --git a/src/base/base_tweak.c b/src/base/base_tweak.c index 084389f8..50454d4c 100644 --- a/src/base/base_tweak.c +++ b/src/base/base_tweak.c @@ -13,7 +13,7 @@ String TweakEx(Arena *arena, TweakVar desc, b32 update_existing) { String result = Zi; Arena *perm = PermArena(); - u64 hash = MixU64(HashFnv64(Fnv64Basis, desc.name)); + u64 hash = HashString(desc.name); TweakVarEntryBin *bin = &Base.tweak.entry_bins[hash % countof(Base.tweak.entry_bins)]; LockTicketMutex(&Base.tweak.tm); { diff --git a/src/base/base_util.h b/src/base/base_util.h index 7b8c074a..5c6d5769 100644 --- a/src/base/base_util.h +++ b/src/base/base_util.h @@ -1,8 +1,3 @@ -//////////////////////////////////////////////////////////// -//~ Hash types - -#define Fnv64Basis 0xCBF29CE484222325 - //////////////////////////////////////////////////////////// //~ Mergesort types @@ -41,27 +36,6 @@ Struct(Dict) DictEntry *last; }; -//////////////////////////////////////////////////////////// -//~ Hash utils - -#define HashF(fmt_cstr, ...) HashF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) -Inline u64 HashF_(String fmt, ...) -{ - u64 result = 0; - TempArena scratch = BeginScratchNoConflict(); - { - va_list args; - va_start(args, fmt); - { - String str = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args)); - result = HashFnv64(Fnv64Basis, str); - } - va_end(args); - } - EndScratch(scratch); - return result; -} - //////////////////////////////////////////////////////////// //~ Mergesort utils diff --git a/src/glyph_cache/glyph_cache.h b/src/glyph_cache/glyph_cache.h index d39f3d05..81744500 100644 --- a/src/glyph_cache/glyph_cache.h +++ b/src/glyph_cache/glyph_cache.h @@ -91,7 +91,7 @@ Struct(GC_Run) }; //////////////////////////////////////////////////////////// -//~ Cmd types +//~ Async cmd types Struct(GC_Cmd) { diff --git a/src/gpu/gpu_common.c b/src/gpu/gpu_common.c index 8005afd4..acf947f1 100644 --- a/src/gpu/gpu_common.c +++ b/src/gpu/gpu_common.c @@ -19,10 +19,40 @@ void G_BootstrapCommon(void) G.quad_indices = G_IdxBuff16(quad_indices); } - // Init point sampler + // Init point clamp sampler { - G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint); - G.basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler); + G_ResourceHandle pt_sampler = G_PushSampler( + gpu_perm, cl, + .filter = G_Filter_MinMagMipPoint, + .x = G_AddressMode_Clamp, + .y = G_AddressMode_Clamp, + .z = G_AddressMode_Clamp, + ); + G.basic_point_clamp_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler); + } + + // Init point wrap sampler + { + G_ResourceHandle pt_sampler = G_PushSampler( + gpu_perm, cl, + .filter = G_Filter_MinMagMipPoint, + .x = G_AddressMode_Wrap, + .y = G_AddressMode_Wrap, + .z = G_AddressMode_Wrap, + ); + G.basic_point_wrap_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler); + } + + // Init blank texture + { + G_ResourceHandle blank_tex = G_PushTexture2D( + gpu_perm, cl, + G_Format_R8G8B8A8_Uint, + VEC2I32(8, 8), + G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, + .flags = G_ResourceFlag_ZeroMemory + ); + G.blank_tex = G_PushTexture2DRef(gpu_perm, blank_tex); } // Init noise texture @@ -46,7 +76,6 @@ void G_BootstrapCommon(void) noise_data.text, noise_dims, RNG3I32(VEC3I32(0, 0, 0), noise_dims) ); - G.basic_noise = G_PushTexture3DRef(gpu_perm, noise_tex); } @@ -101,9 +130,19 @@ G_IndexBufferDesc G_QuadIndices(void) return G.quad_indices; } -G_SamplerStateRef G_BasicSampler(void) +G_SamplerStateRef G_BasicPointClampSampler(void) { - return G.basic_sampler; + return G.basic_point_clamp_sampler; +} + +G_SamplerStateRef G_BasicPointWrapSampler(void) +{ + return G.basic_point_wrap_sampler; +} + +G_Texture2DRef G_BlankTexture2D(void) +{ + return G.blank_tex; } G_Texture3DRef G_BasicNoiseTexture(void) diff --git a/src/gpu/gpu_common.h b/src/gpu/gpu_common.h index d498f85a..3a791fe8 100644 --- a/src/gpu/gpu_common.h +++ b/src/gpu/gpu_common.h @@ -5,7 +5,9 @@ Struct(G_Ctx) { // Common shared resources G_IndexBufferDesc quad_indices; - G_SamplerStateRef basic_sampler; + G_SamplerStateRef basic_point_clamp_sampler; + G_SamplerStateRef basic_point_wrap_sampler; + G_Texture2DRef blank_tex; G_Texture3DRef basic_noise; }; @@ -26,22 +28,20 @@ void G_BootstrapCommon(void); //~ Utils //- Arena - G_ArenaHandle G_PermArena(void); //- Push resource from cpu - G_ResourceHandle G_PushBufferFromCpuCopy_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc); #define G_PushBufferFromCpuCopy(_arena, _cl, _src, ...) \ G_PushBufferFromCpuCopy_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ }) //- Viewport / scissor - Rng3 G_ViewportFromTexture(G_ResourceHandle texture); Rng2 G_ScissorFromTexture(G_ResourceHandle texture); //- Shared resources - G_IndexBufferDesc G_QuadIndices(void); -G_SamplerStateRef G_BasicSampler(void); +G_SamplerStateRef G_BasicPointClampSampler(void); +G_SamplerStateRef G_BasicPointWrapSampler(void); +G_Texture2DRef G_BlankTexture2D(void); G_Texture3DRef G_BasicNoiseTexture(void); diff --git a/src/gpu/gpu_core.h b/src/gpu/gpu_core.h index d26ba2bc..9214552d 100644 --- a/src/gpu/gpu_core.h +++ b/src/gpu/gpu_core.h @@ -271,6 +271,7 @@ Enum(G_Layout) G_Layout_DirectComputeQueue_ShaderReadWrite, // D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS G_Layout_DirectComputeQueue_ShaderRead, // D3D12_BARRIER_LAYOUT_SHADER_RESOURCE G_Layout_DirectComputeQueue_CopyRead, // D3D12_BARRIER_LAYOUT_COPY_SOURCE + G_Layout_DirectComputeQueue_CopyWrite, // D3D12_BARRIER_LAYOUT_COPY_DEST ////////////////////////////// //- Direct queue @@ -281,6 +282,7 @@ Enum(G_Layout) G_Layout_DirectQueue_ShaderReadWrite, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS G_Layout_DirectQueue_ShaderRead, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE G_Layout_DirectQueue_CopyRead, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE + G_Layout_DirectQueue_CopyWrite, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_DEST G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite, // D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE G_Layout_DirectQueue_DepthStencilRead, // D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ @@ -295,6 +297,7 @@ Enum(G_Layout) G_Layout_ComputeQueue_ShaderReadWrite, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS G_Layout_ComputeQueue_ShaderRead, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE G_Layout_ComputeQueue_CopyRead, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE + G_Layout_ComputeQueue_CopyWrite, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_DEST }; // Barrier will execute after previous stages specified by `stage_prev`, and before next stages specified by `stage_next`. diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index 6cbcef21..4ba6b8df 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -425,11 +425,13 @@ D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout) [G_Layout_DirectComputeQueue_ShaderRead_CopyRead] = D3D12_BARRIER_LAYOUT_GENERIC_READ, [G_Layout_DirectComputeQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_SHADER_RESOURCE, [G_Layout_DirectComputeQueue_CopyRead] = D3D12_BARRIER_LAYOUT_COPY_SOURCE, + [G_Layout_DirectComputeQueue_CopyWrite] = D3D12_BARRIER_LAYOUT_COPY_DEST, [G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON, [G_Layout_DirectQueue_ShaderReadWrite] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS, [G_Layout_DirectQueue_ShaderRead_CopyRead_DepthStencilRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ, [G_Layout_DirectQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE, [G_Layout_DirectQueue_CopyRead] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE, + [G_Layout_DirectQueue_CopyWrite] = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_DEST, [G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite] = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE, [G_Layout_DirectQueue_DepthStencilRead] = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ, [G_Layout_DirectQueue_RenderTargetWrite] = D3D12_BARRIER_LAYOUT_RENDER_TARGET, @@ -438,6 +440,7 @@ D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout) [G_Layout_ComputeQueue_ShaderRead_CopyRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ, [G_Layout_ComputeQueue_ShaderRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE, [G_Layout_ComputeQueue_CopyRead] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE, + [G_Layout_ComputeQueue_CopyWrite] = D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_DEST, }; return translate[layout]; }; @@ -447,7 +450,7 @@ D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout) G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc) { - u64 hash = MixU64(HashFnv64(Fnv64Basis, StringFromStruct(&desc))); + u64 hash = HashString(StringFromStruct(&desc)); // Fetch pipeline from cache G_D12_Pipeline *pipeline = 0; diff --git a/src/meta/meta.c b/src/meta/meta.c index 7e7897b1..5e336e93 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -283,7 +283,8 @@ void BuildEntryPoint(WaveLaneCtx *lane) for (StringListNode *n = check_files.first; n; n = n->next) { String file = n->s; - new_metahash = MixU64s(HashFnv64(new_metahash, file), OS_LastWriteTimestampFromPath(file)); + new_metahash = MixU64s(new_metahash, OS_LastWriteTimestampFromPath(file)); + new_metahash = HashStringEx(new_metahash , file); } } diff --git a/src/pp/pp_res/sprite/tiles.ase b/src/pp/pp_res/sprite/tiles.ase new file mode 100644 index 00000000..bb9158a3 --- /dev/null +++ b/src/pp/pp_res/sprite/tiles.ase @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01d7077a1b43124b2931a66a9e5bafc4ee53edfd33b65fa14ced182d6a79d4e6 +size 501 diff --git a/src/pp/pp_res/sprite/tiles_real.ase b/src/pp/pp_res/sprite/tiles_real.ase new file mode 100644 index 00000000..4a56baac --- /dev/null +++ b/src/pp/pp_res/sprite/tiles_real.ase @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93634d9cc0c63913a4100f48e6d096814baa0694bc108b799b73db5a0db54a2f +size 501 diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 1a5acd1c..dd4fec65 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -1221,7 +1221,7 @@ void V_TickForever(WaveLaneCtx *lane) { UI_BuildColumnEx(panel->key); } - UI_Push(Tag, panel->key.hash); + UI_Push(Tag, panel->key.v); panel_dfs->cp = UI_PushCP(panel->key); if (!panel->is_organizing_panel && !panel->is_viewport_panel) @@ -1325,7 +1325,7 @@ void V_TickForever(WaveLaneCtx *lane) for (DrawableTab *tab = first_drawable_tab; tab; tab = tab->next) { - UI_Push(Tag, tab->key.hash); + UI_Push(Tag, tab->key.v); UI_BoxReport tab_rep = UI_ReportsFromKey(tab->key).draw; if (tab == first_drawable_tab) @@ -1538,7 +1538,7 @@ void V_TickForever(WaveLaneCtx *lane) UI_SetNext(Flags, UI_BoxFlag_CaptureMouse); UI_PushCP(UI_BuildColumn()); { - UI_Push(Tag, window->key.hash); + UI_Push(Tag, window->key.v); if (window->is_tile_window) { for (S_TileKind tile_kind = 0; tile_kind < S_TileKind_COUNT; ++tile_kind) @@ -1679,7 +1679,7 @@ void V_TickForever(WaveLaneCtx *lane) palette->key = UI_KeyF("command palette"); UI_Checkpoint palette_cp = UI_PushCP(UI_NilKey); { - UI_Push(Tag, palette->key.hash); + UI_Push(Tag, palette->key.v); UI_Key titlebar_key = UI_KeyF("title bar"); UI_BoxReports titlebar_reps = UI_ReportsFromKey(titlebar_key); UI_BoxReports palette_reps = UI_ReportsFromKey(palette->key); @@ -1880,7 +1880,7 @@ void V_TickForever(WaveLaneCtx *lane) UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_CaptureMouse); UI_PushCP(UI_BuildRowEx(item->key)); { - UI_Push(Tag, item->key.hash); + UI_Push(Tag, item->key.v); // Begin spacer UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X); @@ -2816,7 +2816,7 @@ void V_TickForever(WaveLaneCtx *lane) - if (0) + // if (0) { for (S_Ent *bullet = S_FirstEnt(world); bullet->valid; bullet = S_NextEnt(bullet)) { @@ -3163,6 +3163,8 @@ void V_TickForever(WaveLaneCtx *lane) params.xf = frame->xf; params.seed = RandU64FromState(&frame->rand); + params.pt_wrap_sampler = G_BasicPointWrapSampler(); + params.selection_mode = frame->selection_mode; params.equipped_tile = frame->equipped_tile; @@ -3190,27 +3192,27 @@ void V_TickForever(WaveLaneCtx *lane) params.cells = gpu_cells_ref; params.stains = gpu_stains_ref; params.drynesses = gpu_drynesses_ref; + + // Fill tile textures + { + ResourceKey sheet_resource = ResourceKeyFromStore(&P_Resources, Lit("sprite/tiles.ase")); + for (S_TileKind tile_kind = 0; tile_kind < S_TileKind_COUNT; ++tile_kind) + { + String tile_name = S_TileNameFromKind(tile_kind); + SPR_SheetKey sheet = SPR_SheetKeyFromResource(sheet_resource); + SPR_Slice tile_slice = SPR_SliceFromSheet(sheet, tile_name); + params.tile_slices[tile_kind] = tile_slice; + } + } } G_ResourceHandle gpu_params = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStruct(¶ms)); G_StructuredBufferRef gpu_params_ref = G_PushStructuredBufferRef(frame->gpu_arena, gpu_params, V_GpuParams); - // Fill tile textures - { - ResourceKey tiles_resource = ResourceKeyFromStore(&P_Resources, Lit("sprite/tiles.ase")); - for (S_TileKind tile_kind = 0; tile_kind < S_TileKind_COUNT; ++tile_kind) - { - String tile_name = S_TileNameFromKind(tile_kind); - SPR_Key sprite_key = SPR_KeyFromResource(tiles_resource); - SPR_Slice tile_slice = SPR_SliceFromKey(sprite_key, tile_name); - params.tile_slices[tile_kind] = tile_slice; - } - } - // Upload tiles if (tiles_dirty) { LogDebugF("Uploading tiles to gpu"); - G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite); + G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_CopyWrite); G_CopyCpuToTexture( frame->cl, gpu_tiles, VEC3I32(0, 0, 0), diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 563d8109..48523a78 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -88,8 +88,8 @@ ComputeShader2D(V_BackdropCS, 8, 8) f32 half_thickness = 1; f32 half_bounds_size = S_WorldPitch * 0.5; - Vec2 bounds_screen_p0 = mul(params.xf.world_to_draw, Vec3(-half_bounds_size, -half_bounds_size, 1)); - Vec2 bounds_screen_p1 = mul(params.xf.world_to_draw, Vec3(half_bounds_size, half_bounds_size, 1)); + Vec2 bounds_screen_p0 = mul(params.xf.world_to_ui, Vec3(-half_bounds_size, -half_bounds_size, 1)); + Vec2 bounds_screen_p1 = mul(params.xf.world_to_ui, Vec3(half_bounds_size, half_bounds_size, 1)); bool is_in_bounds = ui_pos.x > (bounds_screen_p0.x - half_thickness) && ui_pos.y > (bounds_screen_p0.y - half_thickness) && ui_pos.x < (bounds_screen_p1.x + half_thickness) && @@ -125,8 +125,8 @@ ComputeShader2D(V_BackdropCS, 8, 8) } // Grid outline { - Vec2 grid_screen_p0 = mul(params.xf.world_to_draw, Vec3(floor(world_pos), 1)); - Vec2 grid_screen_p1 = mul(params.xf.world_to_draw, Vec3(ceil(world_pos), 1)); + Vec2 grid_screen_p0 = mul(params.xf.world_to_ui, Vec3(floor(world_pos), 1)); + Vec2 grid_screen_p1 = mul(params.xf.world_to_ui, Vec3(ceil(world_pos), 1)); f32 grid_dist = 100000; grid_dist = min(grid_dist, abs(ui_pos.x - grid_screen_p0.x)); grid_dist = min(grid_dist, abs(ui_pos.x - grid_screen_p1.x)); @@ -137,27 +137,9 @@ ComputeShader2D(V_BackdropCS, 8, 8) result = grid_color; } } - // Tile - { - switch (tile) - { - default: break; - - case S_TileKind_Floor: - { - result = Color_Blue; - } break; - - case S_TileKind_Wall: - { - // result = Color_Red; - result = Color_Black; - } break; - } - } // Axis { - Vec2 zero_screen = mul(params.xf.world_to_draw, Vec3(0, 0, 1)); + Vec2 zero_screen = mul(params.xf.world_to_ui, Vec3(0, 0, 1)); f32 x_dist = abs(ui_pos.x - zero_screen.x); f32 y_dist = abs(ui_pos.y - zero_screen.y); if (y_dist <= half_thickness) @@ -186,6 +168,44 @@ ComputeShader2D(V_BackdropCS, 8, 8) + + // Tile test + // TODO: Remove this + { + if (tile == S_TileKind_Floor) + { + SamplerState wrap_sampler = G_Dereference(params.pt_wrap_sampler); + SPR_Slice slice = params.tile_slices[tile]; + Texture2D tile_tex = G_Dereference(slice.tex); + result = tile_tex.Sample(wrap_sampler, world_pos); + } + else if (tile == S_TileKind_Wall) + { + result = Color_Black; + } + + + // switch (tile) + // { + // default: break; + + // case S_TileKind_Floor: + // { + // result = Color_Blue; + // } break; + + // case S_TileKind_Wall: + // { + // // result = Color_Red; + // result = Color_Black; + // } break; + // } + } + + + + + // TODO: Remove this // Cells test { @@ -370,7 +390,6 @@ ComputeShader(V_SimParticlesCS, 64) u64 seed0 = MixU64(emitter.seed + particle.seq); u64 seed1 = MixU64(seed0); - f32 rand_speed = (f32)((seed0 >> 0) & 0xFFFF) / (f32)0xFFFF; f32 rand_angle = (f32)((seed0 >> 16) & 0xFFFF) / (f32)0xFFFF; f32 rand_offset = (f32)((seed0 >> 32) & 0xFFFF) / (f32)0xFFFF; diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 84002fd7..e12d6ae0 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -53,9 +53,10 @@ Struct(V_GpuParams) G_Texture2DRef target_ro; G_RWTexture2DRef target_rw; V_Xforms xf; - u64 seed; + G_SamplerStateRef pt_wrap_sampler; + V_SelectionMode selection_mode; S_TileKind equipped_tile; diff --git a/src/sprite/sprite.c b/src/sprite/sprite.c index e3a145f0..54fd06c1 100644 --- a/src/sprite/sprite.c +++ b/src/sprite/sprite.c @@ -11,23 +11,110 @@ void SPR_Bootstrap(void) //////////////////////////////////////////////////////////// //~ Key helpers -SPR_Key SPR_KeyFromResource(ResourceKey resource) +SPR_SheetKey SPR_SheetKeyFromResource(ResourceKey resource) { - SPR_Key result = Zi; + SPR_SheetKey result = Zi; + result.r = resource; return result; } //////////////////////////////////////////////////////////// //~ Lookup -SPR_Slice SPR_SliceFromKey(SPR_Key key, String slice_name) +SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, String slice_name) { SPR_Slice result = Zi; - // u64 hash = key.hash; - // hash = Mi + u64 hash = sheet.r.v; + hash = HashStringEx(hash, slice_name); - // SPR_SliceBin *bin = &SPR.slice_bins[ + i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy); + + // Search for existing entry + b32 found = 0; + SPR_SliceBin *bin = &SPR.slice_bins[hash % countof(SPR.slice_bins)]; + { + Lock bin_lock = LockS(&bin->mutex); + { + SPR_SliceEntry *entry = bin->first; + for (; entry; entry = entry->next) + { + if (entry->hash == hash) + { + break; + } + } + if (entry) + { + if (completion >= Atomic64Fetch(&entry->async_copy_completion_target)) + { + result = entry->slice; + } + found = 1; + } + } + Unlock(&bin_lock); + } + + // Push new entry + if (!found) + { + Lock submit_lock = LockE(&SPR.submit.mutex); + Lock bin_lock = LockE(&bin->mutex); + { + SPR_SliceEntry *entry = bin->first; + for (; entry; entry = entry->next) + { + if (entry->hash == hash) + { + break; + } + } + if (entry) + { + if (completion >= Atomic64Fetch(&entry->async_copy_completion_target)) + { + result = entry->slice; + } + found = 1; + } + else + { + Arena *perm = PermArena(); + + entry = PushStruct(perm, SPR_SliceEntry); + entry->hash = hash; + Atomic64FetchSet(&entry->async_copy_completion_target, I64Max); + entry->sheet = sheet; + entry->slice_name = PushString(perm, slice_name); + SllStackPush(bin->first, entry); + + SPR_CmdNode *n = SPR.submit.first_free; + if (n) + { + ZeroStruct(n); + } + else + { + n = PushStruct(perm, SPR_CmdNode); + } + n->cmd.entry = entry; + SllQueuePush(SPR.submit.first, SPR.submit.last, n); + ++SPR.submit.count; + Atomic32FetchSet(&SPR.new_cmds_present, 1); + SignalAsyncTick(); + } + } + Unlock(&bin_lock); + Unlock(&submit_lock); + } + + if (G_IsRefNil(result.tex)) + { + result.tex = G_BlankTexture2D(); + result.uv_rect.p0 = VEC2(0, 0); + result.uv_rect.p1 = VEC2(1, 1); + } return result; } @@ -37,4 +124,117 @@ SPR_Slice SPR_SliceFromKey(SPR_Key key, String slice_name) void SPR_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame) { + Arena *perm = PermArena(); + SPR_AsyncCtx *async = &SPR.async; + Arena *frame_arena = base_async_lane_frame->arena; + + // TODO: Go wide + if (lane->idx == 0) + { + if (Atomic32Fetch(&SPR.new_cmds_present)) + { + Atomic32Set(&SPR.new_cmds_present, 0); + SPR_CmdNode *first_cmd_node = 0; + SPR_CmdNode *last_cmd_node = 0; + u64 cmds_count = 0; + { + Lock lock = LockE(&SPR.submit.mutex); + { + first_cmd_node = SPR.submit.first; + last_cmd_node = SPR.submit.last; + cmds_count = SPR.submit.count; + SPR.submit.first = 0; + SPR.submit.last = 0; + } + Unlock(&lock); + } + if (cmds_count > 0) + { + for (SPR_CmdNode *n = first_cmd_node; n; n = n->next) + { + SPR_Cmd cmd = n->cmd; + SPR_SliceEntry *slice_entry = cmd.entry; + + SPR_SheetBin *sheet_bin = &async->sheet_bins[slice_entry->sheet.r.v % countof(async->sheet_bins)]; + SPR_SheetEntry *sheet = sheet_bin->first; + for (; sheet; sheet = sheet->next) + { + if (sheet->key.r.v == slice_entry->sheet.r.v) + { + break; + } + } + + // Decode sheet + // TODO: Distribute chunk decoding accross wave + // TODO: Use atlas allocator and separate slices into unique textures + // TODO: Reuse command list for all uploads + if (!sheet) + { + sheet = PushStruct(perm, SPR_SheetEntry); + sheet->key = slice_entry->sheet; + SllStackPush(sheet_bin->first, sheet); + + String encoded = DataFromResource(sheet->key.r); + String name = NameFromResource(sheet->key.r); + LogInfoF("Decoding sprite sheet \"%F\" (%F bytes)", FmtString(name), FmtUint(encoded.len)); + + ASE_DecodedImage decoded_image = ASE_DecodeImage(frame_arena, encoded); + ASE_DecodedSheet decoded_sheet = ASE_DecodeSheet(frame_arena, encoded); + + if (decoded_image.ok) + { + G_ResourceHandle gpu_resource = Zi; + G_ArenaHandle gpu_perm = G_PermArena(); + G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy); + { + Vec3I32 dims = Zi; + dims.x = decoded_image.width; + dims.y = decoded_image.height; + dims.z = 1; + gpu_resource = G_PushTexture2D( + gpu_perm, cl, + G_Format_R8G8B8A8_Unorm_Srgb, + dims, + G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present + ); + G_CopyCpuToTexture( + cl, + gpu_resource, VEC3I32(0, 0, 0), + decoded_image.pixels, dims, + RNG3I32( + VEC3I32(0, 0, 0), + dims + ) + ); + } + i64 completion_target = G_CommitCommandList(cl); + sheet->async_copy_completion_target = completion_target; + sheet->tex = G_PushTexture2DRef(gpu_perm, gpu_resource); + // LogDebugF("Decoded with ref: %F", FmtUint(slice_entry->slice.tex.v)); + } + else + { + // TODO: Use 'missing' texture + sheet->tex = G_BlankTexture2D(); + sheet->async_copy_completion_target = 0; + } + } + slice_entry->slice.tex = sheet->tex; + // FIXME: Real uv + slice_entry->slice.uv_rect.p0 = VEC2(0, 0); + slice_entry->slice.uv_rect.p1= VEC2(1, 1); + Atomic64Set(&slice_entry->async_copy_completion_target, sheet->async_copy_completion_target); + } + + // Free cmds + Lock lock = LockE(&SPR.submit.mutex); + { + last_cmd_node->next = SPR.submit.first_free; + SPR.submit.first_free = first_cmd_node; + } + Unlock(&lock); + } + } + } } diff --git a/src/sprite/sprite.h b/src/sprite/sprite.h index 77f390c0..ba261694 100644 --- a/src/sprite/sprite.h +++ b/src/sprite/sprite.h @@ -1,9 +1,83 @@ +//////////////////////////////////////////////////////////// +//~ Key types + +Struct(SPR_SheetKey) +{ + ResourceKey r; +}; + +//////////////////////////////////////////////////////////// +//~ Cache types + +Struct(SPR_SliceEntry) +{ + SPR_SliceEntry *next; + + SPR_SheetKey sheet; + u64 hash; + Atomic64 async_copy_completion_target; + + String slice_name; + + SPR_Slice slice; +}; + +Struct(SPR_SliceBin) +{ + Mutex mutex; + SPR_SliceEntry *first; +}; + +Struct(SPR_SheetEntry) +{ + SPR_SheetEntry *next; + SPR_SheetKey key; + i64 async_copy_completion_target; + G_Texture2DRef tex; +}; + +Struct(SPR_SheetBin) +{ + SPR_SheetEntry *first; +}; + +//////////////////////////////////////////////////////////// +//~ Async cmd types + +Struct(SPR_Cmd) +{ + SPR_SliceEntry *entry; +}; + +Struct(SPR_CmdNode) +{ + SPR_CmdNode *next; + SPR_Cmd cmd; +}; + //////////////////////////////////////////////////////////// //~ State types +Struct(SPR_AsyncCtx) +{ + SPR_SheetBin sheet_bins[Kibi(16)]; +}; + Struct(SPR_Ctx) { - i32 _; + SPR_SliceBin slice_bins[Kibi(16)]; + + Atomic32 new_cmds_present; + struct + { + Mutex mutex; + SPR_CmdNode *first; + SPR_CmdNode *last; + SPR_CmdNode *first_free; + u64 count; + } submit; + + SPR_AsyncCtx async; }; extern SPR_Ctx SPR; @@ -16,12 +90,12 @@ void SPR_Bootstrap(void); //////////////////////////////////////////////////////////// //~ Key helpers -SPR_Key SPR_KeyFromResource(ResourceKey resource); +SPR_SheetKey SPR_SheetKeyFromResource(ResourceKey resource); //////////////////////////////////////////////////////////// //~ Lookup -SPR_Slice SPR_SliceFromKey(SPR_Key key, String slice_name); +SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, String slice_name); //////////////////////////////////////////////////////////// //~ Async diff --git a/src/sprite/sprite_shared.cgh b/src/sprite/sprite_shared.cgh index 000b56f5..38b62e4a 100644 --- a/src/sprite/sprite_shared.cgh +++ b/src/sprite/sprite_shared.cgh @@ -1,16 +1,8 @@ -//////////////////////////////////////////////////////////// -//~ Key types - -Struct(SPR_Key) -{ - u64 v; -}; - //////////////////////////////////////////////////////////// //~ Slice types Struct(SPR_Slice) { G_Texture2DRef tex; - Rng2 uv; + Rng2 uv_rect; }; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index da7efc98..cb89aeaf 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -12,19 +12,19 @@ void UI_Bootstrap(void) b32 UI_MatchKey(UI_Key a, UI_Key b) { - return a.hash == b.hash; + return a.v == b.v; } b32 UI_IsKeyNil(UI_Key key) { - return key.hash == 0; + return key.v == 0; } UI_Key UI_KeyFromString(String str) { u64 top_tag = UI_Top(Tag); UI_Key key = Zi; - key.hash = HashFnv64(top_tag, str); + key.v = HashFnv64(top_tag, str); return key; } @@ -45,18 +45,17 @@ UI_Key UI_KeyF_(String fmt, ...) UI_Key UI_RandKey(void) { - u64 seed = ++UI.rand_key_seed; UI_Key key = Zi; - key.hash = MixU64(seed); + key.v = RandU64FromState(&UI.rand); return key; } UI_Box *UI_BoxFromKey(UI_Key key) { UI_Box *box = 0; - if (key.hash != 0) + if (key.v != 0) { - UI_BoxBin *bin = &UI.box_bins[key.hash % countof(UI.box_bins)]; + UI_BoxBin *bin = &UI.box_bins[key.v % countof(UI.box_bins)]; for (box = bin->first; box; box = box->next_in_bin) { if (UI_MatchKey(box->key, key)) @@ -284,7 +283,7 @@ UI_Checkpoint UI_PushCP(UI_Key parent) UI_Frame *frame = UI_CurrentFrame(); UI_Stack *stack = frame->top_stack; stack->top_checkpoint.v += 1; - if (parent.hash != 0) + if (parent.v != 0) { UI_Push(Parent, parent); } @@ -574,7 +573,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags) box->key = UI_RootKey; box->gen = 1; UI.boxes_count += 1; - UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)]; + UI_BoxBin *bin = &UI.box_bins[box->key.v % countof(UI.box_bins)]; bin->first = box; bin->last = box; UI.root_box = box; @@ -938,7 +937,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync) UI_Key key = cmd.box.key; UI_Box *box = 0; { - UI_BoxBin *bin = &UI.box_bins[key.hash % countof(UI.box_bins)]; + UI_BoxBin *bin = &UI.box_bins[key.v % countof(UI.box_bins)]; for (box = bin->first; box; box = box->next_in_bin) { if (UI_MatchKey(box->key, key)) @@ -1069,7 +1068,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync) { UI_Box *box = prunes[prune_idx]; UI_Box *parent = box->parent; - UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)]; + UI_BoxBin *bin = &UI.box_bins[box->key.v % countof(UI.box_bins)]; // Re-parent children if (box->first) { @@ -1704,7 +1703,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync) params.target_size = draw_size; params.target_ro = draw_target_ro; params.rects = rects_ro; - params.sampler = G_BasicSampler(); + params.sampler = G_BasicPointClampSampler(); params.cursor_pos = frame->cursor_pos; params.aa = TweakFloat("UI anti-aliasing", 1, 0, 1); } diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index b2aa45e7..ef84b809 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -6,7 +6,7 @@ Struct(UI_Key) { - u64 hash; + u64 v; }; //////////////////////////////////////////////////////////// @@ -412,7 +412,7 @@ Struct(UI_Ctx) UI_BoxBin box_bins[Kibi(256)]; UI_Box *first_free_box; - u64 rand_key_seed; + RandState rand; i64 current_frame_tick; UI_Frame frames[2];