diff --git a/src/gallium/drivers/d3d12/d3d12_dxgi_screen.cpp b/src/gallium/drivers/d3d12/d3d12_dxgi_screen.cpp new file mode 100644 index 00000000000..f0abd401aef --- /dev/null +++ b/src/gallium/drivers/d3d12/d3d12_dxgi_screen.cpp @@ -0,0 +1,148 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "d3d12_screen.h" +#include "d3d12_public.h" + +#include "util/debug.h" +#include "util/u_memory.h" + +#include + +static IDXGIFactory4 * +get_dxgi_factory() +{ + static const GUID IID_IDXGIFactory4 = { + 0x1bc6ea02, 0xef36, 0x464f, + { 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a } + }; + + typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); + PFN_CREATE_DXGI_FACTORY CreateDXGIFactory; + + HMODULE hDXGIMod = LoadLibrary("DXGI.DLL"); + if (!hDXGIMod) { + debug_printf("D3D12: failed to load DXGI.DLL\n"); + return NULL; + } + + CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGIMod, "CreateDXGIFactory"); + if (!CreateDXGIFactory) { + debug_printf("D3D12: failed to load CreateDXGIFactory from DXGI.DLL\n"); + return NULL; + } + + IDXGIFactory4 *factory = NULL; + HRESULT hr = CreateDXGIFactory(IID_IDXGIFactory4, (void **)&factory); + if (FAILED(hr)) { + debug_printf("D3D12: CreateDXGIFactory failed: %08x\n", hr); + return NULL; + } + + return factory; +} + +static IDXGIAdapter1 * +choose_dxgi_adapter(IDXGIFactory4 *factory, LUID *adapter) +{ + IDXGIAdapter1 *ret; + if (adapter) { + if (SUCCEEDED(factory->EnumAdapterByLuid(*adapter, + __uuidof(IDXGIAdapter1), + (void**)&ret))) + return ret; + debug_printf("D3D12: requested adapter missing, falling back to auto-detection...\n"); + } + + bool want_warp = env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false); + if (want_warp) { + if (SUCCEEDED(factory->EnumWarpAdapter(__uuidof(IDXGIAdapter1), + (void**)&ret))) + return ret; + debug_printf("D3D12: failed to enum warp adapter\n"); + return NULL; + } + + // The first adapter is the default + if (SUCCEEDED(factory->EnumAdapters1(0, &ret))) + return ret; + + return NULL; +} + +static const char * +dxgi_get_name(struct pipe_screen *screen) +{ + struct d3d12_dxgi_screen *dxgi_screen = d3d12_dxgi_screen(d3d12_screen(screen)); + static char buf[1000]; + if (dxgi_screen->description[0] == L'\0') + return "D3D12 (Unknown)"; + + snprintf(buf, sizeof(buf), "D3D12 (%S)", dxgi_screen->description); + return buf; +} + +struct pipe_screen * +d3d12_create_dxgi_screen(struct sw_winsys *winsys, LUID *adapter_luid) +{ + struct d3d12_dxgi_screen *screen = CALLOC_STRUCT(d3d12_dxgi_screen); + if (!screen) + return nullptr; + + screen->factory = get_dxgi_factory(); + if (!screen->factory) { + FREE(screen); + return nullptr; + } + + screen->adapter = choose_dxgi_adapter(screen->factory, adapter_luid); + if (!screen->adapter) { + debug_printf("D3D12: no suitable adapter\n"); + FREE(screen); + return nullptr; + } + + DXGI_ADAPTER_DESC1 adapter_desc = {}; + if (FAILED(screen->adapter->GetDesc1(&adapter_desc))) { + debug_printf("D3D12: failed to retrieve adapter description\n"); + FREE(screen); + return nullptr; + } + + screen->base.vendor_id = adapter_desc.VendorId; + // Note: memory sizes in bytes, but stored in size_t, so may be capped at 4GB. + // In that case, adding before conversion to MB can easily overflow. + screen->base.memory_size_megabytes = (adapter_desc.DedicatedVideoMemory >> 20) + + (adapter_desc.DedicatedSystemMemory >> 20) + + (adapter_desc.SharedSystemMemory >> 20); + wcsncpy(screen->description, adapter_desc.Description, ARRAY_SIZE(screen->description)); + screen->base.base.get_name = dxgi_get_name; + + if (!d3d12_init_screen(&screen->base, winsys, screen->adapter)) { + debug_printf("D3D12: failed to initialize DXGI screen\n"); + FREE(screen); + return nullptr; + } + + return &screen->base.base; +} diff --git a/src/gallium/drivers/d3d12/d3d12_public.h b/src/gallium/drivers/d3d12/d3d12_public.h index bd485b3a6c4..8f3f3dbf130 100644 --- a/src/gallium/drivers/d3d12/d3d12_public.h +++ b/src/gallium/drivers/d3d12/d3d12_public.h @@ -32,7 +32,7 @@ extern "C" { #endif struct pipe_screen * -d3d12_create_screen(struct sw_winsys *winsys, LUID *adapter_luid); +d3d12_create_dxgi_screen(struct sw_winsys *winsys, LUID *adapter_luid); #ifdef __cplusplus } diff --git a/src/gallium/drivers/d3d12/d3d12_screen.cpp b/src/gallium/drivers/d3d12/d3d12_screen.cpp index e85fc7c8acc..f8dcb80a830 100644 --- a/src/gallium/drivers/d3d12/d3d12_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_screen.cpp @@ -29,7 +29,6 @@ #include "d3d12_debug.h" #include "d3d12_fence.h" #include "d3d12_format.h" -#include "d3d12_public.h" #include "d3d12_resource.h" #include "d3d12_nir_passes.h" @@ -42,7 +41,6 @@ #include "nir.h" #include "frontend/sw_winsys.h" -#include #include static const struct debug_named_value @@ -81,7 +79,7 @@ d3d12_get_device_vendor(struct pipe_screen *pscreen) { struct d3d12_screen* screen = d3d12_screen(pscreen); - switch (screen->adapter_desc.VendorId) { + switch (screen->vendor_id) { case HW_VENDOR_MICROSOFT: return "Microsoft"; case HW_VENDOR_AMD: @@ -95,29 +93,12 @@ d3d12_get_device_vendor(struct pipe_screen *pscreen) } } -static const char * -d3d12_get_name(struct pipe_screen *pscreen) -{ - struct d3d12_screen* screen = d3d12_screen(pscreen); - - if (screen->adapter_desc.Description[0] == '\0') - return "D3D12 (Unknown)"; - - static char buf[1000]; - snprintf(buf, sizeof(buf), "D3D12 (%S)", screen->adapter_desc.Description); - return buf; -} - static int d3d12_get_video_mem(struct pipe_screen *pscreen) { struct d3d12_screen* screen = d3d12_screen(pscreen); - // Note: memory sizes in bytes, but stored in size_t, so may be capped at 4GB. - // In that case, adding before conversion to MB can easily overflow. - return (screen->adapter_desc.DedicatedVideoMemory >> 20) + - (screen->adapter_desc.DedicatedSystemMemory >> 20) + - (screen->adapter_desc.SharedSystemMemory >> 20); + return screen->memory_size_megabytes; } static int @@ -702,69 +683,8 @@ enable_gpu_validation() debug3->SetEnableGPUBasedValidation(true); } -static IDXGIFactory4 * -get_dxgi_factory() -{ - static const GUID IID_IDXGIFactory4 = { - 0x1bc6ea02, 0xef36, 0x464f, - { 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a } - }; - - typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); - PFN_CREATE_DXGI_FACTORY CreateDXGIFactory; - - HMODULE hDXGIMod = LoadLibrary("DXGI.DLL"); - if (!hDXGIMod) { - debug_printf("D3D12: failed to load DXGI.DLL\n"); - return NULL; - } - - CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGIMod, "CreateDXGIFactory"); - if (!CreateDXGIFactory) { - debug_printf("D3D12: failed to load CreateDXGIFactory from DXGI.DLL\n"); - return NULL; - } - - IDXGIFactory4 *factory = NULL; - HRESULT hr = CreateDXGIFactory(IID_IDXGIFactory4, (void **)&factory); - if (FAILED(hr)) { - debug_printf("D3D12: CreateDXGIFactory failed: %08x\n", hr); - return NULL; - } - - return factory; -} - -static IDXGIAdapter1 * -choose_adapter(IDXGIFactory4 *factory, LUID *adapter) -{ - IDXGIAdapter1 *ret; - if (adapter) { - if (SUCCEEDED(factory->EnumAdapterByLuid(*adapter, - __uuidof(IDXGIAdapter1), - (void**)&ret))) - return ret; - debug_printf("D3D12: requested adapter missing, falling back to auto-detection...\n"); - } - - bool want_warp = env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false); - if (want_warp) { - if (SUCCEEDED(factory->EnumWarpAdapter(__uuidof(IDXGIAdapter1), - (void**)&ret))) - return ret; - debug_printf("D3D12: failed to enum warp adapter\n"); - return NULL; - } - - // The first adapter is the default - if (SUCCEEDED(factory->EnumAdapters1(0, &ret))) - return ret; - - return NULL; -} - static ID3D12Device * -create_device(IDXGIAdapter1 *adapter) +create_device(IUnknown *adapter) { typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**); typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID*, void*, UINT*); @@ -800,7 +720,7 @@ create_device(IDXGIAdapter1 *adapter) static bool can_attribute_at_vertex(struct d3d12_screen *screen) { - switch (screen->adapter_desc.VendorId) { + switch (screen->vendor_id) { case HW_VENDOR_MICROSOFT: return true; default: @@ -808,18 +728,13 @@ can_attribute_at_vertex(struct d3d12_screen *screen) } } -struct pipe_screen * -d3d12_create_screen(struct sw_winsys *winsys, LUID *adapter_luid) +bool +d3d12_init_screen(struct d3d12_screen *screen, struct sw_winsys *winsys, IUnknown *adapter) { - struct d3d12_screen *screen = CALLOC_STRUCT(d3d12_screen); - if (!screen) - return NULL; - d3d12_debug = debug_get_option_d3d12_debug(); screen->winsys = winsys; - screen->base.get_name = d3d12_get_name; screen->base.get_vendor = d3d12_get_vendor; screen->base.get_device_vendor = d3d12_get_device_vendor; screen->base.get_param = d3d12_get_param; @@ -839,24 +754,8 @@ d3d12_create_screen(struct sw_winsys *winsys, LUID *adapter_luid) if (d3d12_debug & D3D12_DEBUG_GPU_VALIDATOR) enable_gpu_validation(); - screen->factory = get_dxgi_factory(); - if (!screen->factory) { - debug_printf("D3D12: failed to create DXGI factory\n"); - goto failed; - } + screen->dev = create_device(adapter); - screen->adapter = choose_adapter(screen->factory, adapter_luid); - if (!screen->adapter) { - debug_printf("D3D12: no suitable adapter\n"); - return NULL; - } - - if (FAILED(screen->adapter->GetDesc1(&screen->adapter_desc))) { - debug_printf("D3D12: failed to retrieve adapter description\n"); - return NULL; - } - - screen->dev = create_device(screen->adapter); if (!screen->dev) { debug_printf("D3D12: failed to create device\n"); goto failed; @@ -963,9 +862,8 @@ d3d12_create_screen(struct sw_winsys *winsys, LUID *adapter_luid) &desc); screen->have_load_at_vertex = can_attribute_at_vertex(screen); - return &screen->base; + return true; failed: - FREE(screen); - return NULL; + return false; } diff --git a/src/gallium/drivers/d3d12/d3d12_screen.h b/src/gallium/drivers/d3d12/d3d12_screen.h index 76e43d4f199..5910b538ae2 100644 --- a/src/gallium/drivers/d3d12/d3d12_screen.h +++ b/src/gallium/drivers/d3d12/d3d12_screen.h @@ -30,7 +30,6 @@ #define D3D12_IGNORE_SDK_LAYERS #include -#include struct pb_manager; @@ -38,8 +37,6 @@ struct d3d12_screen { struct pipe_screen base; struct sw_winsys *winsys; - IDXGIFactory4 *factory; - IDXGIAdapter1 *adapter; ID3D12Device *dev; ID3D12CommandQueue *cmdqueue; @@ -57,7 +54,8 @@ struct d3d12_screen { D3D12_FEATURE_DATA_D3D12_OPTIONS4 opts4; /* description */ - DXGI_ADAPTER_DESC1 adapter_desc; + uint32_t vendor_id; + uint64_t memory_size_megabytes; double timestamp_multiplier; bool have_load_at_vertex; }; @@ -68,4 +66,21 @@ d3d12_screen(struct pipe_screen *pipe) return (struct d3d12_screen *)pipe; } +struct d3d12_dxgi_screen { + struct d3d12_screen base; + + struct IDXGIFactory4 *factory; + struct IDXGIAdapter1 *adapter; + wchar_t description[128]; +}; + +static inline struct d3d12_dxgi_screen * +d3d12_dxgi_screen(struct d3d12_screen *screen) +{ + return (struct d3d12_dxgi_screen *)screen; +} + +bool +d3d12_init_screen(struct d3d12_screen *screen, struct sw_winsys *winsys, IUnknown *adapter); + #endif diff --git a/src/gallium/drivers/d3d12/meson.build b/src/gallium/drivers/d3d12/meson.build index 44a968121f3..56cb4741df1 100644 --- a/src/gallium/drivers/d3d12/meson.build +++ b/src/gallium/drivers/d3d12/meson.build @@ -27,6 +27,7 @@ files_libd3d12 = files( 'd3d12_context.cpp', 'd3d12_descriptor_pool.cpp', 'd3d12_draw.cpp', + 'd3d12_dxgi_screen.cpp', 'd3d12_fence.cpp', 'd3d12_format.c', 'd3d12_gs_variant.cpp', diff --git a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer.cpp b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer.cpp index 9ac8b80b2e6..9409beb9ee6 100644 --- a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer.cpp +++ b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer.cpp @@ -71,7 +71,7 @@ d3d12_wgl_framebuffer_resize(stw_winsys_framebuffer *fb, pipe_resource *templ) { struct d3d12_wgl_framebuffer *framebuffer = d3d12_wgl_framebuffer(fb); - struct d3d12_screen *screen = framebuffer->screen; + struct d3d12_dxgi_screen *screen = d3d12_dxgi_screen(framebuffer->screen); DXGI_SWAP_CHAIN_DESC1 desc = {}; desc.BufferCount = 2; @@ -88,7 +88,7 @@ d3d12_wgl_framebuffer_resize(stw_winsys_framebuffer *fb, if (!framebuffer->swapchain) { ComPtr swapchain1; if (FAILED(screen->factory->CreateSwapChainForHwnd( - screen->cmdqueue, + screen->base.cmdqueue, framebuffer->window, &desc, nullptr, diff --git a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c index 7a193cdef68..65a7be01bbb 100644 --- a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c +++ b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c @@ -38,7 +38,7 @@ d3d12_wgl_create_screen(struct sw_winsys *winsys, HDC hDC) stw_dev->callbacks.pfnGetAdapterLuid(hDC, &local_luid); adapter_luid = &local_luid; } - return d3d12_create_screen(winsys, adapter_luid); + return d3d12_create_dxgi_screen(winsys, adapter_luid); } void