diff --git a/src/common.h b/src/common.h index c0cb4e4b..b702881a 100644 --- a/src/common.h +++ b/src/common.h @@ -489,6 +489,8 @@ struct sprite_tag { #define STRING_FROM_STRUCT(ptr) (CPPCOMPAT_INITLIST_TYPE(struct string) { sizeof(*(ptr)), (u8 *)(ptr) }) +#define STRING_FROM_ARENA(arena) (STRING((arena)->pos, arena_base(arena))) + /* String from static array */ #define STRING_FROM_ARRAY(a) \ ( \ diff --git a/src/gpu_dx11.c b/src/gpu_dx11.c index e0bc51ce..f8d99514 100644 --- a/src/gpu_dx11.c +++ b/src/gpu_dx11.c @@ -214,7 +214,7 @@ struct dx11_shader_desc { #if RESOURCE_RELOADING struct arena *includes_arena; struct sys_mutex *includes_mutex; - struct dict includes_dict; + struct dict *includes_dict; struct atomic_i32 is_dirty; #endif }; @@ -700,7 +700,7 @@ INTERNAL void shader_add_include(struct dx11_shader_desc *desc, struct string in { __prof; u64 hash = hash_fnv64(HASH_FNV64_BASIS, include_name_src); - struct dict *dict = &desc->includes_dict; + struct dict *dict = desc->includes_dict; struct sys_lock lock = sys_mutex_lock_e(desc->includes_mutex); { dict_set(desc->includes_arena, dict, hash, 1); @@ -711,7 +711,7 @@ INTERNAL void shader_add_include(struct dx11_shader_desc *desc, struct string in INTERNAL void shader_reset_includes(struct dx11_shader_desc *desc) { __prof; - struct dict *dict = &desc->includes_dict; + struct dict *dict = desc->includes_dict; struct sys_lock lock = sys_mutex_lock_e(desc->includes_mutex); { dict_reset(dict); @@ -730,7 +730,7 @@ INTERNAL b32 shader_set_dirty(struct string name) atomic_i32_eval_exchange(&desc->is_dirty, 1); caused_dirty = true; } else { - struct dict *includes_dict = &desc->includes_dict; + struct dict *includes_dict = desc->includes_dict; u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); struct sys_lock lock = sys_mutex_lock_e(desc->includes_mutex); { diff --git a/src/gpu_dx12.c b/src/gpu_dx12.c index eeafbbd5..87083688 100644 --- a/src/gpu_dx12.c +++ b/src/gpu_dx12.c @@ -11,6 +11,8 @@ #include "log.h" #include "resource.h" #include "atomic.h" +#include "util.h" +#include "rand.h" /* Include common shader types */ #define SH_CPU 1 @@ -45,6 +47,7 @@ /* Arbitrary limits */ #define DX12_NUM_CBV_SRV_UAV_DESCRIPTORS (1024 * 64) #define DX12_NUM_RTV_DESCRIPTORS (1024 * 1) +#define DX12_COMMAND_BUFFER_MIN_SIZE (1024 * 64) #if RTC # define DX12_DEBUG 1 @@ -101,6 +104,7 @@ struct command_list { struct ID3D12CommandAllocator *ca; struct command_descriptor_heap *first_command_descriptor_heap; + struct command_buffer *first_command_buffer; u64 submitted_fence_target; struct command_list *prev_submitted; @@ -121,6 +125,26 @@ struct command_descriptor_heap { struct command_descriptor_heap *next_submitted; }; +struct command_buffer { + struct command_buffer_group *group; + + struct dx12_resource *staging_resource; + struct dx12_resource *gpu_resource; + u64 count; + + struct command_buffer *next_in_command_list; + + u64 submitted_fence_target; + struct command_queue *submitted_cq; + struct command_buffer *prev_submitted; + struct command_buffer *next_submitted; +}; + +struct command_buffer_group { + struct command_buffer *first_submitted; + struct command_buffer *last_submitted; +}; + struct descriptor { struct cpu_descriptor_heap *heap; D3D12_CPU_DESCRIPTOR_HANDLE handle; @@ -198,6 +222,11 @@ GLOBAL struct { struct command_descriptor_heap *first_submitted_command_descriptor_heap; struct command_descriptor_heap *last_submitted_command_descriptor_heap; + /* Command buffers pool */ + struct sys_mutex *command_buffers_mutex; + struct arena *command_buffers_arena; + struct dict *command_buffers_dict; + /* Resources pool */ struct sys_mutex *resources_mutex; struct arena *resources_arena; @@ -276,10 +305,15 @@ struct gpu_startup_receipt gpu_startup(struct work_startup_receipt *work_sr, str G.handle_entries_mutex = sys_mutex_alloc(); G.handle_entries_arena = arena_alloc(GIGABYTE(64)); - /* Initialize gpu descriptor heaps pool */ + /* Initialize command descriptor heaps pool */ G.command_descriptor_heaps_mutex = sys_mutex_alloc(); G.command_descriptor_heaps_arena = arena_alloc(GIGABYTE(64)); + /* Initialize command buffers pool */ + G.command_buffers_mutex = sys_mutex_alloc(); + G.command_buffers_arena = arena_alloc(GIGABYTE(64)); + G.command_buffers_dict = dict_init(G.command_buffers_arena, 4096); + /* Initialize resources pool */ G.resources_mutex = sys_mutex_alloc(); G.resources_arena = arena_alloc(GIGABYTE(64)); @@ -1183,252 +1217,6 @@ INTERNAL void pipeline_release(struct pipeline *pipeline) } } -/* ========================== * - * Command queue - * ========================== */ - -INTERNAL struct command_queue *command_queue_alloc(enum D3D12_COMMAND_LIST_TYPE type, enum D3D12_COMMAND_QUEUE_PRIORITY priority) -{ - struct command_queue *cq = NULL; - { - struct arena *arena = arena_alloc(GIGABYTE(64)); - cq = arena_push(arena, struct command_queue); - cq->arena = arena; - } - - cq->mutex = sys_mutex_alloc(); - - D3D12_COMMAND_QUEUE_DESC desc = ZI; - desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - desc.Type = type; - desc.Priority = priority; - HRESULT hr = ID3D12Device_CreateCommandQueue(G.device, &desc, &IID_ID3D12CommandQueue, (void **)&cq->cq); - if (FAILED(hr)) { - sys_panic(LIT("Failed to create command queue")); - } - - hr = ID3D12Device_CreateFence(G.device, 0, 0, &IID_ID3D12Fence, (void **)&cq->fence); - if (FAILED(hr)) { - sys_panic(LIT("Failed to create command queue fence")); - } - - return cq; -} - -INTERNAL void command_queue_release(struct command_queue *cq) -{ - /* TODO */ - (UNUSED)cq; - //ID3D12CommandQueue_Release(G.cq_copy_background->cq); -} - -/* ========================== * - * Command list - * ========================== */ - -INTERNAL struct command_list *command_list_open(struct command_queue *cq) -{ - u64 queue_fence_value = ID3D12Fence_GetCompletedValue(cq->fence); - - struct command_list *cl = NULL; - struct ID3D12GraphicsCommandList *old_cl = NULL; - struct ID3D12CommandAllocator *old_ca = NULL; - { - struct sys_lock lock = sys_mutex_lock_e(cq->mutex); - /* Find first command list ready for reuse */ - for (struct command_list *tmp = cq->first_submitted_command_list; tmp; tmp = tmp->next_submitted) { - if (queue_fence_value >= tmp->submitted_fence_target) { - cl = tmp; - break; - } - } - if (cl) { - /* Remove from submitted list */ - old_cl = cl->cl; - old_ca = cl->ca; - struct command_list *prev = cl->prev_submitted; - struct command_list *next = cl->next_submitted; - if (prev) { - prev->next_submitted = next; - } else { - cq->first_submitted_command_list = next; - } - if (next) { - next->prev_submitted = prev; - } else { - cq->last_submitted_command_list = prev; - } - } else { - cl = arena_push_no_zero(cq->arena, struct command_list); - } - sys_mutex_unlock(&lock); - } - MEMZERO_STRUCT(cl); - cl->cq = cq; - - HRESULT hr = 0; - /* FIXME: Determine command list type from command queue */ - if (old_cl) { - cl->cl = old_cl; - cl->ca = old_ca; - } else { - hr = ID3D12Device_CreateCommandAllocator(G.device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, (void **)&cl->ca); - if (FAILED(hr)) { - sys_panic(LIT("Failed to create command allocator")); - } - - hr = ID3D12Device_CreateCommandList(G.device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, cl->ca, NULL, &IID_ID3D12GraphicsCommandList, (void **)&cl->cl); - if (FAILED(hr)) { - sys_panic(LIT("Failed to create command list")); - } - - hr = ID3D12GraphicsCommandList_Close(cl->cl); - if (FAILED(hr)) { - sys_panic(LIT("Failed to close command list during initialization")); - } - } - - /* Close */ - hr = ID3D12CommandAllocator_Reset(cl->ca); - if (FAILED(hr)) { - sys_panic(LIT("Failed to reset command allocator")); - } - - hr = ID3D12GraphicsCommandList_Reset(cl->cl, cl->ca, NULL); - if (FAILED(hr)) { - sys_panic(LIT("Failed to reset command list")); - } - - return cl; -} - -/* TODO: Allow multiple command list submissions */ -INTERNAL void command_list_close(struct command_list *cl) -{ - struct command_queue *cq = cl->cq; - - /* Close & execute */ - HRESULT hr = ID3D12GraphicsCommandList_Close(cl->cl); - if (FAILED(hr)) { - sys_panic(LIT("Failed to close command list before execution")); - } - ID3D12CommandQueue_ExecuteCommandLists(cq->cq, 1, (ID3D12CommandList **)&cl->cl); - - /* Queue fence signal */ - u64 target_fence_value = atomic_u64_eval_add_u64(&cq->fence_target, 1) + 1; - ID3D12CommandQueue_Signal(cq->cq, cq->fence, target_fence_value); - - /* Add descriptor heaps to submitted list */ - { - struct sys_lock lock = sys_mutex_lock_e(G.command_descriptor_heaps_mutex); - for (struct command_descriptor_heap *cdh = cl->first_command_descriptor_heap; cdh; cdh = cdh->next_in_command_list) { - cdh->submitted_cq = cq; - cdh->submitted_fence_target = target_fence_value; - cdh->next_submitted = G.first_submitted_command_descriptor_heap; - if (G.last_submitted_command_descriptor_heap) { - G.last_submitted_command_descriptor_heap->next_submitted = cdh; - } else { - G.first_submitted_command_descriptor_heap = cdh; - } - G.last_submitted_command_descriptor_heap = cdh; - G.first_submitted_command_descriptor_heap = cdh; - } - sys_mutex_unlock(&lock); - } - - /* Add command list to submitted list */ - cl->submitted_fence_target = target_fence_value; - { - struct sys_lock lock = sys_mutex_lock_e(cq->mutex); - if (cq->last_submitted_command_list) { - cq->last_submitted_command_list->next_submitted = cl; - } else { - cq->first_submitted_command_list = cl; - } - cq->last_submitted_command_list = cl; - sys_mutex_unlock(&lock); - } -} - -/* ========================== * - * Command descriptor heap (GPU / shader visible descriptor heap) - * ========================== */ - -INTERNAL struct command_descriptor_heap *command_list_push_descriptor_heap(struct command_list *cl, struct cpu_descriptor_heap *dh_cpu) -{ - ASSERT(dh_cpu->type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); /* Src heap must have expected type */ - - /* Allocate GPU heap */ - struct command_descriptor_heap *cdh = NULL; - ID3D12DescriptorHeap *old_heap = NULL; - D3D12_CPU_DESCRIPTOR_HANDLE old_cpu_handle = ZI; - D3D12_GPU_DESCRIPTOR_HANDLE old_gpu_handle = ZI; - { - struct sys_lock lock = sys_mutex_lock_e(G.command_descriptor_heaps_mutex); - /* Find first heap ready for reuse */ - for (struct command_descriptor_heap *tmp = G.first_submitted_command_descriptor_heap; tmp; tmp = tmp->next_submitted) { - /* TODO: Cache completed fence values */ - u64 queue_fence_value = ID3D12Fence_GetCompletedValue(tmp->submitted_cq->fence); - if (queue_fence_value >= tmp->submitted_fence_target) { - cdh = tmp; - break; - } - } - if (cdh) { - /* Remove from submitted list */ - old_heap = cdh->heap; - old_cpu_handle = cdh->cpu_handle; - old_gpu_handle = cdh->gpu_handle; - struct command_descriptor_heap *prev = cdh->prev_submitted; - struct command_descriptor_heap *next = cdh->next_submitted; - if (prev) { - prev->next_submitted = next; - } else { - G.first_submitted_command_descriptor_heap = next; - } - if (next) { - next->prev_submitted = prev; - } else { - G.last_submitted_command_descriptor_heap = prev; - } - } else { - /* No available heap available for reuse, allocate new */ - cdh = arena_push_no_zero(G.command_descriptor_heaps_arena, struct command_descriptor_heap); - } - sys_mutex_unlock(&lock); - } - MEMZERO_STRUCT(cdh); - - if (old_heap) { - cdh->heap = old_heap; - cdh->cpu_handle = old_cpu_handle; - cdh->gpu_handle = old_gpu_handle; - } else { - D3D12_DESCRIPTOR_HEAP_DESC desc = ZI; - desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - desc.NumDescriptors = DX12_NUM_CBV_SRV_UAV_DESCRIPTORS; - desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - HRESULT hr = ID3D12Device_CreateDescriptorHeap(G.device, &desc, &IID_ID3D12DescriptorHeap, (void **)&cdh->heap); - if (FAILED(hr)) { - sys_panic(LIT("Failed to create GPU descriptor heap")); - } - ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cdh->heap, &cdh->cpu_handle); - ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(cdh->heap, &cdh->gpu_handle); - } - - /* Copy CPU heap */ - { - struct sys_lock lock = sys_mutex_lock_s(dh_cpu->mutex); - ID3D12Device_CopyDescriptorsSimple(G.device, dh_cpu->num_descriptors_reserved, cdh->cpu_handle, dh_cpu->handle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - sys_mutex_unlock(&lock); - } - - /* Insert into command list */ - cdh->next_in_command_list = cl->first_command_descriptor_heap; - cl->first_command_descriptor_heap = cdh; - - return cdh; -} /* ========================== * * Descriptor @@ -1507,14 +1295,6 @@ INTERNAL void cpu_descriptor_heap_release(struct cpu_descriptor_heap *dh) } #endif -/* ========================== * - * Buffer - * ========================== */ - -struct dx12_buffer { - u64 count; -}; - /* ========================== * * Plan * ========================== */ @@ -1522,7 +1302,8 @@ struct dx12_buffer { /* TODO: Move command list out of plan struct */ struct plan { struct arena *arena; - struct dx12_buffer *material_instances; + + struct arena *material_instances_arena; struct plan *next_free; }; @@ -1536,6 +1317,8 @@ INTERNAL struct plan *plan_alloc(void) plan->arena = arena; } + plan->material_instances_arena = arena_alloc(GIGABYTE(1)); + return plan; } @@ -1731,6 +1514,412 @@ struct v2i32 gpu_texture_get_size(struct gpu_handle resource) return res; } +/* ========================== * + * Command queue + * ========================== */ + +INTERNAL struct command_queue *command_queue_alloc(enum D3D12_COMMAND_LIST_TYPE type, enum D3D12_COMMAND_QUEUE_PRIORITY priority) +{ + struct command_queue *cq = NULL; + { + struct arena *arena = arena_alloc(GIGABYTE(64)); + cq = arena_push(arena, struct command_queue); + cq->arena = arena; + } + + cq->mutex = sys_mutex_alloc(); + + D3D12_COMMAND_QUEUE_DESC desc = ZI; + desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + desc.Type = type; + desc.Priority = priority; + HRESULT hr = ID3D12Device_CreateCommandQueue(G.device, &desc, &IID_ID3D12CommandQueue, (void **)&cq->cq); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create command queue")); + } + + hr = ID3D12Device_CreateFence(G.device, 0, 0, &IID_ID3D12Fence, (void **)&cq->fence); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create command queue fence")); + } + + return cq; +} + +INTERNAL void command_queue_release(struct command_queue *cq) +{ + /* TODO */ + (UNUSED)cq; + //ID3D12CommandQueue_Release(G.cq_copy_background->cq); +} + +/* ========================== * + * Command list + * ========================== */ + +INTERNAL struct command_list *command_list_open(struct command_queue *cq) +{ + u64 queue_fence_value = ID3D12Fence_GetCompletedValue(cq->fence); + + struct command_list *cl = NULL; + struct ID3D12GraphicsCommandList *old_cl = NULL; + struct ID3D12CommandAllocator *old_ca = NULL; + { + struct sys_lock lock = sys_mutex_lock_e(cq->mutex); + /* Find first command list ready for reuse */ + for (struct command_list *tmp = cq->first_submitted_command_list; tmp; tmp = tmp->next_submitted) { + if (queue_fence_value >= tmp->submitted_fence_target) { + cl = tmp; + break; + } + } + if (cl) { + /* Remove from submitted list */ + old_cl = cl->cl; + old_ca = cl->ca; + struct command_list *prev = cl->prev_submitted; + struct command_list *next = cl->next_submitted; + if (prev) { + prev->next_submitted = next; + } else { + cq->first_submitted_command_list = next; + } + if (next) { + next->prev_submitted = prev; + } else { + cq->last_submitted_command_list = prev; + } + } else { + cl = arena_push_no_zero(cq->arena, struct command_list); + } + sys_mutex_unlock(&lock); + } + MEMZERO_STRUCT(cl); + cl->cq = cq; + + HRESULT hr = 0; + /* FIXME: Determine command list type from command queue */ + if (old_cl) { + cl->cl = old_cl; + cl->ca = old_ca; + } else { + hr = ID3D12Device_CreateCommandAllocator(G.device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, (void **)&cl->ca); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create command allocator")); + } + + hr = ID3D12Device_CreateCommandList(G.device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, cl->ca, NULL, &IID_ID3D12GraphicsCommandList, (void **)&cl->cl); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create command list")); + } + + hr = ID3D12GraphicsCommandList_Close(cl->cl); + if (FAILED(hr)) { + sys_panic(LIT("Failed to close command list during initialization")); + } + } + + /* Close */ + hr = ID3D12CommandAllocator_Reset(cl->ca); + if (FAILED(hr)) { + sys_panic(LIT("Failed to reset command allocator")); + } + + hr = ID3D12GraphicsCommandList_Reset(cl->cl, cl->ca, NULL); + if (FAILED(hr)) { + sys_panic(LIT("Failed to reset command list")); + } + + return cl; +} + +/* TODO: Allow multiple command list submissions */ +INTERNAL void command_list_close(struct command_list *cl) +{ + struct command_queue *cq = cl->cq; + + /* Close & execute */ + HRESULT hr = ID3D12GraphicsCommandList_Close(cl->cl); + if (FAILED(hr)) { + sys_panic(LIT("Failed to close command list before execution")); + } + ID3D12CommandQueue_ExecuteCommandLists(cq->cq, 1, (ID3D12CommandList **)&cl->cl); + + /* Queue fence signal */ + /* FIXME: Wrap execute & signal in mutex */ + u64 target_fence_value = atomic_u64_eval_add_u64(&cq->fence_target, 1) + 1; + ID3D12CommandQueue_Signal(cq->cq, cq->fence, target_fence_value); + + /* Add descriptor heaps to submitted list */ + { + struct sys_lock lock = sys_mutex_lock_e(G.command_descriptor_heaps_mutex); + for (struct command_descriptor_heap *cdh = cl->first_command_descriptor_heap; cdh; cdh = cdh->next_in_command_list) { + cdh->submitted_cq = cq; + cdh->submitted_fence_target = target_fence_value; + if (G.last_submitted_command_descriptor_heap) { + G.last_submitted_command_descriptor_heap->next_submitted = cdh; + } else { + G.first_submitted_command_descriptor_heap = cdh; + } + G.last_submitted_command_descriptor_heap = cdh; + } + sys_mutex_unlock(&lock); + } + + /* Add command buffers to submitted list */ + { + struct sys_lock lock = sys_mutex_lock_e(G.command_buffers_mutex); + for (struct command_buffer *cb = cl->first_command_buffer; cb; cb = cb->next_in_command_list) { + struct command_buffer_group *group = cb->group; + cb->submitted_cq = cq; + cb->submitted_fence_target = target_fence_value; + if (group->last_submitted) { + group->last_submitted->next_submitted = cb; + } else { + group->first_submitted = cb; + } + group->last_submitted = cb; + } + sys_mutex_unlock(&lock); + } + + /* Add command list to submitted list */ + cl->submitted_fence_target = target_fence_value; + { + struct sys_lock lock = sys_mutex_lock_e(cq->mutex); + if (cq->last_submitted_command_list) { + cq->last_submitted_command_list->next_submitted = cl; + } else { + cq->first_submitted_command_list = cl; + } + cq->last_submitted_command_list = cl; + sys_mutex_unlock(&lock); + } +} + +/* ========================== * + * Command descriptor heap (GPU / shader visible descriptor heap) + * ========================== */ + +INTERNAL struct command_descriptor_heap *command_list_push_descriptor_heap(struct command_list *cl, struct cpu_descriptor_heap *dh_cpu) +{ + ASSERT(dh_cpu->type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); /* Src heap must have expected type */ + + /* Allocate GPU heap */ + struct command_descriptor_heap *cdh = NULL; + ID3D12DescriptorHeap *old_heap = NULL; + D3D12_CPU_DESCRIPTOR_HANDLE old_cpu_handle = ZI; + D3D12_GPU_DESCRIPTOR_HANDLE old_gpu_handle = ZI; + { + struct sys_lock lock = sys_mutex_lock_e(G.command_descriptor_heaps_mutex); + /* Find first heap ready for reuse */ + for (struct command_descriptor_heap *tmp = G.first_submitted_command_descriptor_heap; tmp; tmp = tmp->next_submitted) { + /* TODO: Cache completed fence values */ + u64 queue_fence_value = ID3D12Fence_GetCompletedValue(tmp->submitted_cq->fence); + if (queue_fence_value >= tmp->submitted_fence_target) { + cdh = tmp; + break; + } + } + if (cdh) { + /* Remove from submitted list */ + old_heap = cdh->heap; + old_cpu_handle = cdh->cpu_handle; + old_gpu_handle = cdh->gpu_handle; + struct command_descriptor_heap *prev = cdh->prev_submitted; + struct command_descriptor_heap *next = cdh->next_submitted; + if (prev) { + prev->next_submitted = next; + } else { + G.first_submitted_command_descriptor_heap = next; + } + if (next) { + next->prev_submitted = prev; + } else { + G.last_submitted_command_descriptor_heap = prev; + } + } else { + /* No available heap available for reuse, allocate new */ + cdh = arena_push_no_zero(G.command_descriptor_heaps_arena, struct command_descriptor_heap); + } + sys_mutex_unlock(&lock); + } + MEMZERO_STRUCT(cdh); + + if (old_heap) { + cdh->heap = old_heap; + cdh->cpu_handle = old_cpu_handle; + cdh->gpu_handle = old_gpu_handle; + } else { + D3D12_DESCRIPTOR_HEAP_DESC desc = ZI; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + desc.NumDescriptors = DX12_NUM_CBV_SRV_UAV_DESCRIPTORS; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + HRESULT hr = ID3D12Device_CreateDescriptorHeap(G.device, &desc, &IID_ID3D12DescriptorHeap, (void **)&cdh->heap); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create GPU descriptor heap")); + } + ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cdh->heap, &cdh->cpu_handle); + ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(cdh->heap, &cdh->gpu_handle); + } + + /* Copy CPU heap */ + { + struct sys_lock lock = sys_mutex_lock_s(dh_cpu->mutex); + ID3D12Device_CopyDescriptorsSimple(G.device, dh_cpu->num_descriptors_reserved, cdh->cpu_handle, dh_cpu->handle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + sys_mutex_unlock(&lock); + } + + /* Insert into command list */ + cdh->next_in_command_list = cl->first_command_descriptor_heap; + cl->first_command_descriptor_heap = cdh; + + return cdh; +} + +/* ========================== * + * Command buffer + * ========================== */ + +INTERNAL u64 command_buffer_hash_from_size(u64 size) +{ + u64 hash = rand_u64_from_seed(size); + return hash; +} + +INTERNAL u64 align_up_pow2(u64 v) +{ + u64 res = 0; + if (v > 0) { + res = v - 1; + res |= res >> 1; + res |= res >> 2; + res |= res >> 4; + res |= res >> 8; + res |= res >> 16; + res |= res >> 32; + ++res; + } + return res; +} + +INTERNAL struct command_buffer *command_list_push_buffer(struct command_list *cl, struct string data) +{ + /* Determine size */ + u64 size = max_u64(DX12_COMMAND_BUFFER_MIN_SIZE, align_up_pow2(data.len)); + + /* Allocate buffer */ + struct command_buffer_group *cb_group = NULL; + struct command_buffer *cb = NULL; + struct dx12_resource *old_staging_resource = NULL; + struct dx12_resource *old_gpu_resource = NULL; + { + struct sys_lock lock = sys_mutex_lock_e(G.command_buffers_mutex); + + { + u64 group_hash = command_buffer_hash_from_size(size); + struct dict_entry *cb_group_entry = dict_ensure_entry(G.command_buffers_arena, G.command_buffers_dict, group_hash); + cb_group = cb_group_entry->value; + if (!cb_group) { + /* Create group */ + cb_group = arena_push(G.command_buffers_arena, struct command_buffer_group); + cb_group_entry->value = (u64)cb_group; + } + } + /* Find first command buffer ready for reuse */ + for (struct command_buffer *tmp = cb_group->first_submitted; tmp; tmp = tmp->next_submitted) { + /* TODO: Cache completed fence values */ + u64 queue_fence_value = ID3D12Fence_GetCompletedValue(tmp->submitted_cq->fence); + if (queue_fence_value >= tmp->submitted_fence_target) { + cb = tmp; + break; + } + } + if (cb) { + /* Remove from submitted list */ + old_staging_resource = cb->staging_resource; + old_gpu_resource = cb->gpu_resource; + struct command_buffer *prev = cb->prev_submitted; + struct command_buffer *next = cb->next_submitted; + if (prev) { + prev->next_submitted = next; + } else { + cb_group->first_submitted = next; + } + if (next) { + next->prev_submitted = prev; + } else { + cb_group->last_submitted = prev; + } + } else { + /* Allocate new */ + cb = arena_push_no_zero(G.command_buffers_arena, struct command_buffer); + } + sys_mutex_unlock(&lock); + } + MEMZERO_STRUCT(cb); + cb->group = cb_group; + + if (old_staging_resource) { + cb->staging_resource = old_staging_resource; + cb->gpu_resource = old_gpu_resource; + } else { + /* Create staging resource */ + { +#if 0 + LOCAL_PERSIST const DXGI_FORMAT formats[] = { + [GPU_TEXTURE_FORMAT_R8G8B8A8_UNORM] = DXGI_FORMAT_R8G8B8A8_UNORM, + [GPU_TEXTURE_FORMAT_R8G8B8A8_UNORM_SRGB] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB + }; + + DXGI_FORMAT dxgi_format = 0; + if (format < (i32)ARRAY_COUNT(formats)) { + dxgi_format = formats[format]; + } + if (format == 0) { + sys_panic(LIT("Tried to create texture with unknown format")); + } + + enum dx12_resource_view_flags view_flags = DX12_RESOURCE_VIEW_FLAG_NONE; + + D3D12_HEAP_PROPERTIES heap_props = { .Type = D3D12_HEAP_TYPE_DEFAULT }; + heap_props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heap_props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + + D3D12_HEAP_FLAGS heap_flags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; + + D3D12_RESOURCE_DESC desc = ZI; + desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + desc.Alignment = 0; + desc.Width = size.x; + desc.Height = size.y; + desc.DepthOrArraySize = 1; + desc.MipLevels = 1; + desc.Format = dxgi_format; + desc.SampleDesc.Count = 1; + desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + + D3D12_RESOURCE_STATES initial_state = D3D12_RESOURCE_STATE_GENERIC_READ; + + + cb->staging_resource = dx12_resource_alloc(heap_props, heap_flags, desc, initial_state, view_flags); +#endif + } + /* Create gpu resource */ + } + + + /* Copy & submit data */ + /* FIXME */ + (UNUSED)data; + + /* Insert into command list */ + cb->next_in_command_list = cl->first_command_buffer; + cl->first_command_buffer = cb; + + return cb; +} + /* ========================== * * Dispatch * ========================== */ @@ -1745,6 +1934,7 @@ void gpu_dispatch(struct gpu_dispatch_params params) struct command_queue *cq = G.cq_direct; struct command_list *cl = command_list_open(cq); + struct command_buffer *instance_buffer = command_list_push_buffer(cl, STRING_FROM_ARENA(plan->material_instances_arena)); struct command_descriptor_heap *descriptor_heap = command_list_push_descriptor_heap(cl, G.cbv_srv_uav_heap); /* Viewport */ @@ -1807,7 +1997,7 @@ void gpu_dispatch(struct gpu_dispatch_params params) ID3D12GraphicsCommandList_IASetPrimitiveTopology(cl->cl, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); ID3D12GraphicsCommandList_IASetVertexBuffers(cl->cl, 0, 1, &G.dummy_vertex_buffer_view); ID3D12GraphicsCommandList_IASetIndexBuffer(cl->cl, &G.quad_index_buffer_view); - ID3D12GraphicsCommandList_DrawIndexedInstanced(cl->cl, 6, plan->material_instances->count, 0, 0, 0); + ID3D12GraphicsCommandList_DrawIndexedInstanced(cl->cl, 6, instance_buffer->count, 0, 0, 0); /* Reset render target */ dx12_resource_barrier(cl->cl, target, old_state); diff --git a/src/resource.c b/src/resource.c index 2ee0ba3b..d0f5984a 100644 --- a/src/resource.c +++ b/src/resource.c @@ -246,15 +246,15 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(resource_watch_dispatcher_thread_entry_ sys_mutex_unlock(&watch_dispatcher_lock); { __profscope(run_resource_watch_callbacks); - struct dict dedup_dict = dict_init(temp.arena, WATCH_DISPATCHER_DEDUP_DICT_BINS); + struct dict *dedup_dict = dict_init(temp.arena, WATCH_DISPATCHER_DEDUP_DICT_BINS); for (struct sys_watch_info *info = watch_info_list.first; info; info = info->next) { /* Do not run callbacks for the same file more than once */ b32 skip = false; u64 hash = hash_fnv64(HASH_FNV64_BASIS, info->name); - if (dict_get(&dedup_dict, hash) == 1) { + if (dict_get(dedup_dict, hash) == 1) { skip = true; } else { - dict_set(temp.arena, &dedup_dict, hash, 1); + dict_set(temp.arena, dedup_dict, hash, 1); } if (!skip) { struct sys_lock callbacks_lock = sys_mutex_lock_s(G.watch_callbacks_mutex); diff --git a/src/sim_step.c b/src/sim_step.c index 8d54c610..3b8f0b28 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -464,8 +464,8 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) /* Dicts containing walls that end on edge of tile chunk, keyed by tile end index. * Used to merge walls accross tile chunks. */ - struct dict horizontal_ends_dict = dict_init(scratch.arena, 1024); - struct dict vertical_ends_dict = dict_init(scratch.arena, 1024); + struct dict *horizontal_ends_dict = dict_init(scratch.arena, 1024); + struct dict *vertical_ends_dict = dict_init(scratch.arena, 1024); struct wall_node *first_wall = NULL; @@ -519,11 +519,11 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) if (wall_start == 0) { u64 start_hash = rand_u64_from_seed(*(u64 *)&start); start_hash = rand_u64_from_seeds(start_hash, wall_dir); - struct dict_entry *entry = dict_get_entry(&horizontal_ends_dict, start_hash); + struct dict_entry *entry = dict_get_entry(horizontal_ends_dict, start_hash); if (entry) { /* Existing wall exists accross chunk boundary */ node = (struct wall_node *)entry->value; - dict_remove_entry(&horizontal_ends_dict, entry); + dict_remove_entry(horizontal_ends_dict, entry); } } if (!node) { @@ -537,7 +537,7 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) if (wall_end == SIM_TILES_PER_CHUNK_SQRT) { u64 end_hash = rand_u64_from_seed(*(u64 *)&end); end_hash = rand_u64_from_seeds(end_hash, wall_dir); - dict_set(scratch.arena, &horizontal_ends_dict, end_hash, (u64)node); + dict_set(scratch.arena, horizontal_ends_dict, end_hash, (u64)node); } wall_start = -1; wall_end = -1; @@ -609,11 +609,11 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) if (wall_start == 0) { u64 start_hash = rand_u64_from_seed(*(u64 *)&start); start_hash = rand_u64_from_seeds(start_hash, wall_dir); - struct dict_entry *entry = dict_get_entry(&vertical_ends_dict, start_hash); + struct dict_entry *entry = dict_get_entry(vertical_ends_dict, start_hash); if (entry) { /* Existing wall exists accross chunk boundary */ node = (struct wall_node *)entry->value; - dict_remove_entry(&vertical_ends_dict, entry); + dict_remove_entry(vertical_ends_dict, entry); } } if (!node) { @@ -627,7 +627,7 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) if (wall_end == SIM_TILES_PER_CHUNK_SQRT) { u64 end_hash = rand_u64_from_seed(*(u64 *)&end); end_hash = rand_u64_from_seeds(end_hash, wall_dir); - dict_set(scratch.arena, &vertical_ends_dict, end_hash, (u64)node); + dict_set(scratch.arena, vertical_ends_dict, end_hash, (u64)node); } wall_start = -1; wall_end = -1; diff --git a/src/sprite.c b/src/sprite.c index cb79b2ee..48ebb60d 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -463,7 +463,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str span->start = ase_span->start; span->end = ase_span->end; u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); - dict_set(arena, &sheet.spans_dict, hash, (u64)span); + dict_set(arena, sheet.spans_dict, hash, (u64)span); ++index; } } @@ -494,15 +494,15 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str u64 num_temp_slice_group_nodes = 0; struct temp_slice_group_node *temp_slice_group_head = NULL; { - struct dict temp_slice_dict = dict_init(scratch.arena, (u64)(ase.num_slice_keys * 2)); + struct dict *temp_slice_dict = dict_init(scratch.arena, (u64)(ase.num_slice_keys * 2)); for (struct ase_slice_key *ase_slice_key = ase.slice_key_head; ase_slice_key; ase_slice_key = ase_slice_key->next) { struct string name = ase_slice_key->name; u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); - struct temp_slice_group_node *temp_slice_group_node = (struct temp_slice_group_node *)dict_get(&temp_slice_dict, hash); + struct temp_slice_group_node *temp_slice_group_node = (struct temp_slice_group_node *)dict_get(temp_slice_dict, hash); if (!temp_slice_group_node) { temp_slice_group_node = arena_push(scratch.arena, struct temp_slice_group_node); temp_slice_group_node->name = name; - dict_set(scratch.arena, &temp_slice_dict, hash, (u64)temp_slice_group_node); + dict_set(scratch.arena, temp_slice_dict, hash, (u64)temp_slice_group_node); ++num_temp_slice_group_nodes; temp_slice_group_node->next = temp_slice_group_head; @@ -586,7 +586,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str temp_slice_group_node->final_slice_group = slice_group; u64 hash = hash_fnv64(HASH_FNV64_BASIS, slice_group->name); - dict_set(arena, &sheet.slice_groups_dict, hash, (u64)slice_group); + dict_set(arena, sheet.slice_groups_dict, hash, (u64)slice_group); ++index; } @@ -635,7 +635,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str struct string point_slice_name = ray_slice_name; point_slice_name.len -= ray_suffix.len; u64 hash = hash_fnv64(HASH_FNV64_BASIS, point_slice_name); - struct sprite_sheet_slice_group *point_slice_group = (struct sprite_sheet_slice_group *)dict_get(&sheet.slice_groups_dict, hash); + struct sprite_sheet_slice_group *point_slice_group = (struct sprite_sheet_slice_group *)dict_get(sheet.slice_groups_dict, hash); if (point_slice_group) { u32 point_slices_per_frame = point_slice_group->per_frame_count; @@ -1096,7 +1096,7 @@ struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struc struct sprite_sheet_span res = ZI; if (sheet->spans_count > 0) { u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); - struct sprite_sheet_span *entry = (struct sprite_sheet_span *)dict_get(&sheet->spans_dict, hash); + struct sprite_sheet_span *entry = (struct sprite_sheet_span *)dict_get(sheet->spans_dict, hash); if (entry) { res = *entry; } @@ -1108,7 +1108,7 @@ struct sprite_sheet_slice sprite_sheet_get_slice(struct sprite_sheet *sheet, str { if (sheet->slice_groups_count > 0) { u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); - struct sprite_sheet_slice_group *group = (struct sprite_sheet_slice_group *)dict_get(&sheet->slice_groups_dict, hash); + struct sprite_sheet_slice_group *group = (struct sprite_sheet_slice_group *)dict_get(sheet->slice_groups_dict, hash); if (group) { return group->frame_slices[frame_index * group->per_frame_count]; } @@ -1134,7 +1134,7 @@ struct sprite_sheet_slice_array sprite_sheet_get_slices(struct sprite_sheet *she struct sprite_sheet_slice_array res = ZI; if (sheet->slice_groups_count > 0) { u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); - struct sprite_sheet_slice_group *group = (struct sprite_sheet_slice_group *)dict_get(&sheet->slice_groups_dict, hash); + struct sprite_sheet_slice_group *group = (struct sprite_sheet_slice_group *)dict_get(sheet->slice_groups_dict, hash); if (group) { res.count = group->per_frame_count; res.slices = &group->frame_slices[frame_index * group->per_frame_count]; diff --git a/src/sprite.h b/src/sprite.h index aceb3168..be344ab9 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -72,11 +72,11 @@ struct sprite_sheet { u32 spans_count; struct sprite_sheet_span *spans; - struct dict spans_dict; + struct dict *spans_dict; u32 slice_groups_count; struct sprite_sheet_slice_group *slice_groups; - struct dict slice_groups_dict; + struct dict *slice_groups_dict; }; struct sprite_sheet *sprite_sheet_from_tag_await(struct sprite_scope *scope, struct sprite_tag tag); diff --git a/src/tar.c b/src/tar.c index ce7f34ce..a9bc5df5 100644 --- a/src/tar.c +++ b/src/tar.c @@ -133,7 +133,7 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str archive.lookup = dict_init(arena, (u64)((f64)num_files * ARCHIVE_LOOKUP_TABLE_CAPACITY_FACTOR)); for (struct tar_entry *entry = archive.head; entry; entry = entry->next) { u64 hash = hash_fnv64(HASH_FNV64_BASIS, entry->file_name); - dict_set(arena, &archive.lookup, hash, (u64)entry); + dict_set(arena, archive.lookup, hash, (u64)entry); } /* Build hierarchy */ @@ -147,7 +147,7 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str for (struct string parent_dir_name = entry->file_name; parent_dir_name.len > 0; --parent_dir_name.len) { if (parent_dir_name.text[parent_dir_name.len - 1] == '/') { u64 hash = hash_fnv64(HASH_FNV64_BASIS, parent_dir_name); - parent_entry = (struct tar_entry *)dict_get(&archive.lookup, hash); + parent_entry = (struct tar_entry *)dict_get(archive.lookup, hash); break; } } @@ -165,5 +165,5 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str struct tar_entry *tar_get(struct tar_archive *archive, struct string name) { u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); - return (struct tar_entry *)dict_get(&archive->lookup, hash); + return (struct tar_entry *)dict_get(archive->lookup, hash); } diff --git a/src/tar.h b/src/tar.h index b630d3ad..7a9b9c2b 100644 --- a/src/tar.h +++ b/src/tar.h @@ -13,7 +13,7 @@ struct tar_entry { }; struct tar_archive { - struct dict lookup; + struct dict *lookup; struct tar_entry *head; }; diff --git a/src/util.h b/src/util.h index cc6356ee..aad39548 100644 --- a/src/util.h +++ b/src/util.h @@ -127,12 +127,12 @@ struct dict { struct dict_entry *last; }; -INLINE struct dict dict_init(struct arena *arena, u64 bins_count) +INLINE struct dict *dict_init(struct arena *arena, u64 bins_count) { __prof; - struct dict dict = ZI; - dict.bins_count = max_u64(bins_count, 1); /* Ensure at least 1 bin */ - dict.bins = arena_push_array(arena, struct dict_bin, dict.bins_count); + struct dict *dict = arena_push(arena, struct dict); + dict->bins_count = max_u64(bins_count, 1); /* Ensure at least 1 bin */ + dict->bins = arena_push_array(arena, struct dict_bin, dict->bins_count); return dict; }