mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-04 15:50:42 -07:00
cf86fbd238
## Link to GitHub Issue or related Pull Request, if one exists Fixes #779 Regressed by #720 ## Description of change #720 introduced a static dependency on DX9 which caused `d3d9.dll` to be loaded at boot from `system32`. Some third party hooks (like ifs_layeredfs and dxvk) rely on supplying a custom `d3d9.dll` in the DLL search path (usually in modules) but this change caused Windows to skip that check. Remove the hard dependency on d3d9 and add a CMake check to ensure that compiled binaries do not accidentally introduce new static imports in the future. ## Testing Confirmed that dxvk runs again.
122 lines
4.7 KiB
C++
122 lines
4.7 KiB
C++
#include "configurator.h"
|
|
|
|
#include <d3d9.h>
|
|
|
|
#include "overlay/overlay.h"
|
|
#include "util/libutils.h"
|
|
#include "util/logging.h"
|
|
|
|
namespace cfg {
|
|
|
|
// globals
|
|
bool CONFIGURATOR_STANDALONE = false;
|
|
bool CONFIGURATOR_FORCE_SOFTWARE_RENDER = false;
|
|
ConfigType CONFIGURATOR_TYPE = ConfigType::Config;
|
|
|
|
Configurator::Configurator() {
|
|
CONFIGURATOR_STANDALONE = true;
|
|
}
|
|
|
|
Configurator::~Configurator() {
|
|
CONFIGURATOR_STANDALONE = false;
|
|
}
|
|
|
|
// Attempt to bring up a D3D9 device backing the configurator's window so the
|
|
// overlay can use the hardware-accelerated imgui_impl_dx9 path instead of
|
|
// the CPU rasterizer. Returns true if both Direct3DCreate9 and CreateDevice
|
|
// succeed; the caller falls back to overlay::create_software() otherwise so
|
|
// that environments without D3D9 (Wine without dxvk, headless test boxes,
|
|
// GPUs whose drivers reject HAL) still get a working configurator.
|
|
static bool try_init_d3d9(ConfiguratorWindow &wnd) {
|
|
if (cfg::CONFIGURATOR_FORCE_SOFTWARE_RENDER) {
|
|
return false;
|
|
}
|
|
|
|
if (wnd.hWnd == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
// load d3d9.dll dynamically rather than linking against it statically.
|
|
// a static import would force the system d3d9.dll to load at process
|
|
// startup for the main spice executable too (this file is shared with
|
|
// spice.exe), which loads system32\d3d9.dll before the modules directory
|
|
// is added to the DLL search path - preventing a user-supplied DXVK
|
|
// d3d9.dll in modules from ever loading for the game.
|
|
typedef IDirect3D9 *(WINAPI *Direct3DCreate9_t)(UINT);
|
|
HMODULE d3d9_module = libutils::try_library("d3d9.dll");
|
|
if (d3d9_module == nullptr) {
|
|
log_warning("configurator", "could not load d3d9.dll, falling back to software renderer");
|
|
return false;
|
|
}
|
|
auto Direct3DCreate9_fn =
|
|
reinterpret_cast<Direct3DCreate9_t>(libutils::try_proc(d3d9_module, "Direct3DCreate9"));
|
|
if (Direct3DCreate9_fn == nullptr) {
|
|
log_warning("configurator", "could not find Direct3DCreate9, falling back to software renderer");
|
|
return false;
|
|
}
|
|
|
|
IDirect3D9 *d3d = Direct3DCreate9_fn(D3D_SDK_VERSION);
|
|
if (d3d == nullptr) {
|
|
log_warning("configurator", "Direct3DCreate9 returned NULL, falling back to software renderer");
|
|
return false;
|
|
}
|
|
|
|
D3DPRESENT_PARAMETERS pp {};
|
|
pp.Windowed = TRUE;
|
|
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
// D3DFMT_UNKNOWN -> driver picks the current desktop format
|
|
pp.BackBufferFormat = D3DFMT_UNKNOWN;
|
|
pp.BackBufferWidth = static_cast<UINT>(wnd.client_width);
|
|
pp.BackBufferHeight = static_cast<UINT>(wnd.client_height);
|
|
pp.hDeviceWindow = wnd.hWnd;
|
|
pp.EnableAutoDepthStencil = FALSE;
|
|
pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
|
|
|
|
IDirect3DDevice9 *device = nullptr;
|
|
// SOFTWARE_VERTEXPROCESSING is the most compatible behavior flag; the UI
|
|
// is tiny so we don't need hardware T&L. FPU_PRESERVE keeps our floating
|
|
// point environment intact in case other spice code relies on it.
|
|
const DWORD behavior_flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE;
|
|
HRESULT hr = d3d->CreateDevice(
|
|
D3DADAPTER_DEFAULT,
|
|
D3DDEVTYPE_HAL,
|
|
wnd.hWnd,
|
|
behavior_flags,
|
|
&pp,
|
|
&device);
|
|
if (FAILED(hr) || device == nullptr) {
|
|
log_warning("configurator",
|
|
"D3D9 CreateDevice failed (hr={:#x}), falling back to software renderer",
|
|
static_cast<unsigned int>(hr));
|
|
d3d->Release();
|
|
return false;
|
|
}
|
|
|
|
wnd.d3d = d3d;
|
|
wnd.device = device;
|
|
wnd.pp = pp;
|
|
wnd.use_d3d9 = true;
|
|
return true;
|
|
}
|
|
|
|
void Configurator::run() {
|
|
|
|
// bring up the overlay against either a real D3D9 device or the software
|
|
// rasterizer. The choice is one-shot - the in-game overlay always uses
|
|
// the same renderer the configurator picked here.
|
|
overlay::ENABLED = true;
|
|
if (try_init_d3d9(this->wnd)) {
|
|
log_info("configurator", "using D3D9 hardware-accelerated renderer");
|
|
overlay::create_d3d9(this->wnd.hWnd, this->wnd.d3d, this->wnd.device);
|
|
} else {
|
|
log_info("configurator", "using software renderer");
|
|
overlay::create_software(this->wnd.hWnd);
|
|
}
|
|
overlay::OVERLAY->set_active(true);
|
|
ImGui::GetIO().MouseDrawCursor = false;
|
|
|
|
// run window
|
|
this->wnd.run();
|
|
}
|
|
}
|