From d3fa27ae4acf92b0589a8e16ddab92611ef81efb Mon Sep 17 00:00:00 2001 From: bicarus-dev <202771338+bicarus-dev@users.noreply.github.com> Date: Tue, 30 Sep 2025 22:13:02 -0700 Subject: [PATCH] Detect D3D9 CreateDevice / CreateDeviceEx failures (#388) ## Link to GitHub Issue, if one exists #345 ## Description of change Show a block of warning text if the game crashes after CreateDevice(Ex) fails. ## Testing Tested by injecting invalid resolution into spicecfg. --- .../graphics/backends/d3d9/d3d9_backend.cpp | 6 +++++ src/spice2x/launcher/signal.cpp | 24 ++++++++++++++++++- src/spice2x/launcher/signal.h | 5 ++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp index bf88b88..de85afb 100644 --- a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp +++ b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp @@ -19,6 +19,7 @@ #include "hooks/graphics/graphics.h" #include "launcher/launcher.h" #include "launcher/options.h" +#include "launcher/signal.h" #include "launcher/shutdown.h" #include "misc/clipboard.h" #include "misc/eamuse.h" @@ -775,6 +776,8 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDevice( // log error log_info("graphics::d3d9", "IDirect3D9::CreateDevice failed, hr={}", FMT_HRESULT(ret)); + launcher::signal::D3D9_CREATE_DEVICE_FAILED = true; + launcher::signal::D3D9_CREATE_DEVICE_FAILED_HRESULT = ret; } else if (!D3D9_DEVICE_HOOK_DISABLE) { graphics_hook_window(hFocusWindow, pPresentationParameters); @@ -994,6 +997,9 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDeviceEx( // log error log_warning("graphics::d3d9", "CreateDeviceEx failed, hr={}", FMT_HRESULT(result)); + launcher::signal::D3D9_CREATE_DEVICE_FAILED = true; + launcher::signal::D3D9_CREATE_DEVICE_FAILED_HRESULT = result; + } else if (!D3D9_DEVICE_HOOK_DISABLE) { graphics_hook_window(hFocusWindow, pPresentationParameters); diff --git a/src/spice2x/launcher/signal.cpp b/src/spice2x/launcher/signal.cpp index 51ec7d7..6d20da5 100644 --- a/src/spice2x/launcher/signal.cpp +++ b/src/spice2x/launcher/signal.cpp @@ -35,6 +35,8 @@ namespace launcher::signal { bool SUPERSTEP_SOUND_ERROR = false; bool AVS_DIR_CREATION_FAILURE = false; std::string AVS_SRC_PATH; + bool D3D9_CREATE_DEVICE_FAILED = false; + uint32_t D3D9_CREATE_DEVICE_FAILED_HRESULT; } #define V(variant) case variant: return #variant @@ -137,7 +139,8 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception log_warning("signal", "audio initialization error was previously detected during boot!"); log_warning("signal", " (W:SuperstepSound: Audio device is not available!!!)"); log_warning("signal", " this crash is most likely related to audio init failure"); - log_warning("signal", " fix your audio device, double check your audio options/patches, and try again"); + log_warning("signal", " see if the default audio device changed, fix your audio configuration (e.g., sample rate)"); + log_warning("signal", " double check your spice audio options/patches, and try again"); } if (launcher::signal::AVS_DIR_CREATION_FAILURE) { @@ -152,6 +155,25 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception log_warning("signal", " fix the XML file and try again"); } + if (launcher::signal::D3D9_CREATE_DEVICE_FAILED) { + log_warning("signal", + "D3D9 CreateDevice/CreateDeviceEx failed with {:#x}!", + launcher::signal::D3D9_CREATE_DEVICE_FAILED_HRESULT); + + log_warning("signal", + " this is a common graphics / monitor issue"); + log_warning("signal", + " double check any graphics options you configured in spicecfg"); + log_warning("signal", + " double check that your monitor supports the resolution + refresh rate that the game needs"); + log_warning("signal", + " enable GPU-side resolution scaling in your GPU options as needed"); + log_warning("signal", + " if you have three or more monitors, try unplugging them down to one or two, or enable -graphics-force-single-adapter option"); + log_warning("signal", + " failing all that, see if enabling windowed mode helps"); + } + // walk the exception chain struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord; while (record_cause != nullptr) { diff --git a/src/spice2x/launcher/signal.h b/src/spice2x/launcher/signal.h index 9405794..890739b 100644 --- a/src/spice2x/launcher/signal.h +++ b/src/spice2x/launcher/signal.h @@ -1,16 +1,21 @@ #pragma once #include +#include namespace launcher::signal { // settings extern bool DISABLE; extern bool USE_VEH_WORKAROUND; + + // error cases extern bool SUPERSTEP_SOUND_ERROR; extern bool AVS_DIR_CREATION_FAILURE; extern std::string AVS_XML_PATH; extern std::string AVS_SRC_PATH; + extern bool D3D9_CREATE_DEVICE_FAILED; + extern uint32_t D3D9_CREATE_DEVICE_FAILED_HRESULT; //void print_stacktrace(); void attach();