From 4fb1e0231bb748b4a9754a67c97258b4d9101655 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 6 Jun 2025 18:54:15 -0500 Subject: [PATCH] more dx12 initialization --- src/gpu_dx12.c | 413 ++++++++++++++++++++++++++++--------------------- 1 file changed, 237 insertions(+), 176 deletions(-) diff --git a/src/gpu_dx12.c b/src/gpu_dx12.c index e61ce506..e55c55c8 100644 --- a/src/gpu_dx12.c +++ b/src/gpu_dx12.c @@ -72,10 +72,17 @@ GLOBAL struct { /* Device */ ID3D12Device *device; + /* Desc sizes */ + u32 desc_size_rtv; + /* Swapchain */ u32 swapchain_frame_index; ID3D12CommandQueue *swapchain_cq; + ID3D12CommandAllocator *swapchain_ca; IDXGISwapChain3 *swapchain; + ID3D12DescriptorHeap *swapchain_rtv_heap; + ID3D12Resource *swapchain_rtvs[DX12_SWAPCHAIN_BUFFER_COUNT]; + } G = ZI, DEBUG_ALIAS(G, G_gpu_dx12); /* ========================== * @@ -84,188 +91,239 @@ GLOBAL struct { INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(gpu_shutdown); +INTERNAL void dx12_init(struct sys_window *window) +{ + __prof; + struct temp_arena scratch = scratch_begin_no_conflict(); + HRESULT hr = 0; + + /* Enable debug layer */ + u32 dxgi_factory_flags = 0; +#if DX12_DEBUG + { + ID3D12Debug *debug_controller0 = NULL; + hr = D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug_controller0); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create ID3D12Debug0")); + } + + ID3D12Debug1 *debug_controller1 = NULL; + hr = ID3D12Debug_QueryInterface(debug_controller0, &IID_ID3D12Debug1, (void **)&debug_controller1); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create ID3D12Debug1")); + } + + ID3D12Debug_EnableDebugLayer(debug_controller0); + + /* FIXME: Enable this */ + //ID3D12Debug1_SetEnableGPUBasedValidation(debug_controller1, true); + + ID3D12Debug_Release(debug_controller1); + ID3D12Debug_Release(debug_controller0); + dxgi_factory_flags |= DXGI_CREATE_FACTORY_DEBUG; + } +#endif + + /* Create factory */ + IDXGIFactory6 *factory = NULL; + hr = CreateDXGIFactory2(dxgi_factory_flags, &IID_IDXGIFactory6, (void **)&factory); + if (FAILED(hr)) { + sys_panic(LIT("Failed to initialize DXGI factory")); + } + + /* Create device */ + ID3D12Device *device = NULL; + { + struct string error = LIT("Could not initialize GPU device."); + struct string first_gpu_name = ZI; + u32 adapter_index = 0; + while (true) { + IDXGIAdapter1 *adapter = NULL; + hr = IDXGIFactory6_EnumAdapterByGpuPreference(factory, adapter_index, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, &IID_IDXGIAdapter1, (void **)&adapter); + if (SUCCEEDED(hr)) { + DXGI_ADAPTER_DESC1 desc; + IDXGIAdapter1_GetDesc1(adapter, &desc); + if (!(desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) { + if (first_gpu_name.len == 0) { + first_gpu_name = string_from_wstr_no_limit(scratch.arena, desc.Description); + } + hr = D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device, (void **)&device); + if (SUCCEEDED(hr)) { + D3D12_FEATURE_DATA_D3D12_OPTIONS7 features = ZI; + hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS7, &features, sizeof(features)); + if (SUCCEEDED(hr) && features.MeshShaderTier >= D3D12_MESH_SHADER_TIER_1) { + IDXGIAdapter1_Release(adapter); + adapter = NULL; + break; + } + } + } + ID3D12Device_Release(device); + IDXGIAdapter1_Release(adapter); + adapter = NULL; + device = NULL; + ++adapter_index; + } else { + break; + } + } + /* TODO: Fall back to compute shaders if mesh shaders aren't supported */ + if (!device) { + if (first_gpu_name.len > 0) { + struct string fmt = LIT("Device '%F' does not support DirectX 12_2. Ensure that your drivers are up to date.\n\n" + "Note that older GPUs such as those up to and including the GTX 1000 series, the RX 5000 series, and the Intel Xe-LP series do not support DirectX 12_2 features."); + error = string_format(scratch.arena, fmt, FMT_STR(first_gpu_name)); + } + sys_panic(error); + } + } + + /* Get desc sizes */ + u32 desc_size_rtv = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + +#if DX12_DEBUG + /* Enable D3D12 Debug break */ + { + ID3D12InfoQueue *info = NULL; + hr = ID3D12Device_QueryInterface(device, &IID_ID3D12InfoQueue, (void **)&info); + if (FAILED(hr)) { + sys_panic(LIT("Failed to query ID3D12Device interface")); + } + ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE); + ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_ERROR, TRUE); + ID3D12InfoQueue_Release(info); + } + + /* Enable DXGI Debug break */ + { + IDXGIInfoQueue *dxgi_info = NULL; + hr = DXGIGetDebugInterface1(0, &IID_IDXGIInfoQueue, (void **)&dxgi_info); + if (FAILED(hr)) { + sys_panic(LIT("Failed to get DXGI debug interface")); + } + IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); + IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); + IDXGIInfoQueue_Release(dxgi_info); + } +#endif + + /* Create direct command queue */ + ID3D12CommandQueue *swapchain_cq = NULL; + { + D3D12_COMMAND_QUEUE_DESC desc = ZI; + desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + + hr = ID3D12Device_CreateCommandQueue(device, &desc, &IID_ID3D12CommandQueue, (void **)&swapchain_cq); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create swapchain command queue")); + } + } + + /* Create direct command allocator */ + ID3D12CommandAllocator *swapchain_ca = NULL; + { + hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, (void **)&swapchain_ca); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create swapchain command allocator")); + } + } + + /* Create swapchain */ + IDXGISwapChain3 *swapchain = NULL; + u32 swapchain_frame_index = 0; + { + HWND hwnd = (HWND)sys_window_get_internal_handle(window); + DXGI_SWAP_CHAIN_DESC1 desc = { + .Format = DX12_SWAPCHAIN_FORMAT, + .SampleDesc = { 1, 0 }, + .BufferUsage = DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT, + .BufferCount = DX12_SWAPCHAIN_BUFFER_COUNT, + .Scaling = DXGI_SCALING_NONE, + .Flags = DX12_SWAPCHAIN_FLAGS, + .AlphaMode = DXGI_ALPHA_MODE_IGNORE, + .SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD + }; + + /* Create swapchain1 */ + IDXGISwapChain1 *swapchain1 = NULL; + hr = IDXGIFactory2_CreateSwapChainForHwnd(factory, (IUnknown *)swapchain_cq, hwnd, &desc, NULL, NULL, &swapchain1); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create IDXGISwapChain1")); + } + + /* Upgrade to swapchain3 */ + hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create IDXGISwapChain3")); + } + + /* Disable Alt+Enter changing monitor resolution to match window size */ + IDXGIFactory_MakeWindowAssociation(factory, hwnd, DXGI_MWA_NO_ALT_ENTER); + + /* Get initial frame index */ + swapchain_frame_index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain); + + IDXGISwapChain1_Release(swapchain1); + } + + /* Create swapchain RTV heap */ + ID3D12DescriptorHeap *swapchain_rtv_heap = NULL; + { + D3D12_DESCRIPTOR_HEAP_DESC desc = ZI; + desc.NumDescriptors = DX12_SWAPCHAIN_BUFFER_COUNT; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + + hr = ID3D12Device_CreateDescriptorHeap(device, &desc, &IID_ID3D12DescriptorHeap, (void **)&swapchain_rtv_heap); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create swapchain RTV heap")); + } + } + + /* Create swacphain RTVs */ + ID3D12Resource *swapchain_rtvs[DX12_SWAPCHAIN_BUFFER_COUNT] = ZI; + { + D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = ZI; + ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(swapchain_rtv_heap, &rtv_handle); + for (u32 i = 0; i < DX12_SWAPCHAIN_BUFFER_COUNT; ++i) { + hr = IDXGISwapChain3_GetBuffer(swapchain, i, &IID_ID3D12Resource, (void **)&swapchain_rtvs[i]); + if (FAILED(hr)) { + sys_panic(LIT("Failed to create swapchain RTV")); + } + ID3D12Device_CreateRenderTargetView(device, swapchain_rtvs[i], NULL, rtv_handle); + + rtv_handle.ptr += desc_size_rtv; + } + } + + /* Create command allocator */ + + G.device = device; + G.desc_size_rtv = desc_size_rtv; + G.swapchain_frame_index = swapchain_frame_index; + G.swapchain_cq = swapchain_cq; + G.swapchain_ca = swapchain_ca; + G.swapchain = swapchain; + G.swapchain_rtv_heap = swapchain_rtv_heap; + MEMCPY(&G.swapchain_rtvs, swapchain_rtvs, sizeof(G.swapchain_rtvs)); + + IDXGIFactory6_Release(factory); + scratch_end(scratch); +} + struct gpu_startup_receipt gpu_startup(struct sys_window *window) { - struct temp_arena scratch = scratch_begin_no_conflict(); - HRESULT hr; - /* Initialize handles pool */ G.handle_entries_mutex = sys_mutex_alloc(); G.handle_entries_arena = arena_alloc(GIGABYTE(64)); /* Initialize dx12 */ - { - /* Enable debug layer */ - u32 dxgi_factory_flags = 0; -#if DX12_DEBUG - { - ID3D12Debug *debug_controller0 = NULL; - hr = D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug_controller0); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to create ID3D12Debug0")); - } - - ID3D12Debug1 *debug_controller1 = NULL; - hr = ID3D12Debug_QueryInterface(debug_controller0, &IID_ID3D12Debug1, (void **)&debug_controller1); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to create ID3D12Debug1")); - } - - ID3D12Debug_EnableDebugLayer(debug_controller0); - - /* FIXME: Enable this */ - //ID3D12Debug1_SetEnableGPUBasedValidation(debug_controller1, true); - - ID3D12Debug_Release(debug_controller1); - ID3D12Debug_Release(debug_controller0); - dxgi_factory_flags |= DXGI_CREATE_FACTORY_DEBUG; - } -#endif - - /* Create factory */ - IDXGIFactory6 *factory = NULL; - hr = CreateDXGIFactory2(dxgi_factory_flags, &IID_IDXGIFactory6, (void **)&factory); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to initialize DXGI factory")); - } - - /* Create device */ - ID3D12Device *device = NULL; - { - struct string error = LIT("Could not initialize GPU device."); - struct string first_gpu_name = ZI; - u32 adapter_index = 0; - while (true) { - IDXGIAdapter1 *adapter = NULL; - hr = IDXGIFactory6_EnumAdapterByGpuPreference(factory, adapter_index, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, &IID_IDXGIAdapter1, (void **)&adapter); - if (SUCCEEDED(hr)) { - DXGI_ADAPTER_DESC1 desc; - IDXGIAdapter1_GetDesc1(adapter, &desc); - if (!(desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) { - if (first_gpu_name.len == 0) { - first_gpu_name = string_from_wstr_no_limit(scratch.arena, desc.Description); - } - /* Using feature level 12_0 instead of 12_2 because mesh feature check happens separately - * (because 1600 series cards support mesh shaders but not the rest of 12_2) */ - hr = D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device, (void **)&device); - if (SUCCEEDED(hr)) { - D3D12_FEATURE_DATA_D3D12_OPTIONS7 features = ZI; - hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS7, &features, sizeof(features)); - if (SUCCEEDED(hr) && features.MeshShaderTier >= D3D12_MESH_SHADER_TIER_1) { - IDXGIAdapter1_Release(adapter); - adapter = NULL; - break; - } - } - } - ID3D12Device_Release(device); - IDXGIAdapter1_Release(adapter); - adapter = NULL; - device = NULL; - ++adapter_index; - } else { - break; - } - } - /* TODO: Fall back to compute shaders if mesh shaders aren't supported */ - if (!device) { - if (first_gpu_name.len > 0) { - struct string fmt = LIT("Device '%F' does not support DirectX 12_2. Ensure that your drivers are up to date.\n\n" - "Note that older GPUs such as those up to and including the GTX 1000 series, the RX 5000 series, and the Intel Xe-LP series do not support DirectX 12_2 features."); - error = string_format(scratch.arena, fmt, FMT_STR(first_gpu_name)); - } - sys_panic(error); - } - } - -#if DX12_DEBUG - /* Enable D3D12 Debug break */ - { - ID3D12InfoQueue *info = NULL; - hr = ID3D12Device_QueryInterface(device, &IID_ID3D12InfoQueue, (void **)&info); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to query ID3D12Device interface")); - } - ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE); - ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_ERROR, TRUE); - ID3D12InfoQueue_Release(info); - } - - /* Enable DXGI Debug break */ - { - IDXGIInfoQueue *dxgi_info = NULL; - hr = DXGIGetDebugInterface1(0, &IID_IDXGIInfoQueue, (void **)&dxgi_info); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to get DXGI debug interface")); - } - IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); - IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); - IDXGIInfoQueue_Release(dxgi_info); - } -#endif - - /* Create direct command queue */ - ID3D12CommandQueue *swapchain_cq = NULL; - { - D3D12_COMMAND_QUEUE_DESC desc = ZI; - desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - - hr = ID3D12Device_CreateCommandQueue(device, &desc, &IID_ID3D12CommandQueue, (void **)&swapchain_cq); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to create swapchain command queue")); - } - } - - /* Create swapchain */ - IDXGISwapChain3 *swapchain = NULL; - u32 swapchain_frame_index = 0; - { - HWND hwnd = (HWND)sys_window_get_internal_handle(window); - DXGI_SWAP_CHAIN_DESC1 desc = { - .Format = DX12_SWAPCHAIN_FORMAT, - .SampleDesc = { 1, 0 }, - .BufferUsage = DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT, - .BufferCount = 3, - .Scaling = DXGI_SCALING_NONE, - .Flags = DX12_SWAPCHAIN_FLAGS, - .AlphaMode = DXGI_ALPHA_MODE_IGNORE, - .SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD - }; - - /* Create swapchain1 */ - IDXGISwapChain1 *swapchain1 = NULL; - hr = IDXGIFactory2_CreateSwapChainForHwnd(factory, (IUnknown *)swapchain_cq, hwnd, &desc, NULL, NULL, &swapchain1); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to create IDXGISwapChain1")); - } - - /* Upgrade to swapchain3 */ - hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to create IDXGISwapChain3")); - } - - /* Disable Alt+Enter changing monitor resolution to match window size */ - IDXGIFactory_MakeWindowAssociation(factory, hwnd, DXGI_MWA_NO_ALT_ENTER); - - /* Get initial frame index */ - swapchain_frame_index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain); - - IDXGISwapChain1_Release(swapchain1); - } - - G.device = device; - G.swapchain_frame_index = swapchain_frame_index; - G.swapchain_cq = swapchain_cq; - G.swapchain = swapchain; - - IDXGIFactory6_Release(factory); - } + dx12_init(window); + /* Register callbacks */ app_register_exit_callback(gpu_shutdown); - scratch_end(scratch); struct gpu_startup_receipt res = ZI; return res; } @@ -274,11 +332,14 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(gpu_shutdown) { #if DX12_DEBUG /* Release objects to make live object reporting less noisy */ - { - ID3D12Device_Release(G.device); - ID3D12CommandQueue_Release(G.swapchain_cq); - IDXGISwapChain3_Release(G.swapchain); + for (u64 i = 0; i < ARRAY_COUNT(G.swapchain_rtvs); ++i) { + ID3D12Resource_Release(G.swapchain_rtvs[i]); } + ID3D12DescriptorHeap_Release(G.swapchain_rtv_heap); + ID3D12CommandQueue_Release(G.swapchain_ca); + ID3D12CommandQueue_Release(G.swapchain_cq); + IDXGISwapChain3_Release(G.swapchain); + ID3D12Device_Release(G.device); #endif }