diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 2b3a99c8b..7b0dced0a 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 d3d11.lib d3d12.lib dxgi.lib winmm.lib Dwmapi.lib winhttp.lib) + target_link_libraries(util PRIVATE d3d12.lib dxgi.lib 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/d3d11_device.cpp b/src/util/d3d11_device.cpp index 233fc2f07..9c9b78030 100644 --- a/src/util/d3d11_device.cpp +++ b/src/util/d3d11_device.cpp @@ -81,14 +81,11 @@ bool D3D11Device::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature ComPtr temp_device; ComPtr temp_context; - HRESULT hr = - D3D11CreateDevice(dxgi_adapter.Get(), dxgi_adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, - create_flags, requested_feature_levels.data(), static_cast(requested_feature_levels.size()), - D3D11_SDK_VERSION, temp_device.GetAddressOf(), nullptr, temp_context.GetAddressOf()); - - if (FAILED(hr)) + HRESULT hr; + if (!D3DCommon::CreateD3D11Device(dxgi_adapter.Get(), create_flags, requested_feature_levels.data(), + static_cast(requested_feature_levels.size()), &temp_device, nullptr, + &temp_context, error)) { - Error::SetHResult(error, "Failed to create D3D device: ", hr); return false; } else if (FAILED(hr = temp_device.As(&m_device)) || FAILED(hr = temp_context.As(&m_context))) diff --git a/src/util/d3d_common.cpp b/src/util/d3d_common.cpp index e758eb2c0..353d7d84b 100644 --- a/src/util/d3d_common.cpp +++ b/src/util/d3d_common.cpp @@ -35,6 +35,8 @@ struct FeatureLevelTableEntry struct Libs { std::mutex load_mutex; + DynamicLibrary d3d11_library; + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice; DynamicLibrary d3dcompiler_library; pD3DCompile D3DCompile; DynamicLibrary dxcompiler_library; @@ -111,12 +113,12 @@ D3D_FEATURE_LEVEL D3DCommon::GetDeviceMaxFeatureLevel(IDXGIAdapter1* adapter) D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}; D3D_FEATURE_LEVEL max_supported_level; - HRESULT hr = D3D11CreateDevice(adapter, adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, - requested_feature_levels.data(), static_cast(requested_feature_levels.size()), - D3D11_SDK_VERSION, nullptr, &max_supported_level, nullptr); - if (FAILED(hr)) + Error error; + if (!CreateD3D11Device(adapter, 0, requested_feature_levels.data(), + static_cast(requested_feature_levels.size()), nullptr, &max_supported_level, nullptr, + &error)) { - WARNING_LOG("D3D11CreateDevice() for getting max feature level failed: 0x{:08X}", static_cast(hr)); + WARNING_LOG("D3D11CreateDevice() for getting max feature level failed: {}", error.GetDescription()); max_supported_level = requested_feature_levels.back(); } @@ -145,6 +147,40 @@ bool D3DCommon::SupportsAllowTearing(IDXGIFactory5* factory) return (SUCCEEDED(hr) && allow_tearing_supported == TRUE); } +bool D3DCommon::CreateD3D11Device(IDXGIAdapter* adapter, UINT create_flags, const D3D_FEATURE_LEVEL* feature_levels, + UINT num_feature_levels, Microsoft::WRL::ComPtr* device, + D3D_FEATURE_LEVEL* out_feature_level, + Microsoft::WRL::ComPtr* immediate_context, Error* error) +{ + if (!s_libs.d3d11_library.IsOpen()) + { + // another thread may have opened it + const std::unique_lock lock(s_libs.load_mutex); + if (!s_libs.d3d11_library.IsOpen()) + { + if (!s_libs.d3d11_library.Open("d3d11.dll", error)) + return false; + + if (!s_libs.d3d11_library.GetSymbol("D3D11CreateDevice", &s_libs.D3D11CreateDevice)) + { + Error::SetStringView(error, "Failed to load D3D11CreateDevice from d3d11.dll"); + s_libs.d3dcompiler_library.Close(); + return false; + } + } + } + + const HRESULT hr = s_libs.D3D11CreateDevice( + adapter, adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, create_flags, feature_levels, + num_feature_levels, D3D11_SDK_VERSION, device ? device->ReleaseAndGetAddressOf() : nullptr, out_feature_level, + immediate_context ? immediate_context->ReleaseAndGetAddressOf() : nullptr); + if (SUCCEEDED(hr)) + return true; + + Error::SetHResult(error, "D3D11CreateDevice() failed: ", hr); + return true; +} + 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 02138da1b..d8bb53237 100644 --- a/src/util/d3d_common.h +++ b/src/util/d3d_common.h @@ -25,6 +25,8 @@ struct IDXGIFactory5; struct IDXGIAdapter; struct IDXGIAdapter1; struct IDXGIOutput; +struct ID3D11Device; +struct ID3D11DeviceContext; namespace D3DCommon { @@ -41,6 +43,12 @@ D3D_FEATURE_LEVEL GetDeviceMaxFeatureLevel(IDXGIAdapter1* adapter); Microsoft::WRL::ComPtr CreateFactory(bool debug, Error* error); bool SupportsAllowTearing(IDXGIFactory5* factory); +// create a D3D device +bool CreateD3D11Device(IDXGIAdapter* adapter, UINT create_flags, const D3D_FEATURE_LEVEL* feature_levels, + UINT num_feature_levels, Microsoft::WRL::ComPtr* device, + D3D_FEATURE_LEVEL* out_feature_level, + Microsoft::WRL::ComPtr* immediate_context, 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 c800a3f51..85fb12d9d 100644 --- a/src/util/util.props +++ b/src/util/util.props @@ -13,7 +13,7 @@ - %(AdditionalDependencies);d3d11.lib;d3d12.lib;dxgi.lib;Dwmapi.lib;winhttp.lib + %(AdditionalDependencies);d3d12.lib;dxgi.lib;Dwmapi.lib;winhttp.lib