diff --git a/src/spice2x/CMakeLists.txt b/src/spice2x/CMakeLists.txt index 87ae498..d11d602 100644 --- a/src/spice2x/CMakeLists.txt +++ b/src/spice2x/CMakeLists.txt @@ -236,7 +236,7 @@ add_compile_definitions( ) # SPICE_XP: set by build_all.sh for the WinXP-compat toolchains. Gates out -# the DX11 overlay backend (WinXP lacks D3DCOMPILER_47.dll). +# the DX11 overlay backend option(SPICE_XP "Build for the WinXP-compat toolchain" OFF) if(SPICE_XP) add_compile_definitions(SPICE_XP=1) @@ -734,7 +734,7 @@ set_target_properties(spicetools_spice64 PROPERTIES PREFIX "") set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64") target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1) if(NOT SPICE_XP) - target_link_libraries(spicetools_spice64 PUBLIC d3d11 dxgi d3dcompiler) + target_link_libraries(spicetools_spice64 PUBLIC d3d11 dxgi) target_compile_definitions(spicetools_spice64 PRIVATE SPICE_D3D11=1) endif() @@ -757,7 +757,7 @@ set_target_properties(spicetools_spice64_linux PROPERTIES OUTPUT_NAME "spice64_l target_compile_definitions(spicetools_spice64_linux PRIVATE SPICE64=1) target_compile_definitions(spicetools_spice64_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1) # spice64_linux is never built under the WinXP toolchain, so dx11 is always on. -target_link_libraries(spicetools_spice64_linux PUBLIC d3d11 dxgi d3dcompiler) +target_link_libraries(spicetools_spice64_linux PUBLIC d3d11 dxgi) target_compile_definitions(spicetools_spice64_linux PRIVATE SPICE_D3D11=1) IF(NOT MSVC) diff --git a/src/spice2x/external/imgui/CMakeLists.txt b/src/spice2x/external/imgui/CMakeLists.txt index 7e92231..e979626 100644 --- a/src/spice2x/external/imgui/CMakeLists.txt +++ b/src/spice2x/external/imgui/CMakeLists.txt @@ -21,8 +21,7 @@ set(IMGUI_SOURCES misc/cpp/imgui_stdlib.cpp ) -# spice2x: DX11 backend is only built for non-XP toolchains. WinXP lacks -# D3DCOMPILER_47.dll, and including this TU would pull in D3DCompile imports. +# spice2x: DX11 backend is only built for non-XP toolchains if(NOT SPICE_XP) list(APPEND IMGUI_HEADERS backends/imgui_impl_dx11.h) list(APPEND IMGUI_SOURCES backends/imgui_impl_dx11.cpp) diff --git a/src/spice2x/external/imgui/backends/imgui_impl_dx11.cpp b/src/spice2x/external/imgui/backends/imgui_impl_dx11.cpp index 8aa7756..b25fad4 100644 --- a/src/spice2x/external/imgui/backends/imgui_impl_dx11.cpp +++ b/src/spice2x/external/imgui/backends/imgui_impl_dx11.cpp @@ -50,9 +50,35 @@ #include #include #include -#ifdef _MSC_VER -#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. -#endif +// #ifdef _MSC_VER +// #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. +// #endif + +// spice2x: resolve D3DCompile at runtime rather than static-linking d3dcompiler, +// which would hardwire an import on d3dcompiler_47.dll (absent on stock Win7). +static pD3DCompile ImGui_ImplDX11_GetD3DCompile() +{ + static pD3DCompile fn = []() -> pD3DCompile { + static const char *dlls[] = { + "d3dcompiler_47.dll", + "d3dcompiler_46.dll", + "d3dcompiler_43.dll" }; + + for (const char *dll : dlls) { + HMODULE mod = GetModuleHandleA(dll); + if (!mod) { + mod = LoadLibraryA(dll); + } + if (mod) { + if (auto p = (pD3DCompile) GetProcAddress(mod, "D3DCompile")) { + return p; + } + } + } + return nullptr; + }(); + return fn; +} // Clang/GCC warnings with -Weverything #if defined(__clang__) @@ -442,6 +468,12 @@ bool ImGui_ImplDX11_CreateDeviceObjects() // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. // See https://github.com/ocornut/imgui/pull/638 for sources and details. + // spice2x: dynamically resolved; see ImGui_ImplDX11_GetD3DCompile. + pD3DCompile D3DCompile_fn = ImGui_ImplDX11_GetD3DCompile(); + if (!D3DCompile_fn) { + return false; + } + // Create the vertex shader { static const char* vertexShader = @@ -473,7 +505,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects() }"; ID3DBlob* vertexShaderBlob; - if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vertexShaderBlob, nullptr))) + if (FAILED(D3DCompile_fn(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vertexShaderBlob, nullptr))) return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &bd->pVertexShader) != S_OK) { @@ -530,7 +562,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects() }"; ID3DBlob* pixelShaderBlob; - if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr))) + if (FAILED(D3DCompile_fn(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr))) return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &bd->pPixelShader) != S_OK) { diff --git a/src/spice2x/hooks/graphics/backends/d3d11/d3d11_backend.cpp b/src/spice2x/hooks/graphics/backends/d3d11/d3d11_backend.cpp index 15389b9..c680fc4 100644 --- a/src/spice2x/hooks/graphics/backends/d3d11/d3d11_backend.cpp +++ b/src/spice2x/hooks/graphics/backends/d3d11/d3d11_backend.cpp @@ -213,6 +213,27 @@ void poll_thread() { } } +// the overlay's imgui dx11 backend needs D3DCompile (d3dcompiler_XX.dll) to +// build its shaders. _43 ships with the DX June 2010 redist on stock Win7; +// _46/_47 come with newer Windows. +bool d3dcompiler_available() { + static const wchar_t *names[] = { + L"d3dcompiler_47.dll", + L"d3dcompiler_46.dll", + L"d3dcompiler_43.dll", + }; + for (auto name : names) { + HMODULE mod = GetModuleHandleW(name); + if (!mod) { + mod = LoadLibraryW(name); + } + if (mod && GetProcAddress(mod, "D3DCompile")) { + return true; + } + } + return false; +} + } // namespace void graphics_d3d11_init() { @@ -223,6 +244,14 @@ void graphics_d3d11_init() { return; } + // no d3dcompiler -> overlay can't build shaders; skip dx11 overlay + if (!d3dcompiler_available()) { + log_warning( + "graphics::d3d11", + "d3dcompiler not found; dx11 overlay disabled"); + return; + } + std::lock_guard lock(g_init_mutex); if (g_poll_thread.joinable()) { return; // already initialized