D3DCommon: Load d3d12.dll dynamically

This commit is contained in:
Stenzek 2025-07-13 16:27:25 +10:00
parent 4ead72747b
commit 3bb67c785e
No known key found for this signature in database
6 changed files with 96 additions and 29 deletions

View File

@ -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)

View File

@ -129,28 +129,10 @@ D3D12Device::~D3D12Device()
Assert(s_pipeline_cache_data.empty());
}
D3D12Device::ComPtr<ID3DBlob> D3D12Device::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error)
{
ComPtr<ID3DBlob> blob;
ComPtr<ID3DBlob> 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<const char*>(error_blob->GetBufferPointer()));
return {};
}
return blob;
}
D3D12Device::ComPtr<ID3D12RootSignature> D3D12Device::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc,
Error* error)
{
ComPtr<ID3DBlob> blob = SerializeRootSignature(desc, error);
ComPtr<ID3DBlob> 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<ID3D12Debug> 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)
{

View File

@ -162,7 +162,6 @@ public:
ID3D12GraphicsCommandList4* GetInitCommandList();
// Root signature access.
ComPtr<ID3DBlob> SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error);
ComPtr<ID3D12RootSignature> CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error);
/// Fence value for current command list.

View File

@ -15,6 +15,7 @@
#include "fmt/format.h"
#include <d3d11.h>
#include <d3d12.h>
#include <d3dcompiler.h>
#include <dxcapi.h>
#include <dxgi1_5.h>
@ -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<DynamicHeapArray<u8>> CompileShaderWithFXC(u32 shader_model
static std::optional<DynamicHeapArray<u8>> 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<ID3D12Debug>* 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<ID3D12Device1>* 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<ID3DBlob> D3DCommon::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error)
{
Microsoft::WRL::ComPtr<ID3DBlob> blob;
Microsoft::WRL::ComPtr<ID3DBlob> 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<const char*>(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(),

View File

@ -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<ID3D11DeviceContext>* immediate_context, Error* error);
// D3D12 functions
bool GetD3D12DebugInterface(Microsoft::WRL::ComPtr<ID3D12Debug>* debug, Error* error);
bool CreateD3D12Device(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL feature_level,
Microsoft::WRL::ComPtr<ID3D12Device1>* device, Error* error);
Microsoft::WRL::ComPtr<ID3DBlob> SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error);
// returns a list of all adapter names
GPUDevice::AdapterInfoList GetAdapterInfoList();

View File

@ -13,7 +13,7 @@
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);d3d12.lib;Dwmapi.lib;winhttp.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);Dwmapi.lib;winhttp.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>