transient gpu buffers

This commit is contained in:
jacob 2025-10-21 16:30:27 -05:00
parent 69a8f2e1a3
commit 5d2662e567
6 changed files with 139 additions and 143 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;
////////////////////////////////