diff --git a/.gitignore b/.gitignore index 59e2f67e..6da73f25 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.pdb *.exe .vs/* +.vscode/* unused/ build/ diff --git a/src/app.c b/src/app.c index 1f1848fb..1a8fc966 100644 --- a/src/app.c +++ b/src/app.c @@ -355,6 +355,7 @@ void app_entry_point(struct string args_str) struct sys_lock lock = sys_mutex_lock_e(&G.exit_callbacks_mutex); /* Start callback threads */ + /* TODO: Create these threads when the callbacks are initially registered and have them wait on exit */ { __profscope(app_start_exit_callbacks); for (struct exit_callback *callback = G.exit_callbacks_head; callback; callback = callback->next) { diff --git a/src/gpu_dx12.c b/src/gpu_dx12.c index c4beb370..e61ce506 100644 --- a/src/gpu_dx12.c +++ b/src/gpu_dx12.c @@ -6,6 +6,7 @@ #include "memory.h" #include "string.h" #include "scratch.h" +#include "app.h" #pragma warning(push, 0) # define UNICODE @@ -68,13 +69,21 @@ GLOBAL struct { struct dx12_handle_entry *first_free_handle_entry; u64 num_handle_entries_reserved; + /* Device */ + ID3D12Device *device; + /* Swapchain */ + u32 swapchain_frame_index; + ID3D12CommandQueue *swapchain_cq; + IDXGISwapChain3 *swapchain; } G = ZI, DEBUG_ALIAS(G, G_gpu_dx12); /* ========================== * * Startup * ========================== */ +INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(gpu_shutdown); + struct gpu_startup_receipt gpu_startup(struct sys_window *window) { struct temp_arena scratch = scratch_begin_no_conflict(); @@ -84,160 +93,195 @@ struct gpu_startup_receipt gpu_startup(struct sys_window *window) G.handle_entries_mutex = sys_mutex_alloc(); G.handle_entries_arena = arena_alloc(GIGABYTE(64)); - /* Create debug controller */ - u32 dxgi_factory_flags = 0; -#if DX12_DEBUG - ID3D12Debug *debug_controller = NULL; + /* Initialize dx12 */ { - hr = D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug_controller); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to create D3D12 debug controller")); + /* 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; } - ID3D12Debug_EnableDebugLayer(debug_controller); - ID3D12Debug_Release(debug_controller); - 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 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; + /* 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; } - 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); } } - /* 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 - /* 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")); + /* 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); } - ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE); - ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_ERROR, TRUE); - ID3D12InfoQueue_Release(info); - } - /* 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")); + /* 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); } - 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 command queue */ - ID3D12CommandQueue *cq = NULL; - { - D3D12_COMMAND_QUEUE_DESC desc = ZI; - desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + /* 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 **)&cq); - if (!SUCCEEDED(hr)) { - sys_panic(LIT("Failed to create command queue")); + 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); } - /* 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 - }; + app_register_exit_callback(gpu_shutdown); - /* Create swapchain1 */ - IDXGISwapChain1 *swapchain1 = NULL; - hr = IDXGIFactory2_CreateSwapChainForHwnd(factory, (IUnknown *)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); - - swapchain_frame_index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain); - (UNUSED)swapchain_frame_index; - - IDXGISwapChain1_Release(swapchain1); - } - - IDXGIFactory6_Release(factory); scratch_end(scratch); struct gpu_startup_receipt res = ZI; return res; } +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); + } +#endif +} + /* ========================== * * Handle * ========================== */ diff --git a/src/user.c b/src/user.c index d8fa4ce9..56f883ce 100644 --- a/src/user.c +++ b/src/user.c @@ -2076,6 +2076,7 @@ INTERNAL void user_update(void) { __profscope(render); + struct rect user_viewport = RECT_FROM_V2(V2(0, 0), G.user_size); struct rect backbuffer_viewport = RECT_FROM_V2(V2(0, 0), G.screen_size); struct v2i32 user_resolution = v2_round_to_int(user_viewport.size);