Files
spice2x.github.io/src/spice2x/hooks/graphics/backends/d3d9/d3d9_swapchain.h
T
Tsung-Hsiang Chang 3012139028 gitadora: add native dual fullscreen for Arena (#846)
## Link to GitHub Issue or related Pull Request, if one exists

Fixed https://github.com/spice2x/spice2x.github.io/issues/740

## Description of change

- Enable native D3D9 adapter-group dual fullscreen for the GITADORA
Arena model when the two-screen MAIN + SMALL configuration is selected
without windowed mode.
- Present MAIN and SMALL on their respective monitor heads while keeping
the invisible LEFT and RIGHT targets offscreen.
- Scope the new fake-swap-chain query behavior to the hidden GITADORA
two-head targets, preserving existing behavior for other games and
configurations.

The existing borderless-windowed two-screen path could not consistently
keep input and game timing synchronized and also reduced rendering
performance. Native dual fullscreen avoids that windowed composition
path.

## Testing

- Manually tested GITADORA Arena with separate MAIN and SMALL monitors
in fullscreen mode. Windowed mode still works if the user chooses to use
that.
- Confirmed both displays render correctly, touch input works on the
SMALL screen, gameplay input stays synchronized, and gameplay holds a
steady 60 FPS.
- Built `spicetools_spice64` at commit `e4a98e9` with the repository
Docker toolchain.
- Confirmed no new compiler warnings.
- Confirmed the forbidden static DLL import check passes.
- Confirmed the Windows 7 DLL compatibility check reports `All DLLs
OK!`.

---------

Co-authored-by: vgod <428979+vgod@users.noreply.github.com>
2026-08-02 00:03:36 -07:00

68 lines
2.8 KiB
C

#pragma once
#include <d3d9.h>
interface WrappedIDirect3DDevice9;
struct WrappedIDirect3DSwapChain9 : IDirect3DSwapChain9Ex {
enum class NativeGroupHead { Unknown, Main, Small };
WrappedIDirect3DSwapChain9(
WrappedIDirect3DDevice9 *dev,
IDirect3DSwapChain9 *orig,
NativeGroupHead native_group_head = NativeGroupHead::Unknown) :
pDev(dev), pReal(orig), is_d3d9ex(false), native_group_head(native_group_head)
{
IDirect3DSwapChain9Ex *swapchain = nullptr;
// attempt to upgrade handle
if (SUCCEEDED(this->QueryInterface(IID_PPV_ARGS(&swapchain))) && swapchain != nullptr) {
swapchain->Release();
}
}
WrappedIDirect3DSwapChain9(
WrappedIDirect3DDevice9 *dev,
IDirect3DSwapChain9Ex *orig,
NativeGroupHead native_group_head = NativeGroupHead::Unknown) :
pDev(dev), pReal(orig), is_d3d9ex(true), native_group_head(native_group_head)
{
}
virtual ~WrappedIDirect3DSwapChain9(void) {
}
WrappedIDirect3DSwapChain9(const WrappedIDirect3DSwapChain9 &) = delete;
WrappedIDirect3DSwapChain9 &operator=(const WrappedIDirect3DSwapChain9 &) = delete;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DSwapChain9
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
#pragma endregion
#pragma region IDirect3DSwapChain9Ex
virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
WrappedIDirect3DDevice9 *const pDev;
IDirect3DSwapChain9 *pReal;
bool is_d3d9ex = false;
NativeGroupHead native_group_head = NativeGroupHead::Unknown;
bool should_run_hooks = true;
};