Files
gMod/header/D3D9Wrappers.h
T
GWToolbox Bot 2b2a817c15 Wrap D3D9 COM objects instead of MinHook-patching the cold path
CreateDevice(Ex)/CreateTexture/CreateVolumeTexture/CreateCubeTexture/
UpdateTexture/BeginScene/SetTexture/GetTexture/Release are now intercepted
via ordinary compiled virtual dispatch on wrapper objects returned from
Direct3DCreate9(Ex), instead of MinHook patching the real object's vtable
slots. Nothing is ever patched in this path, so it sidesteps every
self-modifying-code/JIT-cache concern the ARM64 emulator (Windows-on-ARM's
xtajit, or Wine on FEX-Emu/box64) has with inline code patching.

The late-attach path (SetDevice/RegisterExistingDevice/D3D9Hooks.cpp) is
unchanged: wrapping only works when gMod controls object creation from the
start, so late-attach still needs MinHook and remains gated off under ARM64
emulation.
2026-07-07 10:17:08 +00:00

70 lines
4.9 KiB
C++

#pragma once
#include <d3d9.h>
#include <atomic>
// Wraps a real IDirect3D9 so CreateDevice is intercepted via ordinary compiled virtual
// dispatch instead of a MinHook-patched vtable slot (unstable under ARM64 emulation).
// Every other method is a pure forward to the real object.
class WrappedDirect3D9 : public IDirect3D9 {
public:
explicit WrappedDirect3D9(IDirect3D9* real);
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override;
STDMETHOD_(ULONG, AddRef)() override;
STDMETHOD_(ULONG, Release)() override;
STDMETHOD(RegisterSoftwareDevice)(void* pInitializeFunction) override;
STDMETHOD_(UINT, GetAdapterCount)() override;
STDMETHOD(GetAdapterIdentifier)(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier) override;
STDMETHOD_(UINT, GetAdapterModeCount)(UINT Adapter, D3DFORMAT Format) override;
STDMETHOD(EnumAdapterModes)(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode) override;
STDMETHOD(GetAdapterDisplayMode)(UINT Adapter, D3DDISPLAYMODE* pMode) override;
STDMETHOD(CheckDeviceType)(UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) override;
STDMETHOD(CheckDeviceFormat)(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) override;
STDMETHOD(CheckDeviceMultiSampleType)(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) override;
STDMETHOD(CheckDepthStencilMatch)(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) override;
STDMETHOD(CheckDeviceFormatConversion)(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) override;
STDMETHOD(GetDeviceCaps)(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps) override;
STDMETHOD_(HMONITOR, GetAdapterMonitor)(UINT Adapter) override;
STDMETHOD(CreateDevice)(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) override;
protected:
IDirect3D9* real_;
std::atomic<ULONG> ref_count_;
};
class WrappedDirect3D9Ex : public IDirect3D9Ex {
public:
explicit WrappedDirect3D9Ex(IDirect3D9Ex* real);
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override;
STDMETHOD_(ULONG, AddRef)() override;
STDMETHOD_(ULONG, Release)() override;
STDMETHOD(RegisterSoftwareDevice)(void* pInitializeFunction) override;
STDMETHOD_(UINT, GetAdapterCount)() override;
STDMETHOD(GetAdapterIdentifier)(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier) override;
STDMETHOD_(UINT, GetAdapterModeCount)(UINT Adapter, D3DFORMAT Format) override;
STDMETHOD(EnumAdapterModes)(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode) override;
STDMETHOD(GetAdapterDisplayMode)(UINT Adapter, D3DDISPLAYMODE* pMode) override;
STDMETHOD(CheckDeviceType)(UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) override;
STDMETHOD(CheckDeviceFormat)(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) override;
STDMETHOD(CheckDeviceMultiSampleType)(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) override;
STDMETHOD(CheckDepthStencilMatch)(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) override;
STDMETHOD(CheckDeviceFormatConversion)(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) override;
STDMETHOD(GetDeviceCaps)(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps) override;
STDMETHOD_(HMONITOR, GetAdapterMonitor)(UINT Adapter) override;
STDMETHOD(CreateDevice)(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) override;
STDMETHOD_(UINT, GetAdapterModeCountEx)(UINT Adapter, const D3DDISPLAYMODEFILTER* pFilter) override;
STDMETHOD(EnumAdapterModesEx)(UINT Adapter, const D3DDISPLAYMODEFILTER* pFilter, UINT Mode, D3DDISPLAYMODEEX* pMode) override;
STDMETHOD(GetAdapterDisplayModeEx)(UINT Adapter, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation) override;
STDMETHOD(CreateDeviceEx)(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode, IDirect3DDevice9Ex** ppReturnedDeviceInterface) override;
STDMETHOD(GetAdapterLUID)(UINT Adapter, LUID* pLUID) override;
private:
IDirect3D9Ex* real_;
std::atomic<ULONG> ref_count_;
};