From 5d2662e56762529327b277482812adff3bd04c3a Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 21 Oct 2025 16:30:27 -0500 Subject: [PATCH] transient gpu buffers --- src/gpu/gpu_util.c | 141 +++++++++++++++++++++------------------------ src/gpu/gpu_util.h | 35 +++++------ src/pp/pp.c | 62 ++++++++++---------- src/pp/pp.h | 17 ++++-- src/ui/ui.c | 21 +++---- src/ui/ui.h | 6 +- 6 files changed, 139 insertions(+), 143 deletions(-) diff --git a/src/gpu/gpu_util.c b/src/gpu/gpu_util.c index 401bdc1e..2f4d554a 100644 --- a/src/gpu/gpu_util.c +++ b/src/gpu/gpu_util.c @@ -106,56 +106,45 @@ 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) +GPU_TransientBuffer GPU_AcquireTransientBuffer(GPU_QueueKind queue_kind, u32 element_size) { - 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; - + GPU_TransientBuffer tbuff = ZI; + tbuff.element_size = MaxU32(element_size, 1); + tbuff.queue_kind = queue_kind; return tbuff; } void GPU_ReleaseTransientBuffer(GPU_TransientBuffer *tbuff) { + GPU_SharedUtilState *g = &GPU_shared_util_state; + 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) + if (tbuff->first_submitted) { - GPU_ReleaseResource(submitted->resource, GPU_ReleaseFlag_None); - } + for (GPU_SubmittedResourceNode *submitted = tbuff->first_submitted; + submitted; + submitted = submitted->next) + { + GPU_ReleaseResource(submitted->resource, GPU_ReleaseFlag_None); + } - ReleaseArena(tbuff->arena); + Lock lock = LockE(&g->submitted_transient_buffers_mutex); + { + tbuff->last_submitted->next = g->first_free_submitted_transient_buffer; + g->first_free_submitted_transient_buffer = tbuff->first_submitted; + } + Unlock(&lock); + } } -GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff) +GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff, void *src, u64 src_size) { + GPU_SharedUtilState *g = &GPU_shared_util_state; GPU_Resource *resource = 0; - u32 element_count = (tbuff->arena->pos - tbuff->elements_start_pos) / tbuff->element_size; + u64 element_count = src_size / tbuff->element_size; Fence *queue_fence = GPU_FenceFromQueue(tbuff->queue_kind); i64 queue_fence_value = FetchFence(queue_fence); @@ -165,72 +154,76 @@ GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff) Panic(Lit("GPU transient buffer uploaded without a reset")); } - /* Grab resource */ - GPU_SubmittedTransientBufferResource *upload = 0; + /* Grab resource node */ + GPU_SubmittedResourceNode *upload = 0; { - GPU_SubmittedTransientBufferResource *submitted = tbuff->first_submitted; - if (submitted && submitted->fence_target <= queue_fence_value) + if (tbuff->first_submitted && tbuff->first_submitted->fence_target <= queue_fence_value) { - upload = submitted; + upload = tbuff->first_submitted; QueuePop(tbuff->first_submitted, tbuff->last_submitted); } - else if (tbuff->first_free) + if (!upload) { - /* Resource in upload, create new */ - upload = tbuff->first_free; - StackPop(tbuff->first_free); + Lock lock = LockE(&g->submitted_transient_buffers_mutex); + { + upload = g->first_free_submitted_transient_buffer; + if (upload) + { + g->first_free_submitted_transient_buffer = upload->next; + StackPop(g->first_free_submitted_transient_buffer); + } + } + Unlock(&lock); } - else + if (!upload) { - /* 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); + Arena *perm = PermArena(); + upload = PushStruct(perm, GPU_SubmittedResourceNode); } } - if (upload->resource) + /* Create gpu resource */ { - GPU_ReleaseResource(upload->resource, GPU_ReleaseFlag_Reuse); - upload->resource = 0; + 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); } - 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); - + /* Fill gpu resource */ { __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); + CopyBytes(m.mem, src, src_size); GPU_Unmap(m); } tbuff->uploaded = upload; - tbuff->uploaded_element_count = element_count; - return upload->resource; } +GPU_Resource *GPU_UploadTransientBufferFromArena(GPU_TransientBuffer *tbuff, Arena *arena) +{ + u32 element_count = arena->pos / tbuff->element_size; + GPU_Resource *result = GPU_UploadTransientBuffer(tbuff, ArenaBase(arena), tbuff->element_size * element_count); + return result; +} + void GPU_ResetTransientBuffer(GPU_TransientBuffer *tbuff, i64 queue_fence_target) { - PopTo(tbuff->arena, tbuff->elements_start_pos); - GPU_SubmittedTransientBufferResource *use = tbuff->uploaded; - if (use) + GPU_SubmittedResourceNode *uploaded = tbuff->uploaded; + if (uploaded) { - use->fence_target = queue_fence_target; - QueuePush(tbuff->first_submitted, tbuff->last_submitted, use); + uploaded->fence_target = queue_fence_target; + QueuePush(tbuff->first_submitted, tbuff->last_submitted, uploaded); 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 index 8d91853a..cbb971ce 100644 --- a/src/gpu/gpu_util.h +++ b/src/gpu/gpu_util.h @@ -1,30 +1,25 @@ //////////////////////////////// //~ Transient buffer types -Struct(GPU_SubmittedTransientBufferResource) +Struct(GPU_SubmittedResourceNode) { - GPU_SubmittedTransientBufferResource *next; + GPU_SubmittedResourceNode *next; - i64 fence_target; /* Once the buffer's queue reaches the target, the resource can be freed or reused */ + /* Set during transient upload */ GPU_Resource *resource; + + /* Set during transient reset */ + i64 fence_target; /* Once the buffer's queue reaches the target, the resource can be freed or reused */ }; 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; + GPU_SubmittedResourceNode *uploaded; + GPU_SubmittedResourceNode *first_submitted; + GPU_SubmittedResourceNode *last_submitted; u32 max_in_flight; }; @@ -38,6 +33,10 @@ Struct(GPU_SharedUtilState) GPU_Resource *pt_sampler; GPU_Resource *quad_indices; GPU_Resource *noise; + + /* Transient buffer pool */ + Mutex submitted_transient_buffers_mutex; + GPU_SubmittedResourceNode *first_free_submitted_transient_buffer; } extern GPU_shared_util_state; //////////////////////////////// @@ -55,11 +54,9 @@ 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)) +GPU_TransientBuffer GPU_AcquireTransientBuffer(GPU_QueueKind queue_kind, u32 element_size); void GPU_ReleaseTransientBuffer(GPU_TransientBuffer *tbuff); -GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff); +GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff, void *src, u64 src_size); +GPU_Resource *GPU_UploadTransientBufferFromArena(GPU_TransientBuffer *tbuff, Arena *arena); 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 3208ed14..a02222b8 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -455,19 +455,19 @@ void UpdateUser(P_Window *window) UI_PushParent(pp_root_box); //- Init render data buffers - if (!g->material_instances_tbuff) + if (!g->material_instances_arena) { - 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); + g->material_instances_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(MaterialInstance)); + g->ui_rect_instances_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(UiRectInstance)); + g->ui_shape_verts_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(UiShapeVert)); + g->ui_shape_indices_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(u32)); + g->grids_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(MaterialGrid)); + 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)); } - 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 @@ -987,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(grids_arena, MaterialGrid); + MaterialGrid *grid = PushStruct(g->grids_arena, MaterialGrid); *grid = DefaultMaterialGrid; grid->line_thickness = thickness; grid->line_spacing = spacing; @@ -998,12 +998,9 @@ void UpdateUser(P_Window *window) grid->x_srgb = ColorRed; grid->y_srgb = ColorGreen; - MaterialInstance *mat = PushStruct(material_instances_arena, MaterialInstance); + MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance); *mat = DefaultMaterialInstance; - // TODO - // BROKE - // FIXME - mat->grid_id = grid - (MaterialGrid *)ArenaBase(grids_arena); + mat->grid_id = grid - (MaterialGrid *)ArenaBase(g->grids_arena); mat->xf = XformFromRect(RectFromVec2(pos, size)); } @@ -1222,7 +1219,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(material_instances_arena, MaterialInstance); + MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance); *mat = DefaultMaterialInstance; mat->xf = sprite_xform; mat->tex = GPU_Texture2DRidFromResource(texture->gpu_texture); @@ -1257,7 +1254,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(material_instances_arena, MaterialInstance); + MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance); *mat = DefaultMaterialInstance; mat->xf = tile_xf; mat->tex = GPU_Texture2DRidFromResource(tile_texture->gpu_texture); @@ -2283,11 +2280,11 @@ void UpdateUser(P_Window *window) } /* 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); + GPU_Resource *material_instances_buffer = GPU_UploadTransientBufferFromArena(&g->material_instances_tbuff, g->material_instances_arena); + GPU_Resource *ui_rect_instances_buffer = GPU_UploadTransientBufferFromArena(&g->ui_rect_instances_tbuff, g->ui_rect_instances_arena); + GPU_Resource *ui_shape_verts_buffer = GPU_UploadTransientBufferFromArena(&g->ui_shape_verts_tbuff, g->ui_shape_verts_arena); + GPU_Resource *ui_shape_indices_buffer = GPU_UploadTransientBufferFromArena(&g->ui_shape_indices_tbuff, g->ui_shape_indices_arena); + GPU_Resource *grids_buffer = GPU_UploadTransientBufferFromArena(&g->grids_tbuff, g->grids_arena); 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); @@ -2531,12 +2528,17 @@ void UpdateUser(P_Window *window) } g->gpu_render_fence_target = GPU_EndCommandList(cl); - /* 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); + /* Reset render data */ + 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); + 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); } /* Render UI */ diff --git a/src/pp/pp.h b/src/pp/pp.h index 7355f1bc..262cf6ba 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -181,12 +181,17 @@ 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 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; + Arena *material_instances_arena; + Arena *ui_rect_instances_arena; + Arena *ui_shape_verts_arena; + Arena *ui_shape_indices_arena; + Arena *grids_arena; //- Renderer state RandState frame_rand; diff --git a/src/ui/ui.c b/src/ui/ui.c index 84e54a49..1946c119 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -406,26 +406,20 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) //- Build render data /* Init transient buffers */ - if (!g->draw_rects_tbuff) + if (!g->draw_rects_arena) { - g->draw_rects_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, UI_RectInstance); + g->draw_rects_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(UI_RectInstance)); + g->draw_rects_arena = AcquireArena(Gibi(64)); } - 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 (!draw_rects_arena) - { - 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(draw_rects_arena, UI_RectInstance); + UI_RectInstance *rect = PushStruct(g->draw_rects_arena, UI_RectInstance); rect->flags = box->flags; rect->p0 = box->p0; @@ -459,7 +453,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) } /* Upload transient buffers */ - GPU_Resource *draw_rects_buffer = GPU_UploadTransientBuffer(g->draw_rects_tbuff); + GPU_Resource *draw_rects_buffer = GPU_UploadTransientBufferFromArena(&g->draw_rects_tbuff, g->draw_rects_arena); u32 draw_rects_count = GPU_GetBufferCount(draw_rects_buffer); /* Build command list */ @@ -499,8 +493,9 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) } g->render_fence_target = GPU_EndCommandList(cl); - /* Reset transient buffers */ - GPU_ResetTransientBuffer(g->draw_rects_tbuff, g->render_fence_target); + /* Reset render data */ + GPU_ResetTransientBuffer(&g->draw_rects_tbuff, g->render_fence_target); + ResetArena(g->draw_rects_arena); EndScratch(scratch); return g->render_target; diff --git a/src/ui/ui.h b/src/ui/ui.h index 9bde0f3a..c14db5ef 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -107,7 +107,11 @@ Struct(UI_SharedState) //- Render state GPU_Resource *render_target; i64 render_fence_target; - GPU_TransientBuffer *draw_rects_tbuff; + + + GPU_TransientBuffer draw_rects_tbuff; + Arena *draw_rects_arena; + } extern UI_shared_state; ////////////////////////////////