From 3928eaff5467a338bde3ef07fd3991c0c0f77be1 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 13 Jul 2025 15:51:15 +1000 Subject: [PATCH] D3DCommon: Load D3DCompiler dynamically --- src/util/CMakeLists.txt | 2 +- src/util/d3d_common.cpp | 67 ++++++++++++++++++++++++++++++++++------- src/util/d3d_common.h | 2 ++ src/util/util.props | 2 +- 4 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index b2bec8b93..2b3a99c8b 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 d3dcompiler.lib dxgi.lib winmm.lib Dwmapi.lib winhttp.lib) + target_link_libraries(util PRIVATE d3d11.lib 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/d3d_common.cpp b/src/util/d3d_common.cpp index 8b4cbe3fa..e758eb2c0 100644 --- a/src/util/d3d_common.cpp +++ b/src/util/d3d_common.cpp @@ -18,6 +18,7 @@ #include #include #include +#include LOG_CHANNEL(GPUDevice); @@ -30,6 +31,16 @@ struct FeatureLevelTableEntry u16 shader_model_number; const char* feature_level_str; }; + +struct Libs +{ + std::mutex load_mutex; + DynamicLibrary d3dcompiler_library; + pD3DCompile D3DCompile; + DynamicLibrary dxcompiler_library; + DxcCreateInstanceProc DxcCreateInstance; +}; + } // namespace static std::optional> CompileShaderWithFXC(u32 shader_model, bool debug_device, @@ -38,11 +49,9 @@ 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 LoadD3DCompilerLibrary(Error* error); static bool LoadDXCompilerLibrary(Error* error); -static DynamicLibrary s_dxcompiler_library; -static DxcCreateInstanceProc s_DxcCreateInstance; - static constexpr std::array s_feature_levels = {{ {D3D_FEATURE_LEVEL_1_0_CORE, 100, 40, "D3D_FEATURE_LEVEL_1_0_CORE"}, {D3D_FEATURE_LEVEL_9_1, 910, 40, "D3D_FEATURE_LEVEL_9_1"}, @@ -56,6 +65,8 @@ static constexpr std::array s_feature_levels = {{ {D3D_FEATURE_LEVEL_12_1, 1210, 60, "D3D_FEATURE_LEVEL_12_1"}, {D3D_FEATURE_LEVEL_12_2, 1220, 60, "D3D_FEATURE_LEVEL_12_2"}, }}; + +static Libs s_libs; } // namespace D3DCommon const char* D3DCommon::GetFeatureLevelString(u32 render_api_version) @@ -437,6 +448,9 @@ std::optional> D3DCommon::CompileShaderWithFXC(u32 shader_m GPUShaderStage stage, std::string_view source, const char* entry_point, Error* error) { + if (!LoadD3DCompilerLibrary(error)) + return {}; + const char* target; switch (shader_model) { @@ -476,8 +490,8 @@ std::optional> D3DCommon::CompileShaderWithFXC(u32 shader_m Microsoft::WRL::ComPtr blob; Microsoft::WRL::ComPtr error_blob; const HRESULT hr = - D3DCompile(source.data(), source.size(), "0", nullptr, nullptr, entry_point, target, - debug_device ? flags_debug : flags_non_debug, 0, blob.GetAddressOf(), error_blob.GetAddressOf()); + s_libs.D3DCompile(source.data(), source.size(), "0", nullptr, nullptr, entry_point, target, + debug_device ? flags_debug : flags_non_debug, 0, blob.GetAddressOf(), error_blob.GetAddressOf()); std::string_view error_string; if (error_blob) @@ -502,6 +516,29 @@ std::optional> D3DCommon::CompileShaderWithFXC(u32 shader_m return DynamicHeapArray(static_cast(blob->GetBufferPointer()), blob->GetBufferSize()); } +bool D3DCommon::LoadD3DCompilerLibrary(Error* error) +{ + if (s_libs.d3dcompiler_library.IsOpen()) + return true; + + // double check, another thread may have opened it + const std::unique_lock lock(s_libs.load_mutex); + if (s_libs.d3dcompiler_library.IsOpen()) + return true; + + if (!s_libs.d3dcompiler_library.Open(D3DCOMPILER_DLL_A, error)) + return false; + + if (!s_libs.d3dcompiler_library.GetSymbol("D3DCompile", &s_libs.D3DCompile)) + { + Error::SetStringView(error, "Failed to load D3DCompile from d3dcompiler.dll"); + s_libs.d3dcompiler_library.Close(); + return false; + } + + return true; +} + std::optional> D3DCommon::CompileShaderWithDXC(u32 shader_model, bool debug_device, GPUShaderStage stage, std::string_view source, const char* entry_point, Error* error) @@ -511,7 +548,7 @@ std::optional> D3DCommon::CompileShaderWithDXC(u32 shader_m HRESULT hr; Microsoft::WRL::ComPtr utils; - if (FAILED(hr = s_DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(utils.GetAddressOf())))) [[unlikely]] + if (FAILED(hr = s_libs.DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(utils.GetAddressOf())))) [[unlikely]] { Error::SetHResult(error, "DxcCreateInstance(CLSID_DxcUtils) failed: ", hr); return {}; @@ -526,7 +563,7 @@ std::optional> D3DCommon::CompileShaderWithDXC(u32 shader_m } Microsoft::WRL::ComPtr compiler; - if (FAILED(hr = s_DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(compiler.GetAddressOf())))) [[unlikely]] + if (FAILED(hr = s_libs.DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(compiler.GetAddressOf())))) [[unlikely]] { Error::SetHResult(error, "DxcCreateInstance(CLSID_DxcCompiler) failed: ", hr); return {}; @@ -601,13 +638,21 @@ std::optional> D3DCommon::CompileShaderWithDXC(u32 shader_m bool D3DCommon::LoadDXCompilerLibrary(Error* error) { - if (s_dxcompiler_library.IsOpen()) + if (s_libs.dxcompiler_library.IsOpen()) return true; - if (!s_dxcompiler_library.Open("dxcompiler.dll", error) || - !s_dxcompiler_library.GetSymbol("DxcCreateInstance", &s_DxcCreateInstance)) + // double check, another thread may have opened it + const std::unique_lock lock(s_libs.load_mutex); + if (s_libs.dxcompiler_library.IsOpen()) + return true; + + if (!s_libs.dxcompiler_library.Open("dxcompiler.dll", error)) + return false; + + if (!s_libs.dxcompiler_library.GetSymbol("DxcCreateInstance", &s_libs.DxcCreateInstance)) { - s_dxcompiler_library.Close(); + Error::SetStringView(error, "Failed to load DxcCreateInstance from dxcompiler.dll"); + s_libs.dxcompiler_library.Close(); return false; } diff --git a/src/util/d3d_common.h b/src/util/d3d_common.h index 857bd4f9a..02138da1b 100644 --- a/src/util/d3d_common.h +++ b/src/util/d3d_common.h @@ -27,6 +27,7 @@ struct IDXGIAdapter1; struct IDXGIOutput; namespace D3DCommon { + // returns string representation of feature level const char* GetFeatureLevelString(u32 render_api_version); u32 GetRenderAPIVersionForFeatureLevel(D3D_FEATURE_LEVEL feature_level); @@ -76,4 +77,5 @@ struct DXGIFormatMapping }; const DXGIFormatMapping& GetFormatMapping(GPUTexture::Format format); GPUTexture::Format GetFormatForDXGIFormat(DXGI_FORMAT format); + } // namespace D3DCommon diff --git a/src/util/util.props b/src/util/util.props index fc78aab81..c800a3f51 100644 --- a/src/util/util.props +++ b/src/util/util.props @@ -13,7 +13,7 @@ - %(AdditionalDependencies);d3d11.lib;d3d12.lib;d3dcompiler.lib;dxgi.lib;Dwmapi.lib;winhttp.lib + %(AdditionalDependencies);d3d11.lib;d3d12.lib;dxgi.lib;Dwmapi.lib;winhttp.lib