From 69a8f2e1a36192c73fae7e346d7dc5d8d5256b12 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 21 Oct 2025 16:02:35 -0500 Subject: [PATCH] gpu utils --- src/base/base.h | 6 +- src/base/base_math_gpu.h | 11 + src/gpu/gpu.h | 2 + src/gpu/gpu.lay | 8 + src/gpu/gpu_dx12/gpu_dx12.c | 12 +- .../gpu_res}/noise_128x128x64_16.dat | 0 src/gpu/gpu_util.c | 236 ++++++++++++++++++ src/gpu/gpu_util.h | 65 +++++ src/pp/pp.c | 235 +++++------------ src/pp/pp.h | 27 +- src/ui/ui.c | 186 ++++++++++---- src/ui/ui.h | 152 ++--------- src/ui/ui.lay | 6 +- src/ui/ui_draw.gpu | 38 ++- src/ui/ui_draw.h | 11 +- src/ui/ui_flags.h | 8 + src/ui/{ui_widgets.c => ui_util.c} | 0 src/ui/{ui_widgets.h => ui_util.h} | 0 18 files changed, 620 insertions(+), 383 deletions(-) rename src/{pp/pp_res => gpu/gpu_res}/noise_128x128x64_16.dat (100%) create mode 100644 src/gpu/gpu_util.c create mode 100644 src/gpu/gpu_util.h create mode 100644 src/ui/ui_flags.h rename src/ui/{ui_widgets.c => ui_util.c} (100%) rename src/ui/{ui_widgets.h => ui_util.h} (100%) diff --git a/src/base/base.h b/src/base/base.h index 5c2146b1..6d029643 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -398,7 +398,11 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #define AlignedBlock(n) struct alignas(n) //- Enum -#define Enum(name) typedef enum name name; enum name +#if !LanguageIsGpu +# define Enum(name) typedef enum name name; enum name +#else +# define Enum(name) enum name +#endif //- alignof #if LanguageIsC && (CompilerIsMsvc || __STDC_VERSION__ < 202311L) diff --git a/src/base/base_math_gpu.h b/src/base/base_math_gpu.h index 403dbfa8..16dd8ae7 100644 --- a/src/base/base_math_gpu.h +++ b/src/base/base_math_gpu.h @@ -51,3 +51,14 @@ Vec4 LinearFromSrgbU32(u32 srgb32) { return LinearFromSrgbVec4(Vec4NormFromU32(srgb32)); } + +//////////////////////////////// +//~ Ndc helpers + +Vec2 NdcFromViewport(Vec2 viewport_size, Vec2 viewport_coords) +{ + Vec2 result; + result.x = ((viewport_coords.x + 0.5f) / viewport_size.x) * 2.0f - 1.0f; + result.y = 1.0f - ((viewport_coords.y + 0.5f) / viewport_size.y) * 2.0f; + return result; +} diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h index 8c53b85f..237984dc 100644 --- a/src/gpu/gpu.h +++ b/src/gpu/gpu.h @@ -384,6 +384,8 @@ Vec2I32 GPU_GetTextureSize2D(GPU_Resource *resource); Vec3I32 GPU_GetTextureSize3D(GPU_Resource *resource); u64 GPU_GetFootprintSize(GPU_Resource *resource); +u64 GPU_GetBufferCount(GPU_Resource *gpu_resource); + //////////////////////////////// //~ @hookdecl Resource index operations diff --git a/src/gpu/gpu.lay b/src/gpu/gpu.lay index 3e96aa06..eebede0e 100644 --- a/src/gpu/gpu.lay +++ b/src/gpu/gpu.lay @@ -5,9 +5,17 @@ //- Api @IncludeC gpu.h +@IncludeC gpu_util.h + +//- Impl +@IncludeC gpu_util.c //- Dx12 impl @DefaultWindowsImpl gpu_dx12 +//- Embeds +@EmbedDir GPU_Resources gpu_res + //- Startup @Startup GPU_Startup +@Startup GPU_StartupUtils diff --git a/src/gpu/gpu_dx12/gpu_dx12.c b/src/gpu/gpu_dx12/gpu_dx12.c index 1f17a6c4..2ce46274 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.c +++ b/src/gpu/gpu_dx12/gpu_dx12.c @@ -1231,9 +1231,9 @@ GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc) d3d_desc.MaxLOD = desc.sampler.max_lod; /* Defaults */ - if (d3d_desc.AddressU == 0) d3d_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;; - if (d3d_desc.AddressV == 0) d3d_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;; - if (d3d_desc.AddressW == 0) d3d_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;; + if (d3d_desc.AddressU == 0) d3d_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + if (d3d_desc.AddressV == 0) d3d_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + if (d3d_desc.AddressW == 0) d3d_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; if (d3d_desc.MaxLOD >= F32Infinity) { d3d_desc.MaxLOD = D3D12_FLOAT32_MAX; @@ -1351,6 +1351,12 @@ u64 GPU_GetFootprintSize(GPU_Resource *gpu_resource) return footprint_size; } +u64 GPU_GetBufferCount(GPU_Resource *gpu_resource) +{ + GPU_D12_Resource *resource = (GPU_D12_Resource *)gpu_resource; + return resource->desc.buffer.count; +} + //////////////////////////////// //~ @hookdef Resource index hooks diff --git a/src/pp/pp_res/noise_128x128x64_16.dat b/src/gpu/gpu_res/noise_128x128x64_16.dat similarity index 100% rename from src/pp/pp_res/noise_128x128x64_16.dat rename to src/gpu/gpu_res/noise_128x128x64_16.dat diff --git a/src/gpu/gpu_util.c b/src/gpu/gpu_util.c new file mode 100644 index 00000000..401bdc1e --- /dev/null +++ b/src/gpu/gpu_util.c @@ -0,0 +1,236 @@ +GPU_SharedUtilState GPU_shared_util_state = ZI; + +//////////////////////////////// +//~ Startup + +void GPU_StartupUtils(void) +{ + GPU_SharedUtilState *g = &GPU_shared_util_state; + + GPU_QueueKind queue_kind = GPU_QueueKind_Direct; + Fence *queue_fence = GPU_FenceFromQueue(queue_kind); + i64 queue_fence_target = FetchFence(queue_fence); + + GPU_Resource *noise_upload = 0; + GPU_Resource *quad_upload = 0; + GPU_Resource *noise = 0; + GPU_Resource *quad = 0; + + GPU_CommandList *cl = GPU_BeginCommandList(queue_kind); + { + /* Upload noise */ + { + Vec3I32 noise_size = VEC3I32(128, 128, 64); + Resource noise_resource = ResourceFromStore(&GPU_Resources, Lit("noise_128x128x64_16.dat")); + String noise_res_data = DataFromResource(noise_resource); + if (noise_res_data.len != noise_size.x * noise_size.y * noise_size.z * 2) + { + Panic(Lit("Unexpected noise texture size")); + } + GPU_ResourceDesc desc = ZI; + desc.kind = GPU_ResourceKind_Texture3D; + desc.texture.format = GPU_Format_R16_Uint; + desc.texture.size = noise_size; + noise = GPU_AcquireResource(desc); + { + u64 footprint_size = GPU_GetFootprintSize(noise); + GPU_ResourceDesc upload_desc = ZI; + upload_desc.kind = GPU_ResourceKind_Buffer; + upload_desc.buffer.heap_kind = GPU_HeapKind_Upload; + upload_desc.buffer.count = footprint_size; + noise_upload = GPU_AcquireResource(upload_desc); + GPU_Mapped mapped = GPU_Map(noise_upload); + GPU_CopyBytesToFootprint(mapped.mem, noise_res_data.text, noise); + GPU_Unmap(mapped); + } + GPU_TransitionToCopyDst(cl, noise); + GPU_CopyResource(cl, noise, noise_upload); + GPU_TransitionToReadable(cl, noise); + } + + /* Upload quad indices */ + { + u16 quad_indices[6] = { 0, 1, 2, 0, 2, 3 }; + GPU_ResourceDesc desc = ZI; + desc.kind = GPU_ResourceKind_Buffer; + desc.buffer.count = countof(quad_indices); + desc.buffer.stride = sizeof(quad_indices[0]); + quad = GPU_AcquireResource(desc); + { + GPU_ResourceDesc upload_desc = ZI; + upload_desc.kind = GPU_ResourceKind_Buffer; + upload_desc.buffer.heap_kind = GPU_HeapKind_Upload; + upload_desc.buffer.count = desc.buffer.count * desc.buffer.stride; + quad_upload = GPU_AcquireResource(upload_desc); + GPU_Mapped mapped = GPU_Map(quad_upload); + CopyBytes(mapped.mem, quad_indices, sizeof(quad_indices)); + GPU_Unmap(mapped); + } + GPU_TransitionToCopyDst(cl, quad); + GPU_CopyResource(cl, quad, quad_upload); + GPU_TransitionToReadable(cl, quad); + } + } + queue_fence_target = GPU_EndCommandList(cl); + + /* Init point sampler */ + g->pt_sampler = GPU_AcquireResource((GPU_ResourceDesc) { .kind = GPU_ResourceKind_Sampler, .sampler.filter = GPU_Filter_MinMagMipPoint }); + + /* Wait & cleanup */ + YieldOnFence(queue_fence, queue_fence_target); + GPU_ReleaseResource(noise_upload, GPU_ReleaseFlag_None); + GPU_ReleaseResource(quad_upload, GPU_ReleaseFlag_None); + + g->noise = noise; + g->quad_indices = quad; +} + +//////////////////////////////// +//~ Common resource helpers + +GPU_Resource *GPU_GetCommonPointSampler(void) +{ + return GPU_shared_util_state.pt_sampler; +} + +GPU_Resource *GPU_GetCommonQuadIndices(void) +{ + return GPU_shared_util_state.quad_indices; +} + +GPU_Resource *GPU_GetCommonNoise(void) +{ + return GPU_shared_util_state.noise; +} + +//////////////////////////////// +//~ Transient buffer operations + +GPU_TransientBuffer *GPU_AcquireTransientBuffer_(u64 reserve, GPU_QueueKind queue_kind, u32 max_in_flight, u32 element_size, u32 element_align) +{ + element_size = MaxU32(element_size, 1); + element_align = MaxU32(element_align, 1); + max_in_flight = MaxU32(max_in_flight, 1); + + GPU_TransientBuffer *tbuff = 0; + { + Arena *arena = AcquireArena(reserve); + tbuff = PushStruct(arena, GPU_TransientBuffer); + tbuff->arena = arena; + } + + tbuff->queue_kind = queue_kind; + tbuff->submitted_resources = PushStructs(tbuff->arena, GPU_SubmittedTransientBufferResource, max_in_flight); + tbuff->max_in_flight = max_in_flight; + for (u32 i = 0; i < max_in_flight; ++i) + { + /* Init free list */ + StackPush(tbuff->first_free, &tbuff->submitted_resources[i]); + } + + PushAlign(tbuff->arena, element_align); + tbuff->elements_start_pos = tbuff->arena->pos; + tbuff->element_size = element_size; + tbuff->element_align = element_align; + + return tbuff; +} + +void GPU_ReleaseTransientBuffer(GPU_TransientBuffer *tbuff) +{ + Fence *queue_fence = GPU_FenceFromQueue(tbuff->queue_kind); + i64 queue_fence_value = FetchFence(queue_fence); + YieldOnFence(queue_fence, queue_fence_value); + + for (GPU_SubmittedTransientBufferResource *submitted = tbuff->first_submitted; + submitted; + submitted = submitted->next) + { + GPU_ReleaseResource(submitted->resource, GPU_ReleaseFlag_None); + } + + ReleaseArena(tbuff->arena); +} + +GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff) +{ + GPU_Resource *resource = 0; + u32 element_count = (tbuff->arena->pos - tbuff->elements_start_pos) / tbuff->element_size; + + Fence *queue_fence = GPU_FenceFromQueue(tbuff->queue_kind); + i64 queue_fence_value = FetchFence(queue_fence); + + if (tbuff->uploaded != 0) + { + Panic(Lit("GPU transient buffer uploaded without a reset")); + } + + /* Grab resource */ + GPU_SubmittedTransientBufferResource *upload = 0; + { + GPU_SubmittedTransientBufferResource *submitted = tbuff->first_submitted; + if (submitted && submitted->fence_target <= queue_fence_value) + { + upload = submitted; + QueuePop(tbuff->first_submitted, tbuff->last_submitted); + } + else if (tbuff->first_free) + { + /* Resource in upload, create new */ + upload = tbuff->first_free; + StackPop(tbuff->first_free); + } + else + { + /* Resource in use and max_in_flight reached, wait for availability */ + Assert(submitted != 0); + YieldOnFence(queue_fence, submitted->fence_target); + queue_fence_value = FetchFence(queue_fence); + upload = submitted; + QueuePop(tbuff->first_submitted, tbuff->last_submitted); + } + } + + if (upload->resource) + { + GPU_ReleaseResource(upload->resource, GPU_ReleaseFlag_Reuse); + upload->resource = 0; + } + + GPU_ResourceDesc desc = ZI; + desc.kind = GPU_ResourceKind_Buffer; + desc.flags = GPU_ResourceFlag_None; + desc.buffer.heap_kind = GPU_HeapKind_Upload; + desc.buffer.count = element_count; + desc.buffer.stride = tbuff->element_size; + upload->resource = GPU_AcquireResource(desc); + + { + __profn("Copy to transfer buffer"); + GPU_Mapped m = GPU_Map(upload->resource); + CopyBytes(m.mem, ArenaBase(tbuff->arena) + tbuff->elements_start_pos, tbuff->element_size * element_count); + GPU_Unmap(m); + } + + tbuff->uploaded = upload; + tbuff->uploaded_element_count = element_count; + + return upload->resource; +} + +void GPU_ResetTransientBuffer(GPU_TransientBuffer *tbuff, i64 queue_fence_target) +{ + PopTo(tbuff->arena, tbuff->elements_start_pos); + GPU_SubmittedTransientBufferResource *use = tbuff->uploaded; + if (use) + { + use->fence_target = queue_fence_target; + QueuePush(tbuff->first_submitted, tbuff->last_submitted, use); + tbuff->uploaded = 0; + } +} + +Arena *GPU_ArenaFromTransientBuffer(GPU_TransientBuffer *tbuff) +{ + return tbuff->arena; +} diff --git a/src/gpu/gpu_util.h b/src/gpu/gpu_util.h new file mode 100644 index 00000000..8d91853a --- /dev/null +++ b/src/gpu/gpu_util.h @@ -0,0 +1,65 @@ +//////////////////////////////// +//~ Transient buffer types + +Struct(GPU_SubmittedTransientBufferResource) +{ + GPU_SubmittedTransientBufferResource *next; + + i64 fence_target; /* Once the buffer's queue reaches the target, the resource can be freed or reused */ + GPU_Resource *resource; +}; + +Struct(GPU_TransientBuffer) +{ + Arena *arena; + GPU_QueueKind queue_kind; + u64 elements_start_pos; + u32 element_size; + u32 element_align; + + GPU_SubmittedTransientBufferResource *submitted_resources; /* Pool of submitted resource structs */ + + u32 uploaded_element_count; + GPU_SubmittedTransientBufferResource *uploaded; + + GPU_SubmittedTransientBufferResource *first_submitted; + GPU_SubmittedTransientBufferResource *last_submitted; + GPU_SubmittedTransientBufferResource *first_free; + u32 max_in_flight; +}; + + +//////////////////////////////// +//~ State types + +Struct(GPU_SharedUtilState) +{ + /* Common shared resources */ + GPU_Resource *pt_sampler; + GPU_Resource *quad_indices; + GPU_Resource *noise; +} extern GPU_shared_util_state; + +//////////////////////////////// +//~ Startup + +void GPU_StartupUtils(void); + +//////////////////////////////// +//~ Common resource helpers + +GPU_Resource *GPU_GetCommonPointSampler(void); +GPU_Resource *GPU_GetCommonQuadIndices(void); +GPU_Resource *GPU_GetCommonNoise(void); + +//////////////////////////////// +//~ Transient buffer operations + +GPU_TransientBuffer *GPU_AcquireTransientBuffer_(u64 reserve, GPU_QueueKind queue_kind, u32 max_in_flight, u32 element_size, u32 element_align); +#define GPU_AcquireTransientBuffer(reserve, queue_kind, max_in_flight, type) GPU_AcquireTransientBuffer_((reserve), (queue_kind), (max_in_flight), sizeof(type), alignof(type)) +void GPU_ReleaseTransientBuffer(GPU_TransientBuffer *tbuff); + +GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff); +void GPU_ResetTransientBuffer(GPU_TransientBuffer *tbuff, i64 queue_fence_target); + +Arena *GPU_ArenaFromTransientBuffer(GPU_TransientBuffer *tbuff); diff --git a/src/pp/pp.c b/src/pp/pp.c index 4fcf7429..3208ed14 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -26,16 +26,6 @@ void StartupUser(void) g->user_blended_client = AcquireClient(g->user_client_store); g->ss_blended = NilSnapshot(); - /* Renderer sampler */ - g->pt_sampler = GPU_AcquireResource((GPU_ResourceDesc) { .kind = GPU_ResourceKind_Sampler, .sampler.filter = GPU_Filter_MinMagMipPoint }); - - /* Renderer data arenas */ - g->material_instances_arena = AcquireArena(Gibi(64)); - g->ui_rect_instances_arena = AcquireArena(Gibi(64)); - g->ui_shape_verts_arena = AcquireArena(Gibi(64)); - g->ui_shape_indices_arena = AcquireArena(Gibi(64)); - g->grids_arena = AcquireArena(Gibi(64)); - /* Local to user client */ g->local_to_user_client_store = AcquireClientStore(); g->local_to_user_client = AcquireClient(g->local_to_user_client_store); @@ -403,42 +393,6 @@ GPU_Resource *AcquireGbuffer(GPU_Format format, Vec2I32 size) return GPU_AcquireResource(desc); } -//- Upload buffer - -GPU_Resource *AcquireUploadBuffer_(void *src, u32 element_size, u32 element_count) -{ - __prof; - GPU_ResourceDesc desc = ZI; - desc.kind = GPU_ResourceKind_Buffer; - desc.flags = GPU_ResourceFlag_None; - desc.buffer.heap_kind = GPU_HeapKind_Upload; - desc.buffer.count = element_count; - desc.buffer.stride = element_size; - GPU_Resource *r = GPU_AcquireResource(desc); - { - __profn("Copy to transfer buffer"); - GPU_Mapped m = GPU_Map(r); - CopyBytes(m.mem, src, element_size * element_count); - GPU_Unmap(m); - } - return r; -} - -GPU_Resource *AcquireUploadBufferFromArena_(Arena *arena, u32 element_size) -{ - __prof; - u64 element_count = arena->pos / element_size; - GPU_Resource *r = AcquireUploadBuffer_(ArenaBase(arena), element_size, element_count); - return r; -} - -JobDef(DelayReleaseGpuResources, sig, id) -{ - YieldOnFence(sig->begin_fence, sig->begin_fence_target); - GPU_Resource *resource = sig->resources[id]; - GPU_ReleaseResource(resource, sig->flags); -} - //////////////////////////////// //~ Sort entities @@ -500,6 +454,21 @@ void UpdateUser(P_Window *window) UI_Box *pp_root_box = UI_BuildBox(UI_Flag_DrawImage, UI_NilKey); UI_PushParent(pp_root_box); + //- Init render data buffers + if (!g->material_instances_tbuff) + { + g->material_instances_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, MaterialInstance); + g->ui_rect_instances_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, UiRectInstance); + g->ui_shape_verts_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, UiShapeVert); + g->ui_shape_indices_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, u32); + g->grids_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, MaterialGrid); + } + Arena *material_instances_arena = GPU_ArenaFromTransientBuffer(g->material_instances_tbuff); + Arena *ui_rect_instances_arena = GPU_ArenaFromTransientBuffer(g->ui_rect_instances_tbuff); + Arena *ui_shape_verts_arena = GPU_ArenaFromTransientBuffer(g->ui_shape_verts_tbuff); + Arena *ui_shape_indices_arena = GPU_ArenaFromTransientBuffer(g->ui_shape_indices_tbuff); + Arena *grids_arena = GPU_ArenaFromTransientBuffer(g->grids_tbuff); + //- Pull latest local sim snapshot { @@ -1007,7 +976,6 @@ void UpdateUser(P_Window *window) //- Draw grid - /* FIXME: Enable this */ { f32 thickness = 2; @@ -1019,7 +987,7 @@ void UpdateUser(P_Window *window) u32 color0 = Rgba32F(0.17f, 0.17f, 0.17f, 1.f); u32 color1 = Rgba32F(0.15f, 0.15f, 0.15f, 1.f); - MaterialGrid *grid = PushStruct(g->grids_arena, MaterialGrid); + MaterialGrid *grid = PushStruct(grids_arena, MaterialGrid); *grid = DefaultMaterialGrid; grid->line_thickness = thickness; grid->line_spacing = spacing; @@ -1030,9 +998,12 @@ void UpdateUser(P_Window *window) grid->x_srgb = ColorRed; grid->y_srgb = ColorGreen; - MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance); + MaterialInstance *mat = PushStruct(material_instances_arena, MaterialInstance); *mat = DefaultMaterialInstance; - mat->grid_id = grid - (MaterialGrid *)ArenaBase(g->grids_arena); + // TODO + // BROKE + // FIXME + mat->grid_id = grid - (MaterialGrid *)ArenaBase(grids_arena); mat->xf = XformFromRect(RectFromVec2(pos, size)); } @@ -1251,7 +1222,7 @@ void UpdateUser(P_Window *window) Vec3 emittance = ent->sprite_emittance; u32 tint = ent->sprite_tint; S_Frame frame = S_FrameFromIndex(sheet, ent->animation_frame); - MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance); + MaterialInstance *mat = PushStruct(material_instances_arena, MaterialInstance); *mat = DefaultMaterialInstance; mat->xf = sprite_xform; mat->tex = GPU_Texture2DRidFromResource(texture->gpu_texture); @@ -1286,7 +1257,7 @@ void UpdateUser(P_Window *window) Vec2I32 world_tile_index = WorldTileIndexFromLocalTileIndex(chunk_index, local_tile_index); Vec2 pos = PosFromWorldTileIndex(world_tile_index); Xform tile_xf = XformFromRect(RectFromVec2(pos, VEC2(tile_size, tile_size))); - MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance); + MaterialInstance *mat = PushStruct(material_instances_arena, MaterialInstance); *mat = DefaultMaterialInstance; mat->xf = tile_xf; mat->tex = GPU_Texture2DRidFromResource(tile_texture->gpu_texture); @@ -2029,6 +2000,7 @@ void UpdateUser(P_Window *window) GPU_MemoryInfo vram = GPU_QueryMemoryInfo(); + //////////////////////////////// //~ Draw global debug info /* FIXME: Enable this */ #if 1 @@ -2264,14 +2236,15 @@ void UpdateUser(P_Window *window) #endif } + //////////////////////////////// //~ Render + Rect ui_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->ui_size.x, g->ui_size.y)); + Rect render_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->render_size.x, g->render_size.y)); + GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct; + Fence *render_fence = GPU_FenceFromQueue(gpu_render_queue); { __profn("Render"); - GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct; - Rect ui_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->ui_size.x, g->ui_size.y)); - Rect render_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->render_size.x, g->render_size.y)); - Fence *render_fence = GPU_FenceFromQueue(gpu_render_queue); /* Acquire gbuffers */ if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize2D(g->shade_target))) @@ -2309,84 +2282,17 @@ void UpdateUser(P_Window *window) g->ui_target = AcquireGbuffer(GPU_Format_R8G8B8A8_Unorm, g->ui_size); } - /* Init renderer resources */ - if (!g->gpu_noise || !g->gpu_quad) - { - GPU_Resource *noise_upload = 0; - GPU_Resource *quad_upload = 0; - GPU_Resource *noise = 0; - GPU_Resource *quad = 0; - GPU_CommandList *cl = GPU_BeginCommandList(gpu_render_queue); - /* Upload noise */ - { - Vec3I32 noise_size = VEC3I32(128, 128, 64); - Resource noise_resource = ResourceFromStore(&GameResources, Lit("noise_128x128x64_16.dat")); - String noise_res_data = DataFromResource(noise_resource); - if (noise_res_data.len != noise_size.x * noise_size.y * noise_size.z * 2) - { - Panic(Lit("Unexpected noise texture size")); - } - GPU_ResourceDesc desc = ZI; - desc.kind = GPU_ResourceKind_Texture3D; - desc.texture.format = GPU_Format_R16_Uint; - desc.texture.size = noise_size; - noise = GPU_AcquireResource(desc); - { - u64 footprint_size = GPU_GetFootprintSize(noise); - GPU_ResourceDesc upload_desc = ZI; - upload_desc.kind = GPU_ResourceKind_Buffer; - upload_desc.buffer.heap_kind = GPU_HeapKind_Upload; - upload_desc.buffer.count = footprint_size; - noise_upload = GPU_AcquireResource(upload_desc); - GPU_Mapped mapped = GPU_Map(noise_upload); - GPU_CopyBytesToFootprint(mapped.mem, noise_res_data.text, noise); - GPU_Unmap(mapped); - } - GPU_TransitionToCopyDst(cl, noise); - GPU_CopyResource(cl, noise, noise_upload); - GPU_TransitionToReadable(cl, noise); - } - /* Upload quad indices */ - { - u16 quad_indices[6] = { 0, 1, 2, 0, 2, 3 }; - GPU_ResourceDesc desc = ZI; - desc.kind = GPU_ResourceKind_Buffer; - desc.buffer.count = countof(quad_indices); - desc.buffer.stride = sizeof(quad_indices[0]); - quad = GPU_AcquireResource(desc); - { - GPU_ResourceDesc upload_desc = ZI; - upload_desc.kind = GPU_ResourceKind_Buffer; - upload_desc.buffer.heap_kind = GPU_HeapKind_Upload; - upload_desc.buffer.count = desc.buffer.count * desc.buffer.stride; - quad_upload = GPU_AcquireResource(upload_desc); - GPU_Mapped mapped = GPU_Map(quad_upload); - CopyBytes(mapped.mem, quad_indices, sizeof(quad_indices)); - GPU_Unmap(mapped); - } - GPU_TransitionToCopyDst(cl, quad); - GPU_CopyResource(cl, quad, quad_upload); - GPU_TransitionToReadable(cl, quad); - } - g->gpu_render_fence_target = GPU_EndCommandList(cl); - YieldOnFence(render_fence, g->gpu_render_fence_target); - GPU_ReleaseResource(noise_upload, GPU_ReleaseFlag_None); - GPU_ReleaseResource(quad_upload, GPU_ReleaseFlag_None); - g->gpu_noise = noise; - g->gpu_quad = quad; - } - - /* Acquire transfer buffers */ - GPU_Resource *material_instance_buffer = AcquireUploadBufferFromArena(g->material_instances_arena, MaterialInstance); - GPU_Resource *ui_rect_instance_buffer = AcquireUploadBufferFromArena(g->ui_rect_instances_arena, UiRectInstance); - GPU_Resource *ui_shape_verts_buffer = AcquireUploadBufferFromArena(g->ui_shape_verts_arena, UiShapeVert); - GPU_Resource *ui_shape_indices_buffer = AcquireUploadBufferFromArena(g->ui_shape_indices_arena, u32); - GPU_Resource *grids_buffer = AcquireUploadBufferFromArena(g->grids_arena, MaterialGrid); - u64 material_instances_count = ArenaCount(g->material_instances_arena, MaterialInstance); - u64 ui_rect_instances_count = ArenaCount(g->ui_rect_instances_arena, UiRectInstance); - u64 ui_shape_verts_count = ArenaCount(g->ui_shape_verts_arena, UiShapeVert); - u64 ui_shape_indices_count = ArenaCount(g->ui_shape_indices_arena, u32); - u64 grids_count = ArenaCount(g->grids_arena, MaterialGrid); + /* Upload transient buffers */ + GPU_Resource *material_instances_buffer = GPU_UploadTransientBuffer(g->material_instances_tbuff); + GPU_Resource *ui_rect_instances_buffer = GPU_UploadTransientBuffer(g->ui_rect_instances_tbuff); + GPU_Resource *ui_shape_verts_buffer = GPU_UploadTransientBuffer(g->ui_shape_verts_tbuff); + GPU_Resource *ui_shape_indices_buffer = GPU_UploadTransientBuffer(g->ui_shape_indices_tbuff); + GPU_Resource *grids_buffer = GPU_UploadTransientBuffer(g->grids_tbuff); + u64 material_instances_count = GPU_GetBufferCount(material_instances_buffer); + u64 ui_rect_instances_count = GPU_GetBufferCount(ui_rect_instances_buffer); + u64 ui_shape_verts_count = GPU_GetBufferCount(ui_shape_verts_buffer); + u64 ui_shape_indices_count = GPU_GetBufferCount(ui_shape_indices_buffer); + u64 grids_count = GPU_GetBufferCount(grids_buffer); GPU_CommandList *cl = GPU_BeginCommandList(gpu_render_queue); { @@ -2423,8 +2329,8 @@ void UpdateUser(P_Window *window) MaterialSig sig = ZI; sig.projection = world_to_render_vp_matrix; - sig.sampler = GPU_SamplerStateRidFromResource(g->pt_sampler); - sig.instances = GPU_StructuredBufferRidFromResource(material_instance_buffer); + sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler()); + sig.instances = GPU_StructuredBufferRidFromResource(material_instances_buffer); sig.grids = GPU_StructuredBufferRidFromResource(grids_buffer); GPU_Rasterize(cl, &sig, @@ -2433,7 +2339,7 @@ void UpdateUser(P_Window *window) viewport, scissor, material_instances_count, - g->gpu_quad, + GPU_GetCommonQuadIndices(), GPU_RasterizeMode_TriangleList); } @@ -2504,7 +2410,7 @@ void UpdateUser(P_Window *window) { __profn("Shade pass"); GPU_ProfN(cl, Lit("Shade pass")); - Vec3I32 noise_size = GPU_GetTextureSize3D(g->gpu_noise); + Vec3I32 noise_size = GPU_GetTextureSize3D(GPU_GetCommonNoise()); u32 shade_flags = ShadeFlag_None; if (effects_disabled) @@ -2522,7 +2428,7 @@ void UpdateUser(P_Window *window) (u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF)); sig.frame_index = g->frame_index; sig.camera_offset = g->world_to_render_xf.og; - sig.noise = GPU_Texture3DRidFromResource(g->gpu_noise); + sig.noise = GPU_Texture3DRidFromResource(GPU_GetCommonNoise()); sig.albedo = GPU_Texture2DRidFromResource(g->albedo); sig.emittance = GPU_Texture2DRidFromResource(g->emittance); sig.emittance_flood = GPU_Texture2DRidFromResource(g->emittance_flood_read); @@ -2557,7 +2463,7 @@ void UpdateUser(P_Window *window) GPU_Scissor scissor = GPU_ScissorFromRect(ui_viewport); UiBlitSig sig = ZI; - sig.sampler = GPU_SamplerStateRidFromResource(g->pt_sampler); + sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler()); sig.src = GPU_Texture2DRidFromResource(g->shade_read); sig.projection = blit_vp_matrix; sig.flags = UiBlitFlag_ToneMap | UiBlitFlag_GammaCorrect; @@ -2570,7 +2476,7 @@ void UpdateUser(P_Window *window) viewport, scissor, 1, - g->gpu_quad, + GPU_GetCommonQuadIndices(), GPU_RasterizeMode_TriangleList); } @@ -2584,8 +2490,8 @@ void UpdateUser(P_Window *window) UiRectSig sig = ZI; sig.projection = ui_vp_matrix; - sig.sampler = GPU_SamplerStateRidFromResource(g->pt_sampler); - sig.instances = GPU_StructuredBufferRidFromResource(ui_rect_instance_buffer); + sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler()); + sig.instances = GPU_StructuredBufferRidFromResource(ui_rect_instances_buffer); GPU_Rasterize(cl, &sig, UiRectVS, UiRectPS, @@ -2593,7 +2499,7 @@ void UpdateUser(P_Window *window) viewport, scissor, ui_rect_instances_count, - g->gpu_quad, + GPU_GetCommonQuadIndices(), GPU_RasterizeMode_TriangleList); } @@ -2618,44 +2524,25 @@ void UpdateUser(P_Window *window) ui_shape_indices_buffer, GPU_RasterizeMode_TriangleList); } + + //- Transition target to readable before UI pass + GPU_TransitionToReadable(cl, g->ui_target); + } g->gpu_render_fence_target = GPU_EndCommandList(cl); - /* Reset transfer buffers & queue their release */ - { - { - GPU_Resource *release_resources[] = { - material_instance_buffer, - ui_rect_instance_buffer, - ui_shape_verts_buffer, - ui_shape_indices_buffer, - grids_buffer, - }; - Job *job = OpenJob(DelayReleaseGpuResources, JobPool_Inherit); - { - DelayReleaseGpuResources_Sig *sig = PushStruct(job->arena, DelayReleaseGpuResources_Sig); - job->count = countof(release_resources); - job->sig = sig; - sig->begin_fence = render_fence; - sig->begin_fence_target = g->gpu_render_fence_target; - sig->resources = PushStructsNoZero(job->arena, GPU_Resource *, job->count); - sig->flags = GPU_ReleaseFlag_Reuse; - CopyBytes(sig->resources, release_resources, sizeof(release_resources)); - } - CloseJob(job); - } - ResetArena(g->material_instances_arena); - ResetArena(g->ui_rect_instances_arena); - ResetArena(g->ui_shape_verts_arena); - ResetArena(g->ui_shape_indices_arena); - ResetArena(g->grids_arena); - } + /* Reset transients */ + GPU_ResetTransientBuffer(g->material_instances_tbuff, g->gpu_render_fence_target); + GPU_ResetTransientBuffer(g->ui_rect_instances_tbuff, g->gpu_render_fence_target); + GPU_ResetTransientBuffer(g->ui_shape_verts_tbuff, g->gpu_render_fence_target); + GPU_ResetTransientBuffer(g->ui_shape_indices_tbuff, g->gpu_render_fence_target); + GPU_ResetTransientBuffer(g->grids_tbuff, g->gpu_render_fence_target); } /* Render UI */ UI_PopParent(); UI_SetDisplayImage(pp_root_box, g->ui_target); - GPU_Resource *ui_render = UI_EndBuild(); + GPU_Resource *ui_render = UI_EndBuild(ui_viewport); //////////////////////////////// //~ Present diff --git a/src/pp/pp.h b/src/pp/pp.h index b8997291..7355f1bc 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -172,11 +172,7 @@ Struct(SharedUserState) SecondsStat net_bytes_read; SecondsStat net_bytes_sent; - //- Gpu resources - GPU_Resource *pt_sampler; - GPU_Resource *gpu_noise; - GPU_Resource *gpu_quad; - + //- Renderer gbuffers GPU_Resource *albedo; GPU_Resource *emittance; GPU_Resource *emittance_flood_read; @@ -185,15 +181,16 @@ Struct(SharedUserState) GPU_Resource *shade_target; GPU_Resource *ui_target; + //- Render transient buffers + GPU_TransientBuffer *material_instances_tbuff; + GPU_TransientBuffer *ui_rect_instances_tbuff; + GPU_TransientBuffer *ui_shape_verts_tbuff; + GPU_TransientBuffer *ui_shape_indices_tbuff; + GPU_TransientBuffer *grids_tbuff; + + //- Renderer state RandState frame_rand; u64 frame_index; - - Arena *material_instances_arena; - Arena *ui_rect_instances_arena; - Arena *ui_shape_verts_arena; - Arena *ui_shape_indices_arena; - Arena *grids_arena; - i64 gpu_render_fence_target; //- Bind state @@ -295,13 +292,7 @@ void DrawDebugConsole(i32 level, b32 minimized); //////////////////////////////// //~ Gpu buffer helpers -#define AcquireUploadBuffer(src, type, count) AcquireUploadBuffer_((src), sizeof(type), (count)) -#define AcquireUploadBufferFromArena(arena, type) AcquireUploadBufferFromArena_((arena), sizeof(type)) - GPU_Resource *AcquireGbuffer(GPU_Format format, Vec2I32 size); -GPU_Resource *AcquireUploadBuffer_(void *src, u32 element_size, u32 element_count); -GPU_Resource *AcquireUploadBufferFromArena_(Arena *arena, u32 element_size); -JobDecl(DelayReleaseGpuResources, { Fence *begin_fence; u64 begin_fence_target; GPU_Resource **resources; GPU_ReleaseFlag flags; }); //////////////////////////////// //~ Entity sorting diff --git a/src/ui/ui.c b/src/ui/ui.c index 403472d2..84e54a49 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -28,9 +28,9 @@ void UI_PushTagFromHash(u64 hash) { hash = RandU64FromSeeds(hash, g->top_tag->hash); } - UI_Tag *tag = PushStruct(g->build_arena, UI_Tag); - StackPush(g->top_tag, tag); - tag->hash = hash; + UI_TagNode *n = PushStruct(g->build_arena, UI_TagNode); + StackPush(g->top_tag, n); + n->hash = hash; } void UI_PushTagFromString(String str) @@ -42,9 +42,9 @@ void UI_PushTagFromString(String str) hash = g->top_tag->hash; } hash = HashFnv64(hash, str); - UI_Tag *tag = PushStruct(g->build_arena, UI_Tag); - StackPush(g->top_tag, tag); - tag->hash = hash; + UI_TagNode *n = PushStruct(g->build_arena, UI_TagNode); + n->hash = hash; + StackPush(g->top_tag, n); } void UI_PushTagF_(char *fmt_cstr, ...) @@ -63,8 +63,7 @@ void UI_PushTagF_(char *fmt_cstr, ...) void UI_PopTag(void) { - UI_SharedState *g = &UI_shared_state; - StackPop(g->top_tag); + StackPop(UI_shared_state.top_tag); } //- Parent @@ -72,15 +71,46 @@ void UI_PopTag(void) void UI_PushParent(UI_Box *box) { UI_SharedState *g = &UI_shared_state; - UI_Parent *parent = PushStruct(g->build_arena, UI_Parent); - parent->box = box; - StackPush(g->top_parent, parent); + UI_ParentNode *n = PushStruct(g->build_arena, UI_ParentNode); + n->box = box; + StackPush(g->top_parent, n); } void UI_PopParent(void) +{ + StackPop(UI_shared_state.top_parent); +} + +//- Size + +void UI_PushSize(Axis axis, UI_SizeKind kind, f32 v, f32 strictness) { UI_SharedState *g = &UI_shared_state; - StackPop(g->top_parent); + UI_SizeNode *n = PushStruct(g->build_arena, UI_SizeNode); + n->size.kind = kind; + n->size.v = v; + n->size.strictness = strictness; + StackPush(g->top_size[axis], n); +} + +void UI_PopSize(Axis axis) +{ + StackPop(UI_shared_state.top_size[axis]); +} + +//- Layout dir + +void UI_PushLayoutDir(Axis dir) +{ + UI_SharedState *g = &UI_shared_state; + UI_AxisNode *n = PushStruct(g->build_arena, UI_AxisNode); + n->axis = dir; + StackPush(g->top_layout_dir, n); +} + +void UI_PopLayoutDir(void) +{ + StackPop(UI_shared_state.top_layout_dir); } //////////////////////////////// @@ -131,16 +161,21 @@ UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key) box->key = key; box->flags = flags; + + box->tint = 0xFFFFFFFF; + + /* Pull from stack */ box->parent = g->top_parent->box; + box->pref_size[Axis_X] = g->top_size[Axis_X]->size; + box->pref_size[Axis_Y] = g->top_size[Axis_Y]->size; + box->layout_dir = g->top_layout_dir->axis; + DllPushBack(g->top_parent->box->first, g->top_parent->box->last, box); ++box->parent->count; return box; } -//////////////////////////////// -//~ Text - void UI_SetDisplayText(UI_Box *box, String str) { UI_SharedState *g = &UI_shared_state; @@ -148,9 +183,6 @@ void UI_SetDisplayText(UI_Box *box, String str) box->display_text = text; } -//////////////////////////////// -//~ Image - void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img) { box->display_image = img; @@ -187,8 +219,6 @@ void UI_BeginBuild(void) /* Init root box */ g->root_box = PushStruct(g->build_arena, UI_Box); g->root_box->key = UI_RootKey; - g->root_box->pref_size[Axis_X].kind = UI_SizeKind_Absolute; - g->root_box->pref_size[Axis_Y].kind = UI_SizeKind_Absolute; UI_BoxBin *bin = &g->box_bins[g->root_box->key.hash % UI_NumBoxLookupBins]; DllPushBackNP(bin->first, bin->last, g->root_box, next_in_bin, prev_in_bin); ++g->boxes_count; @@ -196,6 +226,9 @@ void UI_BeginBuild(void) /* Init stacks */ UI_PushTagF("root"); UI_PushParent(g->root_box); + UI_PushSize(Axis_X, UI_SizeKind_Percent, 1, 0); + UI_PushSize(Axis_Y, UI_SizeKind_Percent, 1, 0); + UI_PushLayoutDir(Axis_X); if (!g->back_build_arena) { @@ -207,7 +240,7 @@ void UI_BeginBuild(void) //////////////////////////////// //~ End build -GPU_Resource *UI_EndBuild(void) +GPU_Resource *UI_EndBuild(Rect render_viewport) { TempArena scratch = BeginScratchNoConflict(); UI_SharedState *g = &UI_shared_state; @@ -218,9 +251,10 @@ GPU_Resource *UI_EndBuild(void) //- Layout /* Init root size */ - Vec2I32 root_size = VEC2I32(500, 500); - g->root_box->p0 = VEC2(0, 0); - g->root_box->p1 = VEC2(root_size.x, root_size.y); + g->root_box->pref_size[Axis_X].kind = UI_SizeKind_Pixel; + g->root_box->pref_size[Axis_X].v = render_viewport.size.x; + g->root_box->pref_size[Axis_Y].kind = UI_SizeKind_Pixel; + g->root_box->pref_size[Axis_Y].v = render_viewport.size.y; /* Build pre-order & post-order box arrays */ u64 boxes_count = g->boxes_count; @@ -263,21 +297,21 @@ GPU_Resource *UI_EndBuild(void) } /* Calculate independent sizes */ - for (u64 box_index = 1; box_index < boxes_count; ++box_index) + for (u64 box_index = 0; box_index < boxes_count; ++box_index) { UI_Box *box = boxes_pre[box_index]; for (Axis axis = 0; axis < Axis_CountXY; ++axis) { UI_Size pref_size = box->pref_size[axis]; - if (pref_size.kind == UI_SizeKind_Absolute) + if (pref_size.kind == UI_SizeKind_Pixel) { - box->solved_size[axis].v = pref_size.v; + box->solved_dims[axis] = pref_size.v; } else if (pref_size.kind == UI_SizeKind_Text) { /* FIXME: Calculate actual text size here */ f32 text_size = 10; - box->solved_size[axis].v = text_size; + box->solved_dims[axis] = text_size; } } } @@ -292,21 +326,39 @@ GPU_Resource *UI_EndBuild(void) if (pref_size.kind == UI_SizeKind_Percent) { UI_Box *ancestor = box->parent; - UI_Size ancestor_size = ZI; + f32 ancestor_size = 0; for (; ancestor; ancestor = ancestor->parent) { - UI_Size tmp = ancestor->solved_size[axis]; - if (tmp.kind == UI_SizeKind_Absolute || tmp.kind == UI_SizeKind_Text) + UI_Size tmp = ancestor->pref_size[axis]; + if (tmp.kind == UI_SizeKind_Pixel || tmp.kind == UI_SizeKind_Text) { - ancestor_size = tmp; + ancestor_size = ancestor->solved_dims[axis]; break; } } - // box->solved_size = + box->solved_dims[axis] = pref_size.v * ancestor_size; } } } + /* Calculate final positions */ + for (u64 box_index = 0; box_index < boxes_count; ++box_index) + { + UI_Box *box = boxes_pre[box_index]; + UI_Box *parent = box->parent; + Vec2 final_size = VEC2(box->solved_dims[0], box->solved_dims[1]); + if (parent) + { + b32 is_layout_x = parent->layout_dir == Axis_X; + f32 layout_cursor = parent->layout_cursor; + Vec2 offset = VEC2(layout_cursor * is_layout_x, layout_cursor * !is_layout_x); + parent->layout_cursor += final_size.x * is_layout_x + final_size.y * is_layout_x; + box->p0 = AddVec2(parent->p0, offset); + } + box->p1 = AddVec2(box->p0, final_size); + } + + /* TODO: Remove this */ #if 0 { @@ -351,33 +403,46 @@ GPU_Resource *UI_EndBuild(void) #endif //////////////////////////////// - //- Build instances + //- Build render data + + /* Init transient buffers */ + if (!g->draw_rects_tbuff) + { + g->draw_rects_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, UI_RectInstance); + } + Arena *draw_rects_arena = GPU_ArenaFromTransientBuffer(g->draw_rects_tbuff); GPU_QueueKind render_queue = GPU_QueueKind_Direct; Fence *render_fence = GPU_FenceFromQueue(render_queue); /* Init render state */ - if (!g->draw_rects_arena) + if (!draw_rects_arena) { - g->draw_rects_arena = AcquireArena(Gibi(64)); + draw_rects_arena = AcquireArena(Gibi(64)); } /* Build rect instance data */ for (u64 box_index = 0; box_index < boxes_count; ++box_index) { UI_Box *box = boxes_pre[box_index]; - UI_RectInstance *rect = PushStruct(g->draw_rects_arena, UI_RectInstance); + UI_RectInstance *rect = PushStruct(draw_rects_arena, UI_RectInstance); + rect->flags = box->flags; rect->p0 = box->p0; rect->p1 = box->p1; - rect->tint_srgb = 0xFFFFFFFF; + rect->tint_srgb = box->tint; + + if (box->flags & UI_Flag_DrawImage, box->display_image) + { + rect->image_tex = GPU_Texture2DRidFromResource(box->display_image); + } } //////////////////////////////// //- Render - /* Acquire render target */ - if (g->render_target && !EqVec2I32(root_size, GPU_GetTextureSize2D(g->render_target))) + /* Init render target */ + if (g->render_target && !EqVec2I32(VEC2I32(render_viewport.size.x, render_viewport.size.y), GPU_GetTextureSize2D(g->render_target))) { YieldOnFence(render_fence, g->render_fence_target); GPU_ReleaseResource(g->render_target, GPU_ReleaseFlag_None); @@ -389,18 +454,53 @@ GPU_Resource *UI_EndBuild(void) desc.kind = GPU_ResourceKind_Texture2D; desc.flags = GPU_ResourceFlag_Renderable; desc.texture.format = GPU_Format_R8G8B8A8_Unorm; - desc.texture.size = VEC3I32(root_size.x, root_size.y, 1); + desc.texture.size = VEC3I32(render_viewport.size.x, render_viewport.size.y, 1); g->render_target = GPU_AcquireResource(desc); } + /* Upload transient buffers */ + GPU_Resource *draw_rects_buffer = GPU_UploadTransientBuffer(g->draw_rects_tbuff); + u32 draw_rects_count = GPU_GetBufferCount(draw_rects_buffer); + /* Build command list */ GPU_CommandList *cl = GPU_BeginCommandList(render_queue); { + //- Prep rect pass + { + __profn("Clear target"); + GPU_ProfN(cl, Lit("Clear target")); + GPU_TransitionToRenderable(cl, g->render_target, 0); + GPU_ClearRenderable(cl, g->render_target); + } + + //- Rect pass + if (draw_rects_count > 0) + { + __profn("Rect pass"); + GPU_ProfN(cl, Lit("Rect pass")); + + GPU_Viewport viewport = GPU_ViewportFromRect(render_viewport); + GPU_Scissor scissor = GPU_ScissorFromRect(render_viewport); + + UI_RectSig sig = ZI; + sig.viewport_size = RoundVec2ToVec2I32(render_viewport.size); + sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler()); + sig.instances = GPU_StructuredBufferRidFromResource(draw_rects_buffer); + GPU_Rasterize(cl, + &sig, + UI_RectVS, UI_RectPS, + 1, + viewport, + scissor, + draw_rects_count, + GPU_GetCommonQuadIndices(), + GPU_RasterizeMode_TriangleList); + } } g->render_fence_target = GPU_EndCommandList(cl); - /* Reset render state */ - ResetArena(g->draw_rects_arena); + /* Reset transient buffers */ + GPU_ResetTransientBuffer(g->draw_rects_tbuff, g->render_fence_target); EndScratch(scratch); return g->render_target; diff --git a/src/ui/ui.h b/src/ui/ui.h index 7bef02d0..9bde0f3a 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -16,7 +16,7 @@ Enum(UI_SizeKind) { UI_SizeKind_Children, UI_SizeKind_Percent, - UI_SizeKind_Absolute, + UI_SizeKind_Pixel, UI_SizeKind_Text, }; @@ -24,18 +24,12 @@ Struct(UI_Size) { UI_SizeKind kind; f32 v; + f32 strictness; }; //////////////////////////////// //~ Box types -Enum(UI_Flag) -{ - UI_Flag_None = 0, - UI_Flag_DrawText = (1 << 0), - UI_Flag_DrawImage = (1 << 1), -}; - Struct(UI_Box) { //- Hash list @@ -58,9 +52,12 @@ Struct(UI_Box) String display_text; GPU_Resource *display_image; UI_Size pref_size[Axis_CountXY]; + Axis layout_dir; + u32 tint; - //- Solver data - UI_Size solved_size[Axis_CountXY]; + //- Layout data + f32 solved_dims[Axis_CountXY]; + f32 layout_cursor; //- Post-solve data Vec2 p0; @@ -76,8 +73,10 @@ Struct(UI_BoxBin) //////////////////////////////// //~ Stack types -Struct(UI_Tag) { UI_Tag *next; u64 hash; }; -Struct(UI_Parent) { UI_Parent *next; UI_Box *box; }; +Struct(UI_TagNode) { UI_TagNode *next; u64 hash; }; +Struct(UI_ParentNode) { UI_ParentNode *next; UI_Box *box; }; +Struct(UI_SizeNode) { UI_SizeNode *next; UI_Size size; }; +Struct(UI_AxisNode) { UI_AxisNode *next; Axis axis; }; //////////////////////////////// //~ State types @@ -100,13 +99,15 @@ Struct(UI_SharedState) u64 back_boxes_count; //- Stack state - UI_Tag *top_tag; - UI_Parent *top_parent; + UI_TagNode *top_tag; + UI_ParentNode *top_parent; + UI_SizeNode *top_size[Axis_CountXY]; + UI_AxisNode *top_layout_dir; //- Render state GPU_Resource *render_target; i64 render_fence_target; - Arena *draw_rects_arena; + GPU_TransientBuffer *draw_rects_tbuff; } extern UI_shared_state; //////////////////////////////// @@ -128,12 +129,21 @@ void UI_PopTag(void); void UI_PushParent(UI_Box *box); void UI_PopParent(void); +//- Size +void UI_PushSize(Axis axis, UI_SizeKind kind, f32 v, f32 strictness); +void UI_PopSize(Axis axis); + +//- Layout dir +void UI_PushLayoutDir(Axis dir); +void UI_PopLayoutDir(void); + //////////////////////////////// //~ Box UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key); void UI_SetDisplayText(UI_Box *box, String str); +void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img); //////////////////////////////// //~ Image @@ -148,114 +158,4 @@ void UI_BeginBuild(void); //////////////////////////////// //~ End build -GPU_Resource *UI_EndBuild(void); - - - - - - - - - - - - - - - -/* TODO: Remove this */ - -#if 0 - -//////////////////////////////// -//~ Rect - -Struct(UI_RectParams) -{ - Xform xf; - GPU_Resource *texture; - ClipRect clip; - u32 tint; -}; -#define UI_RECTPARAMS(...) ((UI_RectParams) { \ - .tint = ColorWhite, \ - .clip = AllClipped, \ - __VA_ARGS__ \ -}) - -//////////////////////////////// -//~ Text types - -/* How is text aligned within its area */ -Enum(UI_TextAlignment) -{ - UI_TextAlignment_Left, /* Default */ - UI_TextAlignment_Center, - UI_TextAlignment_Right -}; - -/* How does the specified text position relate to the text area. - * E.g. Bottom & Right means the bottom-right of the text area will snap to - * the specified position. */ -Enum(UI_TextOffsetX) -{ - UI_TextOffsetX_Left, /* Default */ - UI_TextOffsetX_Center, - UI_TextOffsetX_Right -}; - -Enum(UI_TextOffsetY) -{ - UI_TextOffsetY_Top, /* Default */ - UI_TextOffsetY_Center, - UI_TextOffsetY_Bottom -}; - -Struct(UI_TextGlyph) -{ - f32 off_x; - f32 off_y; - f32 width; - f32 height; - f32 advance; - ClipRect clip; -}; - -Struct(UI_TextLine) -{ - f32 line_width; - u32 num_glyphs; - UI_TextGlyph *glyphs; - UI_TextLine *next; -}; - -Struct(UI_TextParams) -{ - F_Font *font; - Vec2 pos; - f32 scale; - u32 color; - UI_TextAlignment alignment; - UI_TextOffsetX offset_x; - UI_TextOffsetY offset_y; - String str; -}; -#define UI_TEXTPARAMS(...) ((UI_TextParams) { \ - .scale = 1.0, \ - .alignment = UI_TextAlignment_Left, \ - .offset_x = UI_TextOffsetX_Left, \ - .offset_y = UI_TextOffsetY_Top, \ - .color = ColorWhite, \ - __VA_ARGS__ \ -})s - -//////////////////////////////// -//~ State types - -Struct(UI_SharedState) -{ - i32 _; -} extern UI_shared_state; - -#endif +GPU_Resource *UI_EndBuild(Rect render_viewport); diff --git a/src/ui/ui.lay b/src/ui/ui.lay index b14a03c5..b99d3e0c 100644 --- a/src/ui/ui.lay +++ b/src/ui/ui.lay @@ -4,14 +4,16 @@ @Dep gpu //- Api +@IncludeC ui_flags.h @IncludeC ui.h -@IncludeC ui_widgets.h +@IncludeC ui_util.h @IncludeC ui_draw.h +@IncludeGpu ui_flags.h @IncludeGpu ui_draw.h //- Impl @IncludeC ui.c -@IncludeC ui_widgets.c +@IncludeC ui_util.c @IncludeGpu ui_draw.gpu //- Shaders diff --git a/src/ui/ui_draw.gpu b/src/ui/ui_draw.gpu index 178583cd..8df26757 100644 --- a/src/ui/ui_draw.gpu +++ b/src/ui/ui_draw.gpu @@ -5,7 +5,11 @@ ConstantBuffer UI_rect_sig : register (b0); Struct(UI_RectPS_Input) { + Semantic(Vec4, sv_position); + Semantic(Vec4, tint_lin); + Semantic(Vec2, uv); + Semantic(nointerpolation u32, instance_idx); }; Struct(UI_RectPS_Output) @@ -18,21 +22,25 @@ Struct(UI_RectPS_Output) UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid)) { ConstantBuffer sig = UI_rect_sig; - static const Vec2 unit_quad_verts[4] = { - Vec2(-0.5f, -0.5f), - Vec2(0.5f, -0.5f), - Vec2(0.5f, 0.5f), - Vec2(-0.5f, 0.5f) + static const Vec2 uvs[4] = { + Vec2(0, 0), + Vec2(1, 0), + Vec2(1, 1), + Vec2(0, 1), }; StructuredBuffer instances = UniformResourceFromRid(sig.instances); UI_RectInstance instance = instances[sv_instanceid]; - Vec2 vert = unit_quad_verts[sv_vertexid]; - // Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy; - Vec2 world_pos = 0; + Vec2 uv = uvs[sv_vertexid]; + Vec2 vert = instance.p0 + (uv * instance.p1); + Vec2 ndc = NdcFromViewport(sig.viewport_size, vert); UI_RectPS_Input result; - result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1)); + result.sv_position = Vec4(ndc.xy, 0, 1); + result.tint_lin = LinearFromSrgbU32(instance.tint_srgb); + result.instance_idx = sv_instanceid; + result.uv = uv; + return result; } @@ -41,7 +49,17 @@ UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_ UI_RectPS_Output PSDef(UI_RectPS, UI_RectPS_Input input) { ConstantBuffer sig = UI_rect_sig; - f32 color = 0; + StructuredBuffer instances = UniformResourceFromRid(sig.instances); + UI_RectInstance instance = instances[input.instance_idx]; + + Vec4 color = input.tint_lin; + + if (instance.flags & UI_Flag_DrawImage) + { + SamplerState sampler = UniformSamplerFromRid(sig.sampler); + Texture2D tex = NonUniformResourceFromRid(instance.image_tex); + color *= tex.Sample(sampler, input.uv); + } UI_RectPS_Output result; result.sv_target0 = color; diff --git a/src/ui/ui_draw.h b/src/ui/ui_draw.h index bafb5ff1..c5fab058 100644 --- a/src/ui/ui_draw.h +++ b/src/ui/ui_draw.h @@ -4,21 +4,20 @@ Struct(UI_RectSig) { /* ----------------------------------------------------- */ - Mat4x4 projection; /* 16 consts */ - /* ----------------------------------------------------- */ + Vec2I32 viewport_size; /* 02 consts */ StructuredBufferRid instances; /* 01 consts */ - u32 _pad0; /* 01 consts (padding) */ - u32 _pad1; /* 01 consts (padding) */ - u32 _pad2; /* 01 consts (padding) */ + SamplerStateRid sampler; /* 01 consts */ /* ----------------------------------------------------- */ }; -AssertRootConst(UI_RectSig, 20); +AssertRootConst(UI_RectSig, 4); Struct(UI_RectInstance) { + u32 flags; Vec2 p0; Vec2 p1; u32 tint_srgb; + Texture2DRid image_tex; }; #define UI_DefaultRectInstance (UI_RectInstance) { \ 0 \ diff --git a/src/ui/ui_flags.h b/src/ui/ui_flags.h new file mode 100644 index 00000000..d4a855f8 --- /dev/null +++ b/src/ui/ui_flags.h @@ -0,0 +1,8 @@ +/* NOTE: UI flags are located here since they are shared between application & shader code */ + +Enum(UI_Flag) +{ + UI_Flag_None = 0, + UI_Flag_DrawText = (1 << 0), + UI_Flag_DrawImage = (1 << 1), +}; diff --git a/src/ui/ui_widgets.c b/src/ui/ui_util.c similarity index 100% rename from src/ui/ui_widgets.c rename to src/ui/ui_util.c diff --git a/src/ui/ui_widgets.h b/src/ui/ui_util.h similarity index 100% rename from src/ui/ui_widgets.h rename to src/ui/ui_util.h