From 3bb67c785e271880efeb2b98eb75720ae5d06d16 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 13 Jul 2025 16:27:25 +1000 Subject: [PATCH] D3DCommon: Load d3d12.dll dynamically --- src/util/CMakeLists.txt | 2 +- src/util/d3d12_device.cpp | 30 ++------------- src/util/d3d12_device.h | 1 - src/util/d3d_common.cpp | 80 +++++++++++++++++++++++++++++++++++++++ src/util/d3d_common.h | 10 +++++ src/util/util.props | 2 +- 6 files changed, 96 insertions(+), 29 deletions(-) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 5e3c48a9a..acfbfdba1 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -241,7 +241,7 @@ if(WIN32) xinput_source.h ) target_link_libraries(util PRIVATE d3d12ma) - target_link_libraries(util PRIVATE d3d12.lib winmm.lib Dwmapi.lib winhttp.lib) + target_link_libraries(util PRIVATE winmm.lib Dwmapi.lib winhttp.lib) if(CMAKE_BUILD_TYPE MATCHES "Debug|Devel") target_link_libraries(util PRIVATE WinPixEventRuntime::WinPixEventRuntime) diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index d63da21d2..48f4bff77 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -129,28 +129,10 @@ D3D12Device::~D3D12Device() Assert(s_pipeline_cache_data.empty()); } -D3D12Device::ComPtr D3D12Device::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error) -{ - ComPtr blob; - ComPtr error_blob; - const HRESULT hr = - D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.GetAddressOf(), error_blob.GetAddressOf()); - if (FAILED(hr)) [[unlikely]] - { - Error::SetHResult(error, "D3D12SerializeRootSignature() failed: ", hr); - if (error_blob) - ERROR_LOG(static_cast(error_blob->GetBufferPointer())); - - return {}; - } - - return blob; -} - D3D12Device::ComPtr D3D12Device::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error) { - ComPtr blob = SerializeRootSignature(desc, error); + ComPtr blob = D3DCommon::SerializeRootSignature(desc, error); if (!blob) return {}; @@ -186,7 +168,7 @@ bool D3D12Device::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature if (m_debug_device) { ComPtr debug12; - if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debug12.GetAddressOf())))) + if (D3DCommon::GetD3D12DebugInterface(&debug12, nullptr)) { INFO_LOG("Enabling debug layer."); debug12->EnableDebugLayer(); @@ -217,18 +199,14 @@ bool D3D12Device::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_1_0_CORE; for (D3D_FEATURE_LEVEL try_feature_level : {D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_0}) { - hr = D3D12CreateDevice(m_adapter.Get(), try_feature_level, IID_PPV_ARGS(&m_device)); - if (SUCCEEDED(hr)) + if (D3DCommon::CreateD3D12Device(m_adapter.Get(), try_feature_level, &m_device, error)) { feature_level = try_feature_level; break; } } - if (FAILED(hr)) - { - Error::SetHResult(error, "Failed to create D3D12 device: ", hr); + if (!m_device) return false; - } if (!m_adapter) { diff --git a/src/util/d3d12_device.h b/src/util/d3d12_device.h index a68c84a83..4fc92fa0d 100644 --- a/src/util/d3d12_device.h +++ b/src/util/d3d12_device.h @@ -162,7 +162,6 @@ public: ID3D12GraphicsCommandList4* GetInitCommandList(); // Root signature access. - ComPtr SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error); ComPtr CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error); /// Fence value for current command list. diff --git a/src/util/d3d_common.cpp b/src/util/d3d_common.cpp index 0fe8e93fd..94561b10a 100644 --- a/src/util/d3d_common.cpp +++ b/src/util/d3d_common.cpp @@ -15,6 +15,7 @@ #include "fmt/format.h" #include +#include #include #include #include @@ -39,6 +40,10 @@ struct Libs decltype(&CreateDXGIFactory2) CreateDXGIFactory2; DynamicLibrary d3d11_library; PFN_D3D11_CREATE_DEVICE D3D11CreateDevice; + DynamicLibrary d3d12_library; + PFN_D3D12_CREATE_DEVICE D3D12CreateDevice; + PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface; + PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignature; DynamicLibrary d3dcompiler_library; pD3DCompile D3DCompile; DynamicLibrary dxcompiler_library; @@ -53,6 +58,7 @@ static std::optional> CompileShaderWithFXC(u32 shader_model static std::optional> CompileShaderWithDXC(u32 shader_model, bool debug_device, GPUShaderStage stage, std::string_view source, const char* entry_point, Error* error); +static bool LoadD3D12Library(Error* error); static bool LoadD3DCompilerLibrary(Error* error); static bool LoadDXCompilerLibrary(Error* error); @@ -201,6 +207,80 @@ bool D3DCommon::CreateD3D11Device(IDXGIAdapter* adapter, UINT create_flags, cons return true; } +bool D3DCommon::LoadD3D12Library(Error* error) +{ + if (s_libs.d3d12_library.IsOpen()) + return true; + + // double check, another thread may have opened it + const std::unique_lock lock(s_libs.load_mutex); + if (s_libs.d3d12_library.IsOpen()) + return true; + + if (!s_libs.d3d12_library.Open("d3d12.dll", error)) + return false; + + if (!s_libs.d3d12_library.GetSymbol("D3D12CreateDevice", &s_libs.D3D12CreateDevice) || + !s_libs.d3d12_library.GetSymbol("D3D12GetDebugInterface", &s_libs.D3D12GetDebugInterface) || + !s_libs.d3d12_library.GetSymbol("D3D12SerializeRootSignature", &s_libs.D3D12SerializeRootSignature)) + { + Error::SetStringView(error, "Failed to load one or more required functions from d3d12.dll"); + s_libs.d3d12_library.Close(); + return false; + } + + return true; +} + +bool D3DCommon::GetD3D12DebugInterface(Microsoft::WRL::ComPtr* debug, Error* error) +{ + if (!LoadD3D12Library(error)) + return false; + + const HRESULT hr = s_libs.D3D12GetDebugInterface(IID_PPV_ARGS(debug->ReleaseAndGetAddressOf())); + if (FAILED(hr)) + { + Error::SetHResult(error, "D3D12GetDebugInterface() failed: ", hr); + return false; + } + + return true; +} + +bool D3DCommon::CreateD3D12Device(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL feature_level, + Microsoft::WRL::ComPtr* device, Error* error) +{ + if (!LoadD3D12Library(error)) + return false; + + const HRESULT hr = s_libs.D3D12CreateDevice(adapter, feature_level, IID_PPV_ARGS(device->ReleaseAndGetAddressOf())); + if (FAILED(hr)) + { + Error::SetHResult(error, "D3D12CreateDevice() failed: ", hr); + return false; + } + + return true; +} + +Microsoft::WRL::ComPtr D3DCommon::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error) +{ + Microsoft::WRL::ComPtr blob; + Microsoft::WRL::ComPtr error_blob; + const HRESULT hr = s_libs.D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.GetAddressOf(), + error_blob.GetAddressOf()); + if (FAILED(hr)) [[unlikely]] + { + Error::SetHResult(error, "D3D12SerializeRootSignature() failed: ", hr); + if (error_blob) + ERROR_LOG(static_cast(error_blob->GetBufferPointer())); + + return {}; + } + + return blob; +} + static std::string FixupDuplicateAdapterNames(const GPUDevice::AdapterInfoList& adapter_names, std::string adapter_name) { if (std::any_of(adapter_names.begin(), adapter_names.end(), diff --git a/src/util/d3d_common.h b/src/util/d3d_common.h index d8bb53237..c731cc2af 100644 --- a/src/util/d3d_common.h +++ b/src/util/d3d_common.h @@ -21,12 +21,16 @@ class Error; enum class GPUDriverType : u16; +struct D3D12_ROOT_SIGNATURE_DESC; + struct IDXGIFactory5; struct IDXGIAdapter; struct IDXGIAdapter1; struct IDXGIOutput; struct ID3D11Device; struct ID3D11DeviceContext; +struct ID3D12Debug; +struct ID3D12Device1; namespace D3DCommon { @@ -49,6 +53,12 @@ bool CreateD3D11Device(IDXGIAdapter* adapter, UINT create_flags, const D3D_FEATU D3D_FEATURE_LEVEL* out_feature_level, Microsoft::WRL::ComPtr* immediate_context, Error* error); +// D3D12 functions +bool GetD3D12DebugInterface(Microsoft::WRL::ComPtr* debug, Error* error); +bool CreateD3D12Device(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL feature_level, + Microsoft::WRL::ComPtr* device, Error* error); +Microsoft::WRL::ComPtr SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error); + // returns a list of all adapter names GPUDevice::AdapterInfoList GetAdapterInfoList(); diff --git a/src/util/util.props b/src/util/util.props index 6aebff885..5da4f34e9 100644 --- a/src/util/util.props +++ b/src/util/util.props @@ -13,7 +13,7 @@ - %(AdditionalDependencies);d3d12.lib;Dwmapi.lib;winhttp.lib + %(AdditionalDependencies);Dwmapi.lib;winhttp.lib