From fd1e970b0a127c4c8cf82418345e9384cdef9e5b Mon Sep 17 00:00:00 2001 From: Azalea Date: Mon, 8 Jun 2026 20:21:52 -0400 Subject: [PATCH] [+] chusan fullscreen alt+tab crash fix --- common/gfxhook/d3d9.c | 211 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 209 insertions(+), 2 deletions(-) diff --git a/common/gfxhook/d3d9.c b/common/gfxhook/d3d9.c index 7db36e5..22a0516 100644 --- a/common/gfxhook/d3d9.c +++ b/common/gfxhook/d3d9.c @@ -2,6 +2,7 @@ #include #include +#include #include #include "hook/com-proxy.h" @@ -33,6 +34,27 @@ static HRESULT STDMETHODCALLTYPE my_IDirect3D9Ex_CreateDevice( DWORD flags, D3DPRESENT_PARAMETERS *pp, IDirect3DDevice9 **pdev); +static HRESULT STDMETHODCALLTYPE my_IDirect3DDevice9_Reset( + IDirect3DDevice9 *self, + D3DPRESENT_PARAMETERS *pp); +static HRESULT STDMETHODCALLTYPE my_IDirect3DDevice9_Present( + IDirect3DDevice9 *self, + const RECT *src, + const RECT *dest, + HWND hwnd, + const RGNDATA *dirty); +static HRESULT gfx_d3d9_wrap_device( + IDirect3DDevice9 **pdev, + const D3DPRESENT_PARAMETERS *pp, + bool ex); +static HRESULT gfx_d3d9_device_recover(struct com_proxy *proxy); +static void gfx_d3d9_device_context_free(void *ctx); + +struct gfx_d3d9_device_context { + D3DPRESENT_PARAMETERS pp; + bool have_pp; + bool ex; +}; static struct gfx_config gfx_config; static Direct3DCreate9_t next_Direct3DCreate9; @@ -107,12 +129,14 @@ IDirect3D9 * WINAPI Direct3DCreate9(UINT sdk_ver) { struct com_proxy *proxy; IDirect3D9Vtbl *vtbl; + IDirect3D9Ex *api_ex; IDirect3D9 *api; HRESULT hr; dprintf("Gfx: Direct3DCreate9 hook hit\n"); api = NULL; + api_ex = NULL; if (next_Direct3DCreate9 == NULL) { dprintf("Gfx: next_Direct3DCreate9 == NULL\n"); @@ -120,7 +144,23 @@ IDirect3D9 * WINAPI Direct3DCreate9(UINT sdk_ver) goto fail; } - api = next_Direct3DCreate9(sdk_ver); + if (next_Direct3DCreate9Ex != NULL && !gfx_config.windowed) { + hr = next_Direct3DCreate9Ex(sdk_ver, &api_ex); + + if (SUCCEEDED(hr)) { + dprintf("Gfx: Using Direct3DCreate9Ex for fullscreen D3D9 device\n"); + + api = (IDirect3D9 *) api_ex; + } else { + dprintf( + "Gfx: Direct3DCreate9Ex returned %x, falling back to Direct3DCreate9\n", + (int) hr); + } + } + + if (api == NULL) { + api = next_Direct3DCreate9(sdk_ver); + } if (api == NULL) { dprintf("Gfx: next_Direct3DCreate9 returned NULL\n"); @@ -138,6 +178,7 @@ IDirect3D9 * WINAPI Direct3DCreate9(UINT sdk_ver) vtbl = proxy->vptr; vtbl->CreateDevice = my_IDirect3D9_CreateDevice; + proxy->ctx = api_ex != NULL ? proxy : NULL; return (IDirect3D9 *) proxy; @@ -185,6 +226,7 @@ HRESULT WINAPI Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **d3d9ex) vtbl = proxy->vptr; vtbl->CreateDevice = my_IDirect3D9Ex_CreateDevice; + proxy->ctx = proxy; *d3d9ex = (IDirect3D9Ex *) proxy; @@ -209,11 +251,14 @@ static HRESULT STDMETHODCALLTYPE my_IDirect3D9_CreateDevice( { struct com_proxy *proxy; IDirect3D9 *real; + HRESULT hr; + bool ex; dprintf("Gfx: IDirect3D9::CreateDevice hook hit\n"); proxy = com_proxy_downcast(self); real = proxy->real; + ex = proxy->ctx != NULL; if (gfx_config.windowed) { pp->Windowed = TRUE; @@ -236,7 +281,13 @@ static HRESULT STDMETHODCALLTYPE my_IDirect3D9_CreateDevice( dprintf("Gfx: Using adapter %d\n", gfx_config.monitor); } - return IDirect3D9_CreateDevice(real, adapter, type, hwnd, flags, pp, pdev); + hr = IDirect3D9_CreateDevice(real, adapter, type, hwnd, flags, pp, pdev); + + if (SUCCEEDED(hr)) { + hr = gfx_d3d9_wrap_device(pdev, pp, ex); + } + + return hr; } static HRESULT STDMETHODCALLTYPE my_IDirect3D9Ex_CreateDevice( @@ -259,3 +310,159 @@ static HRESULT STDMETHODCALLTYPE my_IDirect3D9Ex_CreateDevice( pp, pdev); } + +static HRESULT gfx_d3d9_wrap_device( + IDirect3DDevice9 **pdev, + const D3DPRESENT_PARAMETERS *pp, + bool ex) +{ + struct gfx_d3d9_device_context *ctx; + struct com_proxy *proxy; + IDirect3DDevice9Vtbl *vtbl; + HRESULT hr; + + assert(pdev != NULL); + + if (*pdev == NULL) { + return S_OK; + } + + ctx = calloc(1, sizeof(*ctx)); + + if (ctx == NULL) { + return E_OUTOFMEMORY; + } + + if (pp != NULL) { + memcpy(&ctx->pp, pp, sizeof(ctx->pp)); + ctx->have_pp = true; + } + + ctx->ex = ex; + + hr = com_proxy_wrap(&proxy, *pdev, sizeof(*(*pdev)->lpVtbl)); + + if (FAILED(hr)) { + dprintf("Gfx: Device com_proxy_wrap returned %x\n", (int) hr); + free(ctx); + + return hr; + } + + proxy->ctx = ctx; + proxy->cleanup_ctx = gfx_d3d9_device_context_free; + + vtbl = proxy->vptr; + vtbl->Reset = my_IDirect3DDevice9_Reset; + vtbl->Present = my_IDirect3DDevice9_Present; + + *pdev = (IDirect3DDevice9 *) proxy; + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE my_IDirect3DDevice9_Reset( + IDirect3DDevice9 *self, + D3DPRESENT_PARAMETERS *pp) +{ + struct gfx_d3d9_device_context *ctx; + struct com_proxy *proxy; + IDirect3DDevice9 *real; + HRESULT hr; + + proxy = com_proxy_downcast(self); + real = proxy->real; + ctx = proxy->ctx; + + hr = IDirect3DDevice9_Reset(real, pp); + + if (SUCCEEDED(hr) && ctx != NULL && pp != NULL) { + memcpy(&ctx->pp, pp, sizeof(ctx->pp)); + ctx->have_pp = true; + } + + return hr; +} + +static HRESULT STDMETHODCALLTYPE my_IDirect3DDevice9_Present( + IDirect3DDevice9 *self, + const RECT *src, + const RECT *dest, + HWND hwnd, + const RGNDATA *dirty) +{ + struct com_proxy *proxy; + IDirect3DDevice9 *real; + struct gfx_d3d9_device_context *ctx; + HRESULT hr; + + proxy = com_proxy_downcast(self); + real = proxy->real; + ctx = proxy->ctx; + + if (ctx != NULL && ctx->ex) { + hr = IDirect3DDevice9Ex_PresentEx( + (IDirect3DDevice9Ex *) real, + src, + dest, + hwnd, + dirty, + 0); + } else { + hr = IDirect3DDevice9_Present(real, src, dest, hwnd, dirty); + } + + if (hr == D3DERR_DEVICELOST) { + dprintf("Gfx: D3D9 device lost, attempting reset\n"); + + return gfx_d3d9_device_recover(proxy); + } + + return hr; +} + +static HRESULT gfx_d3d9_device_recover(struct com_proxy *proxy) +{ + struct gfx_d3d9_device_context *ctx; + IDirect3DDevice9 *real; + HRESULT hr; + + assert(proxy != NULL); + + real = proxy->real; + ctx = proxy->ctx; + + if (ctx == NULL || !ctx->have_pp) { + return D3DERR_DEVICELOST; + } + + hr = IDirect3DDevice9_TestCooperativeLevel(real); + + while (hr == D3DERR_DEVICELOST) { + Sleep(10); + hr = IDirect3DDevice9_TestCooperativeLevel(real); + } + + if (hr != D3DERR_DEVICENOTRESET) { + return D3DERR_DEVICELOST; + } + + hr = IDirect3DDevice9_Reset(real, &ctx->pp); + + if (hr == D3DERR_INVALIDCALL) { + return D3DERR_DEVICELOST; + } + + if (FAILED(hr)) { + return hr; + } + + dprintf("Gfx: D3D9 device reset successfully\n"); + + return D3D_OK; +} + +static void gfx_d3d9_device_context_free(void *ctx) +{ + free(ctx); +}