more dx12 initialization

This commit is contained in:
jacob 2025-06-06 18:54:15 -05:00
parent 50ca2387fa
commit 4fb1e0231b

View File

@ -72,10 +72,17 @@ GLOBAL struct {
/* Device */ /* Device */
ID3D12Device *device; ID3D12Device *device;
/* Desc sizes */
u32 desc_size_rtv;
/* Swapchain */ /* Swapchain */
u32 swapchain_frame_index; u32 swapchain_frame_index;
ID3D12CommandQueue *swapchain_cq; ID3D12CommandQueue *swapchain_cq;
ID3D12CommandAllocator *swapchain_ca;
IDXGISwapChain3 *swapchain; IDXGISwapChain3 *swapchain;
ID3D12DescriptorHeap *swapchain_rtv_heap;
ID3D12Resource *swapchain_rtvs[DX12_SWAPCHAIN_BUFFER_COUNT];
} G = ZI, DEBUG_ALIAS(G, G_gpu_dx12); } G = ZI, DEBUG_ALIAS(G, G_gpu_dx12);
/* ========================== * /* ========================== *
@ -84,188 +91,239 @@ GLOBAL struct {
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(gpu_shutdown); 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 gpu_startup_receipt gpu_startup(struct sys_window *window)
{ {
struct temp_arena scratch = scratch_begin_no_conflict();
HRESULT hr;
/* Initialize handles pool */ /* Initialize handles pool */
G.handle_entries_mutex = sys_mutex_alloc(); G.handle_entries_mutex = sys_mutex_alloc();
G.handle_entries_arena = arena_alloc(GIGABYTE(64)); G.handle_entries_arena = arena_alloc(GIGABYTE(64));
/* Initialize dx12 */ /* Initialize dx12 */
{ dx12_init(window);
/* 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);
}
/* Register callbacks */
app_register_exit_callback(gpu_shutdown); app_register_exit_callback(gpu_shutdown);
scratch_end(scratch);
struct gpu_startup_receipt res = ZI; struct gpu_startup_receipt res = ZI;
return res; return res;
} }
@ -274,11 +332,14 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(gpu_shutdown)
{ {
#if DX12_DEBUG #if DX12_DEBUG
/* Release objects to make live object reporting less noisy */ /* Release objects to make live object reporting less noisy */
{ for (u64 i = 0; i < ARRAY_COUNT(G.swapchain_rtvs); ++i) {
ID3D12Device_Release(G.device); ID3D12Resource_Release(G.swapchain_rtvs[i]);
ID3D12CommandQueue_Release(G.swapchain_cq);
IDXGISwapChain3_Release(G.swapchain);
} }
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 #endif
} }