From 6c3c7231ffa9ccd7112723928ed5f36a1c92ef3c Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 13 Dec 2025 18:41:01 -0600 Subject: [PATCH] descriptor reuse --- src/config.h | 4 +- src/gpu/gpu_dx12/gpu_dx12_core.c | 260 +++++++++++++++++++++++-------- src/gpu/gpu_dx12/gpu_dx12_core.h | 101 ++++++------ src/ui/ui_core.c | 2 +- 4 files changed, 259 insertions(+), 108 deletions(-) diff --git a/src/config.h b/src/config.h index 6329442a..960b7842 100644 --- a/src/config.h +++ b/src/config.h @@ -69,8 +69,8 @@ #define FLOOD_DEBUG 0 -#define GPU_DEBUG 0 -#define GPU_DEBUG_VALIDATION 0 +#define GPU_DEBUG 1 +#define GPU_DEBUG_VALIDATION 1 #define GPU_SHADER_PRINT 1 #define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64); diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index f4496b6b..4f79c43d 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -202,6 +202,7 @@ void G_Bootstrap(void) G_D12_DescriptorHeap *heap = &g->descriptor_heaps[kind]; heap->descriptors_arena = AcquireArena(Gibi(1)); + heap->kind = kind; heap->type = desc.type; heap->max_count = desc.max; heap->descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(g->device, desc.type); @@ -724,23 +725,25 @@ i64 G_D12_CommitRawCommandList(G_D12_RawCommandList *cl) } /* Commit */ - i64 completion = 0; + i64 completion_target = 0; { + /* Execute */ + ID3D12CommandQueue_ExecuteCommandLists(queue->d3d_queue, 1, (ID3D12CommandList **)&cl->d3d_cl); + Lock lock = LockE(&queue->commit_mutex); { - completion = ++queue->commit_fence_target; - cl->commit_fence_target = completion; + completion_target = ++queue->commit_fence_target; + cl->commit_fence_target = completion_target; - /* Execute */ - ID3D12CommandQueue_ExecuteCommandLists(queue->d3d_queue, 1, (ID3D12CommandList **)&cl->d3d_cl); - ID3D12CommandQueue_Signal(queue->d3d_queue, queue->commit_fence, completion); + ID3D12CommandQueue_Signal(queue->d3d_queue, queue->commit_fence, completion_target); /* Append */ SllQueuePush(queue->first_committed_cl, queue->last_committed_cl, cl); } Unlock(&lock); } - return completion; + + return completion_target; } //////////////////////////////////////////////////////////// @@ -780,11 +783,64 @@ void G_D12_ResetArena(G_D12_CmdList *cl, G_D12_Arena *gpu_arena) /* FIXME: Move descriptors into committed lists */ /* FIXME: Release id3d12 resource com object references */ + // for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx) + // { + // G_D12_ResourceHeap *heap = &gpu_arena->resource_heaps[heap_idx]; + // heap->pos = 0; + + // if (heap->first_reset_resource) + // { + // heap->last_reset_resource->next = heap->first_resource; + // } + // else + // { + // heap->first_reset_resource = heap->first_resource; + // } + // heap->last_reset_resource = heap->last_resource; + // heap->reset_resources_count += heap->resources_count; + // heap->resources_count = 0; + // heap->first_resource = 0; + // heap->last_resource = 0; + // } + + + + for (u64 heap_idx = 0; heap_idx < countof(gpu_arena->resource_heaps); ++heap_idx) { G_D12_ResourceHeap *heap = &gpu_arena->resource_heaps[heap_idx]; heap->pos = 0; + + /* FIXME: Free list if this actually works */ + for (G_D12_Resource *resource = heap->resources.first; resource; resource = resource->next) + { + ID3D12Resource_Release(resource->d3d_resource); + } + heap->resources.count = 0; + heap->resources.first = 0; + heap->resources.last = 0; } + + + + + /* Push descriptors to cl reset list */ + { + if (cl->reset_descriptors.last) + { + cl->reset_descriptors.last->next = gpu_arena->descriptors.first; + } + else + { + cl->reset_descriptors.first = gpu_arena->descriptors.first; + } + cl->reset_descriptors.last = gpu_arena->descriptors.last; + cl->reset_descriptors.count += gpu_arena->descriptors.count; + gpu_arena->descriptors.count = 0; + gpu_arena->descriptors.first = 0; + gpu_arena->descriptors.last = 0; + } + } //////////////////////////////////////////////////////////// @@ -891,16 +947,18 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_ResourceDesc desc) Panic(Lit("Gpu heap overflow")); } - hr = ID3D12Device10_CreatePlacedResource2(g->device, - heap->d3d_heap, - 0, - &d3d_desc, - D3D12_BARRIER_LAYOUT_UNDEFINED, - 0, - 0, - 0, - &IID_ID3D12Resource, - (void **)&heap->d3d_mapped_resource); + hr = ID3D12Device10_CreatePlacedResource2( + g->device, + heap->d3d_heap, + 0, + &d3d_desc, + D3D12_BARRIER_LAYOUT_UNDEFINED, + 0, + 0, + 0, + &IID_ID3D12Resource, + (void **)&heap->d3d_mapped_resource + ); } if (SUCCEEDED(hr)) { @@ -919,7 +977,7 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_ResourceDesc desc) } ////////////////////////////// - //- Create buffer / texture + //- Initialize d3d resource desc D3D12_BARRIER_LAYOUT initial_layout = D3D12_BARRIER_LAYOUT_UNDEFINED; D3D12_CLEAR_VALUE clear_value = ZI; @@ -964,34 +1022,72 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_ResourceDesc desc) } } - u64 alloc_size = 0; - u64 alloc_align = 0; + u64 align_in_heap = 0; + u64 size_in_heap = 0; { D3D12_RESOURCE_ALLOCATION_INFO alloc_info = ZI; ID3D12Device_GetResourceAllocationInfo(g->device, &alloc_info, 0, 1, (D3D12_RESOURCE_DESC *)&d3d_desc); - alloc_size = alloc_info.SizeInBytes; - alloc_align = alloc_info.Alignment; + align_in_heap = alloc_info.Alignment; + size_in_heap = alloc_info.SizeInBytes; } + ////////////////////////////// + //- Re-use existing resource + + // u64 pos_in_heap = 0; + // ID3D12Resource *d3d_resource = 0; + // { + // resource = heap->first_reset_resource; + // if (resource) + // { + // SllQueuePop(heap->first_reset_resource, heap->last_reset_resource); + // --heap->reset_resources_count; + // b32 can_use = 1; + // can_use = can_use && resource->is_texture == is_texture; + // can_use = can_use && resource->size_in_heap >= size_in_heap; + // can_use = can_use && resource->pos_in_heap % align_in_heap == 0; + // if (can_use) + // { + // d3d_resource = resource->d3d_resource; + // pos_in_heap = resource->pos_in_heap; + // size_in_heap = resource->size_in_heap; + // heap->pos = resource->pos_in_heap + resource->size_in_heap; + // } + // else + // { + // /* FIXME: Free d3d resource here? */ + // ZeroStruct(resource); + // } + // } + // if (!resource) + // { + // resource = PushStruct(gpu_arena->arena, G_D12_Resource); + // } + // } u64 pos_in_heap = 0; + ID3D12Resource *d3d_resource = 0; + { + resource = PushStruct(gpu_arena->arena, G_D12_Resource); + } + + ////////////////////////////// + //- Create new d3d resource + + if (!resource->d3d_resource) { pos_in_heap = heap->pos; - pos_in_heap = AlignU64(pos_in_heap, alloc_align); - heap->pos = pos_in_heap + alloc_size; - if (pos_in_heap + alloc_size > heap->size) + pos_in_heap = AlignU64(pos_in_heap, align_in_heap); + heap->pos = pos_in_heap + size_in_heap; + if (pos_in_heap + size_in_heap > heap->size) { Panic(Lit("Gpu arena overflow")); } - } - - ID3D12Resource *d3d_resource = 0; - { hr = ID3D12Device10_CreatePlacedResource2( g->device, heap->d3d_heap, pos_in_heap, &d3d_desc, - D3D12_BARRIER_LAYOUT_UNDEFINED, + initial_layout, (d3d_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? &clear_value : 0, 0, 0, @@ -1000,9 +1096,12 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_ResourceDesc desc) ); } - resource = PushStruct(gpu_arena->arena, G_D12_Resource); + ////////////////////////////// + //- Insert resource + resource->heap = heap; resource->pos_in_heap = pos_in_heap; + resource->size_in_heap = size_in_heap; resource->d3d_resource = d3d_resource; resource->uid = Atomic64FetchAdd(&g->resource_creation_gen.v, 1) + 1; resource->flags = flags; @@ -1010,6 +1109,7 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_ResourceDesc desc) { resource->buffer_size = desc.buffer.size; resource->buffer_size_actual = d3d_desc.Width; + /* TODO: Cache this */ resource->buffer_gpu_address = ID3D12Resource_GetGPUVirtualAddress(d3d_resource); } if (is_texture) @@ -1020,6 +1120,9 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_ResourceDesc desc) resource->texture_mip_levels = desc.texture.mip_levels; resource->texture_layout = initial_layout; } + + SllQueuePush(heap->resources.first, heap->resources.last, resource); + ++heap->resources.count; } ////////////////////////////// @@ -1052,32 +1155,30 @@ G_D12_Descriptor *G_D12_PushDescriptor(G_D12_Arena *gpu_arena, G_D12_DescriptorH G_D12_DescriptorHeap *heap = &g->descriptor_heaps[heap_kind]; G_D12_Descriptor *descriptor = 0; + u32 index = 0; /* Grab completed descriptor from arena */ - G_D12_DescriptorList *descriptors_by_queue = gpu_arena->committed_descriptors_by_heap_and_queue[heap_kind]; - for (G_QueueKind queue_kind = 0; !descriptor && queue_kind < G_NumQueues; ++queue_kind) + G_D12_DescriptorList *descriptors = &gpu_arena->reset_descriptors_by_heap[heap_kind]; + descriptor = descriptors->first; + if (descriptor) { - G_D12_DescriptorList *descriptors = &descriptors_by_queue[queue_kind]; - descriptor = descriptors->first; - if (descriptor) + G_D12_Queue *queue = G_D12_QueueFromKind(descriptor->completion_queue_kind); + i64 queue_commit_completion = ID3D12Fence_GetCompletedValue(queue->commit_fence); + if (queue_commit_completion >= descriptor->completion_queue_target) { - G_D12_Queue *queue = G_D12_QueueFromKind(queue_kind); - u64 queue_commit_completion = ID3D12Fence_GetCompletedValue(queue->commit_fence); - if (queue_commit_completion >= descriptor->queue_commit_target) - { - /* Descriptor no longer in use by gpu, reuse it */ - DllQueueRemove(descriptors->first, descriptors->last, descriptor); - } - else - { - /* Descriptor may still be in use by gpu */ - descriptor = 0; - } + /* Descriptor no longer in use by gpu, reuse it */ + SllQueuePop(descriptors->first, descriptors->last); + --descriptors->count; + index = descriptor->index; + } + else + { + /* Descriptor may still be in use by gpu */ + descriptor = 0; } } /* Allocate new descriptor from heap */ - u32 index = 0; if (!descriptor) { Lock lock = LockE(&heap->mutex); @@ -1085,7 +1186,7 @@ G_D12_Descriptor *G_D12_PushDescriptor(G_D12_Arena *gpu_arena, G_D12_DescriptorH if (heap->first_free) { descriptor = heap->first_free; - DllStackRemove(heap->first_free, descriptor); + SllStackPop(heap->first_free); index = descriptor->index; } else @@ -1104,9 +1205,13 @@ G_D12_Descriptor *G_D12_PushDescriptor(G_D12_Arena *gpu_arena, G_D12_DescriptorH /* Initialize descriptor handle */ ZeroStruct(descriptor); - descriptor->heap = heap; + descriptor->gpu_arena = gpu_arena; descriptor->index = index; descriptor->handle.ptr = heap->start_handle.ptr + (index * heap->descriptor_size); + descriptor->heap = heap; + + SllQueuePush(gpu_arena->descriptors.first, gpu_arena->descriptors.last, descriptor); + ++gpu_arena->descriptors.count; return descriptor; } @@ -1478,14 +1583,16 @@ G_D12_StagingRegionNode *G_D12_PushStagingRegion(G_D12_CmdList *cl, u64 size) d3d_desc.SampleDesc.Quality = 0; D3D12_HEAP_PROPERTIES heap_props = { .Type = D3D12_HEAP_TYPE_UPLOAD }; - HRESULT hr = ID3D12Device_CreateCommittedResource(g->device, - &heap_props, - D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, - &d3d_desc, - D3D12_RESOURCE_STATE_COMMON, - 0, - &IID_ID3D12Resource, - (void **)&d3d_resource); + HRESULT hr = ID3D12Device_CreateCommittedResource( + g->device, + &heap_props, + D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, + &d3d_desc, + D3D12_RESOURCE_STATE_COMMON, + 0, + &IID_ID3D12Resource, + (void **)&d3d_resource + ); if (!SUCCEEDED(hr)) { /* TODO: Don't panic */ @@ -2192,7 +2299,38 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle) } /* End dx12 command list */ - i64 completion = G_D12_CommitRawCommandList(rcl); + i64 completion_target = G_D12_CommitRawCommandList(rcl); + + /* Attach completion info to descriptors */ + for (G_D12_Descriptor *d = cl->reset_descriptors.first; d;) + { + G_D12_Descriptor *next = d->next; + { + G_D12_Arena *gpu_arena = d->gpu_arena; + d->completion_queue_kind = queue_kind; + d->completion_queue_target = completion_target; + G_D12_DescriptorList *gpu_arena_reset_descriptors_list = &gpu_arena->reset_descriptors_by_heap[d->heap->kind]; + SllQueuePush(gpu_arena_reset_descriptors_list->first, gpu_arena_reset_descriptors_list->last, d); + ++gpu_arena_reset_descriptors_list->count; + } + d = next; + } + + // /* Attach completion info to resources */ + // for (G_D12_Resource *r = cl->reset_resources.first; r;) + // { + // G_D12_Resource *next = r->next; + // { + // G_D12_ResourceHeap *heap = r->heap; + // G_D12_Arena *gpu_arena = >heap->gpu_arena; + // r->completion_queue_kind = queue->kind; + // r->completion_queue_target = completion_target; + // G_D12_ResourceList *heap_reset_resources_list = &heap->reset_resources; + // SllQueuePush(heap_reset_resources_list->first, heap_reset_resourecs_list->last, r); + // ++heap_reset_resources_list->count; + // } + // r = next; + // } /* Free command list */ { @@ -2205,7 +2343,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle) } EndScratch(scratch); - return completion; + return completion_target; } //- Arena diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.h b/src/gpu/gpu_dx12/gpu_dx12_core.h index 7048e3cd..78770be8 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.h +++ b/src/gpu/gpu_dx12/gpu_dx12_core.h @@ -55,6 +55,47 @@ Struct(G_D12_PipelineBin) G_D12_Pipeline *first; }; +//////////////////////////////////////////////////////////// +//~ Resource types + +Struct(G_D12_Resource) +{ + G_D12_Resource *next; + + struct G_D12_ResourceHeap *heap; + u64 pos_in_heap; + u64 size_in_heap; + + ID3D12Resource *d3d_resource; + u64 uid; + G_ResourceFlag flags; + + /* Buffer info */ + u64 buffer_size; + u64 buffer_size_actual; + D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address; + + /* Texture info */ + b32 is_texture; + G_Format texture_format; + Vec3I32 texture_dims; + i32 texture_mip_levels; + D3D12_BARRIER_LAYOUT texture_layout; + + /* Sampler info */ + G_SamplerDesc sampler_desc; + + /* Backbuffer info */ + struct G_D12_Swapchain *swapchain; +}; + +Struct(G_D12_ResourceList) +{ + u64 count; + G_D12_Resource *first; + G_D12_Resource *last; +}; + //////////////////////////////////////////////////////////// //~ Descriptor types @@ -70,6 +111,7 @@ Enum(G_D12_DescriptorHeapKind) Struct(G_D12_DescriptorHeap) { Arena *descriptors_arena; + G_D12_DescriptorHeapKind kind; D3D12_DESCRIPTOR_HEAP_TYPE type; u32 descriptor_size; @@ -84,8 +126,10 @@ Struct(G_D12_DescriptorHeap) Struct(G_D12_Descriptor) { G_D12_Descriptor *next; - G_D12_Descriptor *prev; - u64 queue_commit_target; + + struct G_D12_Arena *gpu_arena; + G_QueueKind completion_queue_kind; + i64 completion_queue_target; G_D12_DescriptorHeap *heap; D3D12_CPU_DESCRIPTOR_HANDLE handle; @@ -94,6 +138,7 @@ Struct(G_D12_Descriptor) Struct(G_D12_DescriptorList) { + u64 count; G_D12_Descriptor *first; G_D12_Descriptor *last; }; @@ -120,17 +165,14 @@ Struct(G_D12_ResourceHeap) { G_D12_ResourceHeapKind kind; + struct GPU_D12_Arena *gpu_arena; + ID3D12Heap *d3d_heap; ID3D12Resource *d3d_mapped_resource; void *mapped; - u64 resources_count; - struct G_D12_Resource *first_resource; - struct G_D12_Resource *last_resource; - - u64 reset_resources_count; - struct G_D12_Resource *first_reset_resource; - struct G_D12_Resource *last_reset_resource; + G_D12_ResourceList resources; + G_D12_ResourceList reset_resources; u64 pos; u64 size; @@ -139,44 +181,13 @@ Struct(G_D12_ResourceHeap) Struct(G_D12_Arena) { Arena *arena; - G_D12_DescriptorList committed_descriptors_by_heap_and_queue[G_D12_DescriptorHeapKind_Count][G_NumQueues]; + + G_D12_DescriptorList descriptors; + G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count]; G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count]; }; -//////////////////////////////////////////////////////////// -//~ Resource types - -Struct(G_D12_Resource) -{ - G_D12_Resource *next; - - G_D12_ResourceHeap *heap; - u64 pos_in_heap; - - ID3D12Resource *d3d_resource; - u64 uid; - G_ResourceFlag flags; - - /* Buffer info */ - u64 buffer_size; - u64 buffer_size_actual; - D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address; - - /* Texture info */ - b32 is_texture; - G_Format texture_format; - Vec3I32 texture_dims; - i32 texture_mip_levels; - D3D12_BARRIER_LAYOUT texture_layout; - - /* Sampler info */ - G_SamplerDesc sampler_desc; - - /* Backbuffer info */ - struct G_D12_Swapchain *swapchain; -}; - //////////////////////////////////////////////////////////// //~ Staging types @@ -351,8 +362,10 @@ Struct(G_D12_CmdChunk) Struct(G_D12_CmdList) { - G_QueueKind queue_kind; G_D12_CmdList *next; + G_QueueKind queue_kind; + + G_D12_DescriptorList reset_descriptors; G_D12_CmdChunk *first_cmd_chunk; G_D12_CmdChunk *last_cmd_chunk; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 7a245e70..01e9ddbe 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -1402,7 +1402,7 @@ void UI_EndFrame(UI_Frame *frame) //- Clear pass { - G_ClearRenderTarget(frame->cl, draw_target, VEC4(0, 0, 0, 1)); + G_ClearRenderTarget(frame->cl, draw_target, VEC4(0, 0, 0, 0)); } //- Rect pass