From 2b2a817c158e47e0a07411929a4341c9b2ede637 Mon Sep 17 00:00:00 2001 From: GWToolbox Bot Date: Tue, 7 Jul 2026 10:17:08 +0000 Subject: [PATCH 1/2] 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. --- header/D3D9DeviceWrapper.h | 305 +++++++++++++++++++ header/D3D9TextureWrappers.h | 127 ++++++++ header/D3D9Wrappers.h | 69 +++++ source/D3D9DeviceWrapper.cpp | 536 +++++++++++++++++++++++++++++++++ source/D3D9TextureWrappers.cpp | 212 +++++++++++++ source/D3D9Wrappers.cpp | 166 ++++++++++ source/dll_main.cpp | 17 +- 7 files changed, 1426 insertions(+), 6 deletions(-) create mode 100644 header/D3D9DeviceWrapper.h create mode 100644 header/D3D9TextureWrappers.h create mode 100644 header/D3D9Wrappers.h create mode 100644 source/D3D9DeviceWrapper.cpp create mode 100644 source/D3D9TextureWrappers.cpp create mode 100644 source/D3D9Wrappers.cpp diff --git a/header/D3D9DeviceWrapper.h b/header/D3D9DeviceWrapper.h new file mode 100644 index 0000000..d092c17 --- /dev/null +++ b/header/D3D9DeviceWrapper.h @@ -0,0 +1,305 @@ +#pragma once + +#include +#include + +class TextureClient; + +// Wraps a real IDirect3DDevice9 so CreateTexture/CreateVolumeTexture/CreateCubeTexture/ +// UpdateTexture/BeginScene/SetTexture/GetTexture/Release are 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 device. +class WrappedDirect3DDevice9 : public IDirect3DDevice9 { +public: + explicit WrappedDirect3DDevice9(IDirect3DDevice9* real); + + IDirect3DDevice9* RealDevice() const { return real_; } + TextureClient* Client() const { return client_; } + void SetClient(TextureClient* client) { client_ = client; } + + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override; + STDMETHOD_(ULONG, AddRef)() override; + STDMETHOD_(ULONG, Release)() override; + + STDMETHOD(TestCooperativeLevel)() override; + STDMETHOD_(UINT, GetAvailableTextureMem)() override; + STDMETHOD(EvictManagedResources)() override; + STDMETHOD(GetDirect3D)(IDirect3D9** ppD3D9) override; + STDMETHOD(GetDeviceCaps)(D3DCAPS9* pCaps) override; + STDMETHOD(GetDisplayMode)(UINT iSwapChain, D3DDISPLAYMODE* pMode) override; + STDMETHOD(GetCreationParameters)(D3DDEVICE_CREATION_PARAMETERS* pParameters) override; + STDMETHOD(SetCursorProperties)(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap) override; + STDMETHOD_(void, SetCursorPosition)(int X, int Y, DWORD Flags) override; + STDMETHOD_(BOOL, ShowCursor)(BOOL bShow) override; + STDMETHOD(CreateAdditionalSwapChain)(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain) override; + STDMETHOD(GetSwapChain)(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain) override; + STDMETHOD_(UINT, GetNumberOfSwapChains)() override; + STDMETHOD(Reset)(D3DPRESENT_PARAMETERS* pPresentationParameters) override; + STDMETHOD(Present)(const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion) override; + STDMETHOD(GetBackBuffer)(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer) override; + STDMETHOD(GetRasterStatus)(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus) override; + STDMETHOD(SetDialogBoxMode)(BOOL bEnableDialogs) override; + STDMETHOD_(void, SetGammaRamp)(UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP* pRamp) override; + STDMETHOD_(void, GetGammaRamp)(UINT iSwapChain, D3DGAMMARAMP* pRamp) override; + STDMETHOD(CreateTexture)(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle) override; + STDMETHOD(CreateVolumeTexture)(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle) override; + STDMETHOD(CreateCubeTexture)(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle) override; + STDMETHOD(CreateVertexBuffer)(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle) override; + STDMETHOD(CreateIndexBuffer)(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle) override; + STDMETHOD(CreateRenderTarget)(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override; + STDMETHOD(CreateDepthStencilSurface)(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override; + STDMETHOD(UpdateSurface)(IDirect3DSurface9* pSourceSurface, const RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface, const POINT* pDestPoint) override; + STDMETHOD(UpdateTexture)(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture) override; + STDMETHOD(GetRenderTargetData)(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface) override; + STDMETHOD(GetFrontBufferData)(UINT iSwapChain, IDirect3DSurface9* pDestSurface) override; + STDMETHOD(StretchRect)(IDirect3DSurface9* pSourceSurface, const RECT* pSourceRect, IDirect3DSurface9* pDestSurface, const RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter) override; + STDMETHOD(ColorFill)(IDirect3DSurface9* pSurface, const RECT* pRect, D3DCOLOR color) override; + STDMETHOD(CreateOffscreenPlainSurface)(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override; + STDMETHOD(SetRenderTarget)(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget) override; + STDMETHOD(GetRenderTarget)(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget) override; + STDMETHOD(SetDepthStencilSurface)(IDirect3DSurface9* pNewZStencil) override; + STDMETHOD(GetDepthStencilSurface)(IDirect3DSurface9** ppZStencilSurface) override; + STDMETHOD(BeginScene)() override; + STDMETHOD(EndScene)() override; + STDMETHOD(Clear)(DWORD Count, const D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) override; + STDMETHOD(SetTransform)(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix) override; + STDMETHOD(GetTransform)(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) override; + STDMETHOD(MultiplyTransform)(D3DTRANSFORMSTATETYPE, const D3DMATRIX*) override; + STDMETHOD(SetViewport)(const D3DVIEWPORT9* pViewport) override; + STDMETHOD(GetViewport)(D3DVIEWPORT9* pViewport) override; + STDMETHOD(SetMaterial)(const D3DMATERIAL9* pMaterial) override; + STDMETHOD(GetMaterial)(D3DMATERIAL9* pMaterial) override; + STDMETHOD(SetLight)(DWORD Index, const D3DLIGHT9*) override; + STDMETHOD(GetLight)(DWORD Index, D3DLIGHT9*) override; + STDMETHOD(LightEnable)(DWORD Index, BOOL Enable) override; + STDMETHOD(GetLightEnable)(DWORD Index, BOOL* pEnable) override; + STDMETHOD(SetClipPlane)(DWORD Index, const float* pPlane) override; + STDMETHOD(GetClipPlane)(DWORD Index, float* pPlane) override; + STDMETHOD(SetRenderState)(D3DRENDERSTATETYPE State, DWORD Value) override; + STDMETHOD(GetRenderState)(D3DRENDERSTATETYPE State, DWORD* pValue) override; + STDMETHOD(CreateStateBlock)(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB) override; + STDMETHOD(BeginStateBlock)() override; + STDMETHOD(EndStateBlock)(IDirect3DStateBlock9** ppSB) override; + STDMETHOD(SetClipStatus)(const D3DCLIPSTATUS9* pClipStatus) override; + STDMETHOD(GetClipStatus)(D3DCLIPSTATUS9* pClipStatus) override; + STDMETHOD(GetTexture)(DWORD Stage, IDirect3DBaseTexture9** ppTexture) override; + STDMETHOD(SetTexture)(DWORD Stage, IDirect3DBaseTexture9* pTexture) override; + STDMETHOD(GetTextureStageState)(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) override; + STDMETHOD(SetTextureStageState)(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) override; + STDMETHOD(GetSamplerState)(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue) override; + STDMETHOD(SetSamplerState)(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) override; + STDMETHOD(ValidateDevice)(DWORD* pNumPasses) override; + STDMETHOD(SetPaletteEntries)(UINT PaletteNumber, const PALETTEENTRY* pEntries) override; + STDMETHOD(GetPaletteEntries)(UINT PaletteNumber, PALETTEENTRY* pEntries) override; + STDMETHOD(SetCurrentTexturePalette)(UINT PaletteNumber) override; + STDMETHOD(GetCurrentTexturePalette)(UINT* PaletteNumber) override; + STDMETHOD(SetScissorRect)(const RECT* pRect) override; + STDMETHOD(GetScissorRect)(RECT* pRect) override; + STDMETHOD(SetSoftwareVertexProcessing)(BOOL bSoftware) override; + STDMETHOD_(BOOL, GetSoftwareVertexProcessing)() override; + STDMETHOD(SetNPatchMode)(float nSegments) override; + STDMETHOD_(float, GetNPatchMode)() override; + STDMETHOD(DrawPrimitive)(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) override; + STDMETHOD(DrawIndexedPrimitive)(D3DPRIMITIVETYPE, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) override; + STDMETHOD(DrawPrimitiveUP)(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) override; + STDMETHOD(DrawIndexedPrimitiveUP)(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void* pIndexData, D3DFORMAT IndexDataFormat, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) override; + STDMETHOD(ProcessVertices)(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags) override; + STDMETHOD(CreateVertexDeclaration)(const D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl) override; + STDMETHOD(SetVertexDeclaration)(IDirect3DVertexDeclaration9* pDecl) override; + STDMETHOD(GetVertexDeclaration)(IDirect3DVertexDeclaration9** ppDecl) override; + STDMETHOD(SetFVF)(DWORD FVF) override; + STDMETHOD(GetFVF)(DWORD* pFVF) override; + STDMETHOD(CreateVertexShader)(const DWORD* pFunction, IDirect3DVertexShader9** ppShader) override; + STDMETHOD(SetVertexShader)(IDirect3DVertexShader9* pShader) override; + STDMETHOD(GetVertexShader)(IDirect3DVertexShader9** ppShader) override; + STDMETHOD(SetVertexShaderConstantF)(UINT StartRegister, const float* pConstantData, UINT Vector4fCount) override; + STDMETHOD(GetVertexShaderConstantF)(UINT StartRegister, float* pConstantData, UINT Vector4fCount) override; + STDMETHOD(SetVertexShaderConstantI)(UINT StartRegister, const int* pConstantData, UINT Vector4iCount) override; + STDMETHOD(GetVertexShaderConstantI)(UINT StartRegister, int* pConstantData, UINT Vector4iCount) override; + STDMETHOD(SetVertexShaderConstantB)(UINT StartRegister, const BOOL* pConstantData, UINT BoolCount) override; + STDMETHOD(GetVertexShaderConstantB)(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) override; + STDMETHOD(SetStreamSource)(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride) override; + STDMETHOD(GetStreamSource)(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* pOffsetInBytes, UINT* pStride) override; + STDMETHOD(SetStreamSourceFreq)(UINT StreamNumber, UINT Setting) override; + STDMETHOD(GetStreamSourceFreq)(UINT StreamNumber, UINT* pSetting) override; + STDMETHOD(SetIndices)(IDirect3DIndexBuffer9* pIndexData) override; + STDMETHOD(GetIndices)(IDirect3DIndexBuffer9** ppIndexData) override; + STDMETHOD(CreatePixelShader)(const DWORD* pFunction, IDirect3DPixelShader9** ppShader) override; + STDMETHOD(SetPixelShader)(IDirect3DPixelShader9* pShader) override; + STDMETHOD(GetPixelShader)(IDirect3DPixelShader9** ppShader) override; + STDMETHOD(SetPixelShaderConstantF)(UINT StartRegister, const float* pConstantData, UINT Vector4fCount) override; + STDMETHOD(GetPixelShaderConstantF)(UINT StartRegister, float* pConstantData, UINT Vector4fCount) override; + STDMETHOD(SetPixelShaderConstantI)(UINT StartRegister, const int* pConstantData, UINT Vector4iCount) override; + STDMETHOD(GetPixelShaderConstantI)(UINT StartRegister, int* pConstantData, UINT Vector4iCount) override; + STDMETHOD(SetPixelShaderConstantB)(UINT StartRegister, const BOOL* pConstantData, UINT BoolCount) override; + STDMETHOD(GetPixelShaderConstantB)(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) override; + STDMETHOD(DrawRectPatch)(UINT Handle, const float* pNumSegs, const D3DRECTPATCH_INFO* pRectPatchInfo) override; + STDMETHOD(DrawTriPatch)(UINT Handle, const float* pNumSegs, const D3DTRIPATCH_INFO* pTriPatchInfo) override; + STDMETHOD(DeletePatch)(UINT Handle) override; + STDMETHOD(CreateQuery)(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) override; + +protected: + IDirect3DDevice9* real_; + std::atomic ref_count_; + TextureClient* client_; + + // Shared by Release() here and by WrappedDirect3DDevice9Ex::Release(); deletes + // client_ exactly as h_DeviceRelease does, via TextureClient::CurrentClient(). + void TeardownTextureClient(); +}; + +// Adds IDirect3DDevice9Ex's own methods via ordinary forwards, plus CreateDeviceEx-style +// interception is one level up (in WrappedDirect3D9Ex); this class only needs to override +// the base's virtuals once (inherited) and add the Ex-only ones. +class WrappedDirect3DDevice9Ex : public IDirect3DDevice9Ex { +public: + explicit WrappedDirect3DDevice9Ex(IDirect3DDevice9Ex* real); + + IDirect3DDevice9Ex* RealDeviceEx() const { return real_; } + TextureClient* Client() const { return client_; } + void SetClient(TextureClient* client) { client_ = client; } + + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override; + STDMETHOD_(ULONG, AddRef)() override; + STDMETHOD_(ULONG, Release)() override; + + STDMETHOD(TestCooperativeLevel)() override; + STDMETHOD_(UINT, GetAvailableTextureMem)() override; + STDMETHOD(EvictManagedResources)() override; + STDMETHOD(GetDirect3D)(IDirect3D9** ppD3D9) override; + STDMETHOD(GetDeviceCaps)(D3DCAPS9* pCaps) override; + STDMETHOD(GetDisplayMode)(UINT iSwapChain, D3DDISPLAYMODE* pMode) override; + STDMETHOD(GetCreationParameters)(D3DDEVICE_CREATION_PARAMETERS* pParameters) override; + STDMETHOD(SetCursorProperties)(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap) override; + STDMETHOD_(void, SetCursorPosition)(int X, int Y, DWORD Flags) override; + STDMETHOD_(BOOL, ShowCursor)(BOOL bShow) override; + STDMETHOD(CreateAdditionalSwapChain)(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain) override; + STDMETHOD(GetSwapChain)(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain) override; + STDMETHOD_(UINT, GetNumberOfSwapChains)() override; + STDMETHOD(Reset)(D3DPRESENT_PARAMETERS* pPresentationParameters) override; + STDMETHOD(Present)(const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion) override; + STDMETHOD(GetBackBuffer)(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer) override; + STDMETHOD(GetRasterStatus)(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus) override; + STDMETHOD(SetDialogBoxMode)(BOOL bEnableDialogs) override; + STDMETHOD_(void, SetGammaRamp)(UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP* pRamp) override; + STDMETHOD_(void, GetGammaRamp)(UINT iSwapChain, D3DGAMMARAMP* pRamp) override; + STDMETHOD(CreateTexture)(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle) override; + STDMETHOD(CreateVolumeTexture)(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle) override; + STDMETHOD(CreateCubeTexture)(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle) override; + STDMETHOD(CreateVertexBuffer)(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle) override; + STDMETHOD(CreateIndexBuffer)(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle) override; + STDMETHOD(CreateRenderTarget)(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override; + STDMETHOD(CreateDepthStencilSurface)(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override; + STDMETHOD(UpdateSurface)(IDirect3DSurface9* pSourceSurface, const RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface, const POINT* pDestPoint) override; + STDMETHOD(UpdateTexture)(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture) override; + STDMETHOD(GetRenderTargetData)(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface) override; + STDMETHOD(GetFrontBufferData)(UINT iSwapChain, IDirect3DSurface9* pDestSurface) override; + STDMETHOD(StretchRect)(IDirect3DSurface9* pSourceSurface, const RECT* pSourceRect, IDirect3DSurface9* pDestSurface, const RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter) override; + STDMETHOD(ColorFill)(IDirect3DSurface9* pSurface, const RECT* pRect, D3DCOLOR color) override; + STDMETHOD(CreateOffscreenPlainSurface)(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override; + STDMETHOD(SetRenderTarget)(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget) override; + STDMETHOD(GetRenderTarget)(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget) override; + STDMETHOD(SetDepthStencilSurface)(IDirect3DSurface9* pNewZStencil) override; + STDMETHOD(GetDepthStencilSurface)(IDirect3DSurface9** ppZStencilSurface) override; + STDMETHOD(BeginScene)() override; + STDMETHOD(EndScene)() override; + STDMETHOD(Clear)(DWORD Count, const D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) override; + STDMETHOD(SetTransform)(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix) override; + STDMETHOD(GetTransform)(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) override; + STDMETHOD(MultiplyTransform)(D3DTRANSFORMSTATETYPE, const D3DMATRIX*) override; + STDMETHOD(SetViewport)(const D3DVIEWPORT9* pViewport) override; + STDMETHOD(GetViewport)(D3DVIEWPORT9* pViewport) override; + STDMETHOD(SetMaterial)(const D3DMATERIAL9* pMaterial) override; + STDMETHOD(GetMaterial)(D3DMATERIAL9* pMaterial) override; + STDMETHOD(SetLight)(DWORD Index, const D3DLIGHT9*) override; + STDMETHOD(GetLight)(DWORD Index, D3DLIGHT9*) override; + STDMETHOD(LightEnable)(DWORD Index, BOOL Enable) override; + STDMETHOD(GetLightEnable)(DWORD Index, BOOL* pEnable) override; + STDMETHOD(SetClipPlane)(DWORD Index, const float* pPlane) override; + STDMETHOD(GetClipPlane)(DWORD Index, float* pPlane) override; + STDMETHOD(SetRenderState)(D3DRENDERSTATETYPE State, DWORD Value) override; + STDMETHOD(GetRenderState)(D3DRENDERSTATETYPE State, DWORD* pValue) override; + STDMETHOD(CreateStateBlock)(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB) override; + STDMETHOD(BeginStateBlock)() override; + STDMETHOD(EndStateBlock)(IDirect3DStateBlock9** ppSB) override; + STDMETHOD(SetClipStatus)(const D3DCLIPSTATUS9* pClipStatus) override; + STDMETHOD(GetClipStatus)(D3DCLIPSTATUS9* pClipStatus) override; + STDMETHOD(GetTexture)(DWORD Stage, IDirect3DBaseTexture9** ppTexture) override; + STDMETHOD(SetTexture)(DWORD Stage, IDirect3DBaseTexture9* pTexture) override; + STDMETHOD(GetTextureStageState)(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) override; + STDMETHOD(SetTextureStageState)(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) override; + STDMETHOD(GetSamplerState)(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue) override; + STDMETHOD(SetSamplerState)(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) override; + STDMETHOD(ValidateDevice)(DWORD* pNumPasses) override; + STDMETHOD(SetPaletteEntries)(UINT PaletteNumber, const PALETTEENTRY* pEntries) override; + STDMETHOD(GetPaletteEntries)(UINT PaletteNumber, PALETTEENTRY* pEntries) override; + STDMETHOD(SetCurrentTexturePalette)(UINT PaletteNumber) override; + STDMETHOD(GetCurrentTexturePalette)(UINT* PaletteNumber) override; + STDMETHOD(SetScissorRect)(const RECT* pRect) override; + STDMETHOD(GetScissorRect)(RECT* pRect) override; + STDMETHOD(SetSoftwareVertexProcessing)(BOOL bSoftware) override; + STDMETHOD_(BOOL, GetSoftwareVertexProcessing)() override; + STDMETHOD(SetNPatchMode)(float nSegments) override; + STDMETHOD_(float, GetNPatchMode)() override; + STDMETHOD(DrawPrimitive)(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) override; + STDMETHOD(DrawIndexedPrimitive)(D3DPRIMITIVETYPE, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) override; + STDMETHOD(DrawPrimitiveUP)(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) override; + STDMETHOD(DrawIndexedPrimitiveUP)(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void* pIndexData, D3DFORMAT IndexDataFormat, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) override; + STDMETHOD(ProcessVertices)(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags) override; + STDMETHOD(CreateVertexDeclaration)(const D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl) override; + STDMETHOD(SetVertexDeclaration)(IDirect3DVertexDeclaration9* pDecl) override; + STDMETHOD(GetVertexDeclaration)(IDirect3DVertexDeclaration9** ppDecl) override; + STDMETHOD(SetFVF)(DWORD FVF) override; + STDMETHOD(GetFVF)(DWORD* pFVF) override; + STDMETHOD(CreateVertexShader)(const DWORD* pFunction, IDirect3DVertexShader9** ppShader) override; + STDMETHOD(SetVertexShader)(IDirect3DVertexShader9* pShader) override; + STDMETHOD(GetVertexShader)(IDirect3DVertexShader9** ppShader) override; + STDMETHOD(SetVertexShaderConstantF)(UINT StartRegister, const float* pConstantData, UINT Vector4fCount) override; + STDMETHOD(GetVertexShaderConstantF)(UINT StartRegister, float* pConstantData, UINT Vector4fCount) override; + STDMETHOD(SetVertexShaderConstantI)(UINT StartRegister, const int* pConstantData, UINT Vector4iCount) override; + STDMETHOD(GetVertexShaderConstantI)(UINT StartRegister, int* pConstantData, UINT Vector4iCount) override; + STDMETHOD(SetVertexShaderConstantB)(UINT StartRegister, const BOOL* pConstantData, UINT BoolCount) override; + STDMETHOD(GetVertexShaderConstantB)(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) override; + STDMETHOD(SetStreamSource)(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride) override; + STDMETHOD(GetStreamSource)(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* pOffsetInBytes, UINT* pStride) override; + STDMETHOD(SetStreamSourceFreq)(UINT StreamNumber, UINT Setting) override; + STDMETHOD(GetStreamSourceFreq)(UINT StreamNumber, UINT* pSetting) override; + STDMETHOD(SetIndices)(IDirect3DIndexBuffer9* pIndexData) override; + STDMETHOD(GetIndices)(IDirect3DIndexBuffer9** ppIndexData) override; + STDMETHOD(CreatePixelShader)(const DWORD* pFunction, IDirect3DPixelShader9** ppShader) override; + STDMETHOD(SetPixelShader)(IDirect3DPixelShader9* pShader) override; + STDMETHOD(GetPixelShader)(IDirect3DPixelShader9** ppShader) override; + STDMETHOD(SetPixelShaderConstantF)(UINT StartRegister, const float* pConstantData, UINT Vector4fCount) override; + STDMETHOD(GetPixelShaderConstantF)(UINT StartRegister, float* pConstantData, UINT Vector4fCount) override; + STDMETHOD(SetPixelShaderConstantI)(UINT StartRegister, const int* pConstantData, UINT Vector4iCount) override; + STDMETHOD(GetPixelShaderConstantI)(UINT StartRegister, int* pConstantData, UINT Vector4iCount) override; + STDMETHOD(SetPixelShaderConstantB)(UINT StartRegister, const BOOL* pConstantData, UINT BoolCount) override; + STDMETHOD(GetPixelShaderConstantB)(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) override; + STDMETHOD(DrawRectPatch)(UINT Handle, const float* pNumSegs, const D3DRECTPATCH_INFO* pRectPatchInfo) override; + STDMETHOD(DrawTriPatch)(UINT Handle, const float* pNumSegs, const D3DTRIPATCH_INFO* pTriPatchInfo) override; + STDMETHOD(DeletePatch)(UINT Handle) override; + STDMETHOD(CreateQuery)(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) override; + + STDMETHOD(SetConvolutionMonoKernel)(UINT width, UINT height, float* rows, float* columns) override; + STDMETHOD(ComposeRects)(IDirect3DSurface9* pSrc, IDirect3DSurface9* pDst, IDirect3DVertexBuffer9* pSrcRectDescs, UINT NumRects, IDirect3DVertexBuffer9* pDstRectDescs, D3DCOMPOSERECTSOP Operation, int Xoffset, int Yoffset) override; + STDMETHOD(PresentEx)(const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion, DWORD dwFlags) override; + STDMETHOD(GetGPUThreadPriority)(INT* pPriority) override; + STDMETHOD(SetGPUThreadPriority)(INT Priority) override; + STDMETHOD(WaitForVBlank)(UINT iSwapChain) override; + STDMETHOD(CheckResourceResidency)(IDirect3DResource9** pResourceArray, UINT32 NumResources) override; + STDMETHOD(SetMaximumFrameLatency)(UINT MaxLatency) override; + STDMETHOD(GetMaximumFrameLatency)(UINT* pMaxLatency) override; + STDMETHOD(CheckDeviceState)(HWND hDestinationWindow) override; + STDMETHOD(CreateRenderTargetEx)(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) override; + STDMETHOD(CreateOffscreenPlainSurfaceEx)(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) override; + STDMETHOD(CreateDepthStencilSurfaceEx)(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) override; + STDMETHOD(ResetEx)(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) override; + STDMETHOD(GetDisplayModeEx)(UINT iSwapChain, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation) override; + +private: + IDirect3DDevice9Ex* real_; + std::atomic ref_count_; + TextureClient* client_; + + void TeardownTextureClient(); +}; diff --git a/header/D3D9TextureWrappers.h b/header/D3D9TextureWrappers.h new file mode 100644 index 0000000..ab34edc --- /dev/null +++ b/header/D3D9TextureWrappers.h @@ -0,0 +1,127 @@ +#pragma once + +#include +#include + +class TextureClient; + +// Wraps a real IDirect3D*Texture9 so every method is ordinary compiled virtual dispatch +// instead of a MinHook-patched vtable slot. See D3D9DeviceWrapper.h for why this matters. +class WrappedTexture9 : public IDirect3DTexture9 { +public: + explicit WrappedTexture9(IDirect3DTexture9* real); + + IDirect3DTexture9* RealTexture() const { return real_; } + + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override; + STDMETHOD_(ULONG, AddRef)() override; + STDMETHOD_(ULONG, Release)() override; + + STDMETHOD(GetDevice)(IDirect3DDevice9** ppDevice) override; + STDMETHOD(SetPrivateData)(REFGUID refguid, const void* pData, DWORD SizeOfData, DWORD Flags) override; + STDMETHOD(GetPrivateData)(REFGUID refguid, void* pData, DWORD* pSizeOfData) override; + STDMETHOD(FreePrivateData)(REFGUID refguid) override; + STDMETHOD_(DWORD, SetPriority)(DWORD PriorityNew) override; + STDMETHOD_(DWORD, GetPriority)() override; + STDMETHOD_(void, PreLoad)() override; + STDMETHOD_(D3DRESOURCETYPE, GetType)() override; + + STDMETHOD_(DWORD, SetLOD)(DWORD LODNew) override; + STDMETHOD_(DWORD, GetLOD)() override; + STDMETHOD_(DWORD, GetLevelCount)() override; + STDMETHOD(SetAutoGenFilterType)(D3DTEXTUREFILTERTYPE FilterType) override; + STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)() override; + STDMETHOD_(void, GenerateMipSubLevels)() override; + + STDMETHOD(GetLevelDesc)(UINT Level, D3DSURFACE_DESC* pDesc) override; + STDMETHOD(GetSurfaceLevel)(UINT Level, IDirect3DSurface9** ppSurfaceLevel) override; + STDMETHOD(LockRect)(UINT Level, D3DLOCKED_RECT* pLockedRect, const RECT* pRect, DWORD Flags) override; + STDMETHOD(UnlockRect)(UINT Level) override; + STDMETHOD(AddDirtyRect)(const RECT* pDirtyRect) override; + +private: + IDirect3DTexture9* real_; + std::atomic ref_count_; +}; + +class WrappedVolumeTexture9 : public IDirect3DVolumeTexture9 { +public: + explicit WrappedVolumeTexture9(IDirect3DVolumeTexture9* real); + + IDirect3DVolumeTexture9* RealTexture() const { return real_; } + + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override; + STDMETHOD_(ULONG, AddRef)() override; + STDMETHOD_(ULONG, Release)() override; + + STDMETHOD(GetDevice)(IDirect3DDevice9** ppDevice) override; + STDMETHOD(SetPrivateData)(REFGUID refguid, const void* pData, DWORD SizeOfData, DWORD Flags) override; + STDMETHOD(GetPrivateData)(REFGUID refguid, void* pData, DWORD* pSizeOfData) override; + STDMETHOD(FreePrivateData)(REFGUID refguid) override; + STDMETHOD_(DWORD, SetPriority)(DWORD PriorityNew) override; + STDMETHOD_(DWORD, GetPriority)() override; + STDMETHOD_(void, PreLoad)() override; + STDMETHOD_(D3DRESOURCETYPE, GetType)() override; + + STDMETHOD_(DWORD, SetLOD)(DWORD LODNew) override; + STDMETHOD_(DWORD, GetLOD)() override; + STDMETHOD_(DWORD, GetLevelCount)() override; + STDMETHOD(SetAutoGenFilterType)(D3DTEXTUREFILTERTYPE FilterType) override; + STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)() override; + STDMETHOD_(void, GenerateMipSubLevels)() override; + + STDMETHOD(GetLevelDesc)(UINT Level, D3DVOLUME_DESC* pDesc) override; + STDMETHOD(GetVolumeLevel)(UINT Level, IDirect3DVolume9** ppVolumeLevel) override; + STDMETHOD(LockBox)(UINT Level, D3DLOCKED_BOX* pLockedVolume, const D3DBOX* pBox, DWORD Flags) override; + STDMETHOD(UnlockBox)(UINT Level) override; + STDMETHOD(AddDirtyBox)(const D3DBOX* pDirtyBox) override; + +private: + IDirect3DVolumeTexture9* real_; + std::atomic ref_count_; +}; + +class WrappedCubeTexture9 : public IDirect3DCubeTexture9 { +public: + explicit WrappedCubeTexture9(IDirect3DCubeTexture9* real); + + IDirect3DCubeTexture9* RealTexture() const { return real_; } + + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override; + STDMETHOD_(ULONG, AddRef)() override; + STDMETHOD_(ULONG, Release)() override; + + STDMETHOD(GetDevice)(IDirect3DDevice9** ppDevice) override; + STDMETHOD(SetPrivateData)(REFGUID refguid, const void* pData, DWORD SizeOfData, DWORD Flags) override; + STDMETHOD(GetPrivateData)(REFGUID refguid, void* pData, DWORD* pSizeOfData) override; + STDMETHOD(FreePrivateData)(REFGUID refguid) override; + STDMETHOD_(DWORD, SetPriority)(DWORD PriorityNew) override; + STDMETHOD_(DWORD, GetPriority)() override; + STDMETHOD_(void, PreLoad)() override; + STDMETHOD_(D3DRESOURCETYPE, GetType)() override; + + STDMETHOD_(DWORD, SetLOD)(DWORD LODNew) override; + STDMETHOD_(DWORD, GetLOD)() override; + STDMETHOD_(DWORD, GetLevelCount)() override; + STDMETHOD(SetAutoGenFilterType)(D3DTEXTUREFILTERTYPE FilterType) override; + STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)() override; + STDMETHOD_(void, GenerateMipSubLevels)() override; + + STDMETHOD(GetLevelDesc)(UINT Level, D3DSURFACE_DESC* pDesc) override; + STDMETHOD(GetCubeMapSurface)(D3DCUBEMAP_FACES FaceType, UINT Level, IDirect3DSurface9** ppCubeMapSurface) override; + STDMETHOD(LockRect)(D3DCUBEMAP_FACES FaceType, UINT Level, D3DLOCKED_RECT* pLockedRect, const RECT* pRect, DWORD Flags) override; + STDMETHOD(UnlockRect)(D3DCUBEMAP_FACES FaceType, UINT Level) override; + STDMETHOD(AddDirtyRect)(D3DCUBEMAP_FACES FaceType, const RECT* pDirtyRect) override; + +private: + IDirect3DCubeTexture9* real_; + std::atomic ref_count_; +}; + +// Real texture pointer -> wrapper, for the D3D9 calls that only ever hand back real +// pointers (e.g. IDirect3DDevice9::GetTexture) so they can be turned back into the +// wrapper identity the game must see. Populated by each wrapper's constructor, erased +// in its destructor/Release. +IDirect3DBaseTexture9* FindWrapperForRealTexture(IDirect3DBaseTexture9* real); +void RegisterWrapperForRealTexture(IDirect3DBaseTexture9* real, IDirect3DBaseTexture9* wrapper); +void UnregisterWrapperForRealTexture(IDirect3DBaseTexture9* real); diff --git a/header/D3D9Wrappers.h b/header/D3D9Wrappers.h new file mode 100644 index 0000000..6ac2d63 --- /dev/null +++ b/header/D3D9Wrappers.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include + +// 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 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 ref_count_; +}; diff --git a/source/D3D9DeviceWrapper.cpp b/source/D3D9DeviceWrapper.cpp new file mode 100644 index 0000000..309ad67 --- /dev/null +++ b/source/D3D9DeviceWrapper.cpp @@ -0,0 +1,536 @@ +#include "Main.h" +#include "D3D9DeviceWrapper.h" +#include "D3D9TextureWrappers.h" + +import TextureClient; + +namespace { + + // Unwraps a WrappedTexture9/WrappedVolumeTexture9/WrappedCubeTexture9 to the real + // pointer the real device needs; passes non-wrapper (or null) pointers through as-is. + IDirect3DBaseTexture9* Unwrap(IDirect3DBaseTexture9* texture) + { + if (texture == nullptr) return nullptr; + switch (texture->GetType()) { + case D3DRTYPE_TEXTURE: return static_cast(texture)->RealTexture(); + case D3DRTYPE_VOLUMETEXTURE: return static_cast(texture)->RealTexture(); + case D3DRTYPE_CUBETEXTURE: return static_cast(texture)->RealTexture(); + default: return texture; + } + } + +} + +// ---- WrappedDirect3DDevice9 ---------------------------------------------- + +WrappedDirect3DDevice9::WrappedDirect3DDevice9(IDirect3DDevice9* real) : real_(real), ref_count_(1), client_(nullptr) +{ + real_->AddRef(); +} + +HRESULT WrappedDirect3DDevice9::QueryInterface(REFIID riid, void** ppvObj) +{ + if (riid == IID_IUnknown || riid == IID_IDirect3DDevice9) { + AddRef(); + *ppvObj = this; + return S_OK; + } + // Unrecognized-but-successful QueryInterface hands back an unwrapped real pointer. + return real_->QueryInterface(riid, ppvObj); +} + +ULONG WrappedDirect3DDevice9::AddRef() +{ + return ++ref_count_; +} + +void WrappedDirect3DDevice9::TeardownTextureClient() +{ + if (auto* client = TextureClient::CurrentClient()) + delete client; +} + +ULONG WrappedDirect3DDevice9::Release() +{ + const ULONG count = --ref_count_; + if (count == 0) { + TeardownTextureClient(); + real_->Release(); + delete this; + return 0; + } + return count; +} + +HRESULT WrappedDirect3DDevice9::TestCooperativeLevel() { return real_->TestCooperativeLevel(); } +UINT WrappedDirect3DDevice9::GetAvailableTextureMem() { return real_->GetAvailableTextureMem(); } +HRESULT WrappedDirect3DDevice9::EvictManagedResources() { return real_->EvictManagedResources(); } +HRESULT WrappedDirect3DDevice9::GetDirect3D(IDirect3D9** ppD3D9) { return real_->GetDirect3D(ppD3D9); } +HRESULT WrappedDirect3DDevice9::GetDeviceCaps(D3DCAPS9* pCaps) { return real_->GetDeviceCaps(pCaps); } +HRESULT WrappedDirect3DDevice9::GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode) { return real_->GetDisplayMode(iSwapChain, pMode); } +HRESULT WrappedDirect3DDevice9::GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS* pParameters) { return real_->GetCreationParameters(pParameters); } +HRESULT WrappedDirect3DDevice9::SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap) { return real_->SetCursorProperties(XHotSpot, YHotSpot, pCursorBitmap); } +void WrappedDirect3DDevice9::SetCursorPosition(int X, int Y, DWORD Flags) { real_->SetCursorPosition(X, Y, Flags); } +BOOL WrappedDirect3DDevice9::ShowCursor(BOOL bShow) { return real_->ShowCursor(bShow); } +HRESULT WrappedDirect3DDevice9::CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain) { return real_->CreateAdditionalSwapChain(pPresentationParameters, pSwapChain); } +HRESULT WrappedDirect3DDevice9::GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain) { return real_->GetSwapChain(iSwapChain, pSwapChain); } +UINT WrappedDirect3DDevice9::GetNumberOfSwapChains() { return real_->GetNumberOfSwapChains(); } +HRESULT WrappedDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) { return real_->Reset(pPresentationParameters); } +HRESULT WrappedDirect3DDevice9::Present(const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion) { return real_->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); } +HRESULT WrappedDirect3DDevice9::GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer) { return real_->GetBackBuffer(iSwapChain, iBackBuffer, Type, ppBackBuffer); } +HRESULT WrappedDirect3DDevice9::GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus) { return real_->GetRasterStatus(iSwapChain, pRasterStatus); } +HRESULT WrappedDirect3DDevice9::SetDialogBoxMode(BOOL bEnableDialogs) { return real_->SetDialogBoxMode(bEnableDialogs); } +void WrappedDirect3DDevice9::SetGammaRamp(UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP* pRamp) { real_->SetGammaRamp(iSwapChain, Flags, pRamp); } +void WrappedDirect3DDevice9::GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp) { real_->GetGammaRamp(iSwapChain, pRamp); } + +HRESULT WrappedDirect3DDevice9::CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle) +{ + IDirect3DTexture9* real_texture = nullptr; + const HRESULT hr = real_->CreateTexture(Width, Height, Levels, Usage, Format, Pool, &real_texture, pSharedHandle); + if (FAILED(hr) || real_texture == nullptr) { + if (ppTexture) *ppTexture = nullptr; + return hr; + } + const auto wrapped = new WrappedTexture9(real_texture); + real_texture->Release(); // the wrapper holds its own AddRef'd reference + if (client_) client_->OnCreateTexture(wrapped, TexType::Tex2D); + *ppTexture = wrapped; + return hr; +} + +HRESULT WrappedDirect3DDevice9::CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle) +{ + IDirect3DVolumeTexture9* real_texture = nullptr; + const HRESULT hr = real_->CreateVolumeTexture(Width, Height, Depth, Levels, Usage, Format, Pool, &real_texture, pSharedHandle); + if (FAILED(hr) || real_texture == nullptr) { + if (ppVolumeTexture) *ppVolumeTexture = nullptr; + return hr; + } + const auto wrapped = new WrappedVolumeTexture9(real_texture); + real_texture->Release(); + if (client_) client_->OnCreateTexture(wrapped, TexType::Volume); + *ppVolumeTexture = wrapped; + return hr; +} + +HRESULT WrappedDirect3DDevice9::CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle) +{ + IDirect3DCubeTexture9* real_texture = nullptr; + const HRESULT hr = real_->CreateCubeTexture(EdgeLength, Levels, Usage, Format, Pool, &real_texture, pSharedHandle); + if (FAILED(hr) || real_texture == nullptr) { + if (ppCubeTexture) *ppCubeTexture = nullptr; + return hr; + } + const auto wrapped = new WrappedCubeTexture9(real_texture); + real_texture->Release(); + if (client_) client_->OnCreateTexture(wrapped, TexType::Cube); + *ppCubeTexture = wrapped; + return hr; +} + +HRESULT WrappedDirect3DDevice9::CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle) { return real_->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle); } +HRESULT WrappedDirect3DDevice9::CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle) { return real_->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, pSharedHandle); } +HRESULT WrappedDirect3DDevice9::CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) { return real_->CreateRenderTarget(Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle); } +HRESULT WrappedDirect3DDevice9::CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) { return real_->CreateDepthStencilSurface(Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle); } +HRESULT WrappedDirect3DDevice9::UpdateSurface(IDirect3DSurface9* pSourceSurface, const RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface, const POINT* pDestPoint) { return real_->UpdateSurface(pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint); } + +HRESULT WrappedDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture) +{ + const HRESULT hr = real_->UpdateTexture(Unwrap(pSourceTexture), Unwrap(pDestinationTexture)); + if (SUCCEEDED(hr) && client_) + client_->OnUpdateTexture(pSourceTexture, pDestinationTexture); // re-hash by wrapper identity + return hr; +} + +HRESULT WrappedDirect3DDevice9::GetRenderTargetData(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface) { return real_->GetRenderTargetData(pRenderTarget, pDestSurface); } +HRESULT WrappedDirect3DDevice9::GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface) { return real_->GetFrontBufferData(iSwapChain, pDestSurface); } +HRESULT WrappedDirect3DDevice9::StretchRect(IDirect3DSurface9* pSourceSurface, const RECT* pSourceRect, IDirect3DSurface9* pDestSurface, const RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter) { return real_->StretchRect(pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter); } +HRESULT WrappedDirect3DDevice9::ColorFill(IDirect3DSurface9* pSurface, const RECT* pRect, D3DCOLOR color) { return real_->ColorFill(pSurface, pRect, color); } +HRESULT WrappedDirect3DDevice9::CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) { return real_->CreateOffscreenPlainSurface(Width, Height, Format, Pool, ppSurface, pSharedHandle); } +HRESULT WrappedDirect3DDevice9::SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget) { return real_->SetRenderTarget(RenderTargetIndex, pRenderTarget); } +HRESULT WrappedDirect3DDevice9::GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget) { return real_->GetRenderTarget(RenderTargetIndex, ppRenderTarget); } +HRESULT WrappedDirect3DDevice9::SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil) { return real_->SetDepthStencilSurface(pNewZStencil); } +HRESULT WrappedDirect3DDevice9::GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface) { return real_->GetDepthStencilSurface(ppZStencilSurface); } + +HRESULT WrappedDirect3DDevice9::BeginScene() +{ + if (client_) client_->OnBeginScene(); + return real_->BeginScene(); +} + +HRESULT WrappedDirect3DDevice9::EndScene() { return real_->EndScene(); } +HRESULT WrappedDirect3DDevice9::Clear(DWORD Count, const D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) { return real_->Clear(Count, pRects, Flags, Color, Z, Stencil); } +HRESULT WrappedDirect3DDevice9::SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix) { return real_->SetTransform(State, pMatrix); } +HRESULT WrappedDirect3DDevice9::GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) { return real_->GetTransform(State, pMatrix); } +HRESULT WrappedDirect3DDevice9::MultiplyTransform(D3DTRANSFORMSTATETYPE state, const D3DMATRIX* matrix) { return real_->MultiplyTransform(state, matrix); } +HRESULT WrappedDirect3DDevice9::SetViewport(const D3DVIEWPORT9* pViewport) { return real_->SetViewport(pViewport); } +HRESULT WrappedDirect3DDevice9::GetViewport(D3DVIEWPORT9* pViewport) { return real_->GetViewport(pViewport); } +HRESULT WrappedDirect3DDevice9::SetMaterial(const D3DMATERIAL9* pMaterial) { return real_->SetMaterial(pMaterial); } +HRESULT WrappedDirect3DDevice9::GetMaterial(D3DMATERIAL9* pMaterial) { return real_->GetMaterial(pMaterial); } +HRESULT WrappedDirect3DDevice9::SetLight(DWORD Index, const D3DLIGHT9* light) { return real_->SetLight(Index, light); } +HRESULT WrappedDirect3DDevice9::GetLight(DWORD Index, D3DLIGHT9* light) { return real_->GetLight(Index, light); } +HRESULT WrappedDirect3DDevice9::LightEnable(DWORD Index, BOOL Enable) { return real_->LightEnable(Index, Enable); } +HRESULT WrappedDirect3DDevice9::GetLightEnable(DWORD Index, BOOL* pEnable) { return real_->GetLightEnable(Index, pEnable); } +HRESULT WrappedDirect3DDevice9::SetClipPlane(DWORD Index, const float* pPlane) { return real_->SetClipPlane(Index, pPlane); } +HRESULT WrappedDirect3DDevice9::GetClipPlane(DWORD Index, float* pPlane) { return real_->GetClipPlane(Index, pPlane); } +HRESULT WrappedDirect3DDevice9::SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) { return real_->SetRenderState(State, Value); } +HRESULT WrappedDirect3DDevice9::GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue) { return real_->GetRenderState(State, pValue); } +HRESULT WrappedDirect3DDevice9::CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB) { return real_->CreateStateBlock(Type, ppSB); } +HRESULT WrappedDirect3DDevice9::BeginStateBlock() { return real_->BeginStateBlock(); } +HRESULT WrappedDirect3DDevice9::EndStateBlock(IDirect3DStateBlock9** ppSB) { return real_->EndStateBlock(ppSB); } +HRESULT WrappedDirect3DDevice9::SetClipStatus(const D3DCLIPSTATUS9* pClipStatus) { return real_->SetClipStatus(pClipStatus); } +HRESULT WrappedDirect3DDevice9::GetClipStatus(D3DCLIPSTATUS9* pClipStatus) { return real_->GetClipStatus(pClipStatus); } + +HRESULT WrappedDirect3DDevice9::GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture) +{ + const HRESULT hr = real_->GetTexture(Stage, ppTexture); + if (FAILED(hr) || !ppTexture || !*ppTexture) return hr; + + // The real call only ever returns real pointers; recover the wrapper identity. + auto* wrapper = FindWrapperForRealTexture(*ppTexture); + if (wrapper == nullptr) { + // Not one of ours (created before hooks/pass-through path) - nothing to translate. + return hr; + } + (*ppTexture)->Release(); // drop the real ref the runtime handed back + IDirect3DBaseTexture9* result = wrapper; + + if (client_) { + if (auto* original = client_->ResolveOriginalFromFake(wrapper)) { + original->AddRef(); + result = original; + } + else { + wrapper->AddRef(); + } + } + else { + wrapper->AddRef(); + } + *ppTexture = result; + return hr; +} + +HRESULT WrappedDirect3DDevice9::SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture) +{ + IDirect3DBaseTexture9* bind = client_ ? client_->ResolveBinding(pTexture) : pTexture; + return real_->SetTexture(Stage, Unwrap(bind)); +} + +HRESULT WrappedDirect3DDevice9::GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) { return real_->GetTextureStageState(Stage, Type, pValue); } +HRESULT WrappedDirect3DDevice9::SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) { return real_->SetTextureStageState(Stage, Type, Value); } +HRESULT WrappedDirect3DDevice9::GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue) { return real_->GetSamplerState(Sampler, Type, pValue); } +HRESULT WrappedDirect3DDevice9::SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) { return real_->SetSamplerState(Sampler, Type, Value); } +HRESULT WrappedDirect3DDevice9::ValidateDevice(DWORD* pNumPasses) { return real_->ValidateDevice(pNumPasses); } +HRESULT WrappedDirect3DDevice9::SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY* pEntries) { return real_->SetPaletteEntries(PaletteNumber, pEntries); } +HRESULT WrappedDirect3DDevice9::GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries) { return real_->GetPaletteEntries(PaletteNumber, pEntries); } +HRESULT WrappedDirect3DDevice9::SetCurrentTexturePalette(UINT PaletteNumber) { return real_->SetCurrentTexturePalette(PaletteNumber); } +HRESULT WrappedDirect3DDevice9::GetCurrentTexturePalette(UINT* PaletteNumber) { return real_->GetCurrentTexturePalette(PaletteNumber); } +HRESULT WrappedDirect3DDevice9::SetScissorRect(const RECT* pRect) { return real_->SetScissorRect(pRect); } +HRESULT WrappedDirect3DDevice9::GetScissorRect(RECT* pRect) { return real_->GetScissorRect(pRect); } +HRESULT WrappedDirect3DDevice9::SetSoftwareVertexProcessing(BOOL bSoftware) { return real_->SetSoftwareVertexProcessing(bSoftware); } +BOOL WrappedDirect3DDevice9::GetSoftwareVertexProcessing() { return real_->GetSoftwareVertexProcessing(); } +HRESULT WrappedDirect3DDevice9::SetNPatchMode(float nSegments) { return real_->SetNPatchMode(nSegments); } +float WrappedDirect3DDevice9::GetNPatchMode() { return real_->GetNPatchMode(); } +HRESULT WrappedDirect3DDevice9::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) { return real_->DrawPrimitive(PrimitiveType, StartVertex, PrimitiveCount); } +HRESULT WrappedDirect3DDevice9::DrawIndexedPrimitive(D3DPRIMITIVETYPE type, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) { return real_->DrawIndexedPrimitive(type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); } +HRESULT WrappedDirect3DDevice9::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) { return real_->DrawPrimitiveUP(PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); } +HRESULT WrappedDirect3DDevice9::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void* pIndexData, D3DFORMAT IndexDataFormat, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) { return real_->DrawIndexedPrimitiveUP(PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); } +HRESULT WrappedDirect3DDevice9::ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags) { return real_->ProcessVertices(SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags); } +HRESULT WrappedDirect3DDevice9::CreateVertexDeclaration(const D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl) { return real_->CreateVertexDeclaration(pVertexElements, ppDecl); } +HRESULT WrappedDirect3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl) { return real_->SetVertexDeclaration(pDecl); } +HRESULT WrappedDirect3DDevice9::GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl) { return real_->GetVertexDeclaration(ppDecl); } +HRESULT WrappedDirect3DDevice9::SetFVF(DWORD FVF) { return real_->SetFVF(FVF); } +HRESULT WrappedDirect3DDevice9::GetFVF(DWORD* pFVF) { return real_->GetFVF(pFVF); } +HRESULT WrappedDirect3DDevice9::CreateVertexShader(const DWORD* pFunction, IDirect3DVertexShader9** ppShader) { return real_->CreateVertexShader(pFunction, ppShader); } +HRESULT WrappedDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9* pShader) { return real_->SetVertexShader(pShader); } +HRESULT WrappedDirect3DDevice9::GetVertexShader(IDirect3DVertexShader9** ppShader) { return real_->GetVertexShader(ppShader); } +HRESULT WrappedDirect3DDevice9::SetVertexShaderConstantF(UINT StartRegister, const float* pConstantData, UINT Vector4fCount) { return real_->SetVertexShaderConstantF(StartRegister, pConstantData, Vector4fCount); } +HRESULT WrappedDirect3DDevice9::GetVertexShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount) { return real_->GetVertexShaderConstantF(StartRegister, pConstantData, Vector4fCount); } +HRESULT WrappedDirect3DDevice9::SetVertexShaderConstantI(UINT StartRegister, const int* pConstantData, UINT Vector4iCount) { return real_->SetVertexShaderConstantI(StartRegister, pConstantData, Vector4iCount); } +HRESULT WrappedDirect3DDevice9::GetVertexShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount) { return real_->GetVertexShaderConstantI(StartRegister, pConstantData, Vector4iCount); } +HRESULT WrappedDirect3DDevice9::SetVertexShaderConstantB(UINT StartRegister, const BOOL* pConstantData, UINT BoolCount) { return real_->SetVertexShaderConstantB(StartRegister, pConstantData, BoolCount); } +HRESULT WrappedDirect3DDevice9::GetVertexShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) { return real_->GetVertexShaderConstantB(StartRegister, pConstantData, BoolCount); } +HRESULT WrappedDirect3DDevice9::SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride) { return real_->SetStreamSource(StreamNumber, pStreamData, OffsetInBytes, Stride); } +HRESULT WrappedDirect3DDevice9::GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* pOffsetInBytes, UINT* pStride) { return real_->GetStreamSource(StreamNumber, ppStreamData, pOffsetInBytes, pStride); } +HRESULT WrappedDirect3DDevice9::SetStreamSourceFreq(UINT StreamNumber, UINT Setting) { return real_->SetStreamSourceFreq(StreamNumber, Setting); } +HRESULT WrappedDirect3DDevice9::GetStreamSourceFreq(UINT StreamNumber, UINT* pSetting) { return real_->GetStreamSourceFreq(StreamNumber, pSetting); } +HRESULT WrappedDirect3DDevice9::SetIndices(IDirect3DIndexBuffer9* pIndexData) { return real_->SetIndices(pIndexData); } +HRESULT WrappedDirect3DDevice9::GetIndices(IDirect3DIndexBuffer9** ppIndexData) { return real_->GetIndices(ppIndexData); } +HRESULT WrappedDirect3DDevice9::CreatePixelShader(const DWORD* pFunction, IDirect3DPixelShader9** ppShader) { return real_->CreatePixelShader(pFunction, ppShader); } +HRESULT WrappedDirect3DDevice9::SetPixelShader(IDirect3DPixelShader9* pShader) { return real_->SetPixelShader(pShader); } +HRESULT WrappedDirect3DDevice9::GetPixelShader(IDirect3DPixelShader9** ppShader) { return real_->GetPixelShader(ppShader); } +HRESULT WrappedDirect3DDevice9::SetPixelShaderConstantF(UINT StartRegister, const float* pConstantData, UINT Vector4fCount) { return real_->SetPixelShaderConstantF(StartRegister, pConstantData, Vector4fCount); } +HRESULT WrappedDirect3DDevice9::GetPixelShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount) { return real_->GetPixelShaderConstantF(StartRegister, pConstantData, Vector4fCount); } +HRESULT WrappedDirect3DDevice9::SetPixelShaderConstantI(UINT StartRegister, const int* pConstantData, UINT Vector4iCount) { return real_->SetPixelShaderConstantI(StartRegister, pConstantData, Vector4iCount); } +HRESULT WrappedDirect3DDevice9::GetPixelShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount) { return real_->GetPixelShaderConstantI(StartRegister, pConstantData, Vector4iCount); } +HRESULT WrappedDirect3DDevice9::SetPixelShaderConstantB(UINT StartRegister, const BOOL* pConstantData, UINT BoolCount) { return real_->SetPixelShaderConstantB(StartRegister, pConstantData, BoolCount); } +HRESULT WrappedDirect3DDevice9::GetPixelShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) { return real_->GetPixelShaderConstantB(StartRegister, pConstantData, BoolCount); } +HRESULT WrappedDirect3DDevice9::DrawRectPatch(UINT Handle, const float* pNumSegs, const D3DRECTPATCH_INFO* pRectPatchInfo) { return real_->DrawRectPatch(Handle, pNumSegs, pRectPatchInfo); } +HRESULT WrappedDirect3DDevice9::DrawTriPatch(UINT Handle, const float* pNumSegs, const D3DTRIPATCH_INFO* pTriPatchInfo) { return real_->DrawTriPatch(Handle, pNumSegs, pTriPatchInfo); } +HRESULT WrappedDirect3DDevice9::DeletePatch(UINT Handle) { return real_->DeletePatch(Handle); } +HRESULT WrappedDirect3DDevice9::CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) { return real_->CreateQuery(Type, ppQuery); } + +// ---- WrappedDirect3DDevice9Ex --------------------------------------------- + +WrappedDirect3DDevice9Ex::WrappedDirect3DDevice9Ex(IDirect3DDevice9Ex* real) : real_(real), ref_count_(1), client_(nullptr) +{ + real_->AddRef(); +} + +HRESULT WrappedDirect3DDevice9Ex::QueryInterface(REFIID riid, void** ppvObj) +{ + if (riid == IID_IUnknown || riid == IID_IDirect3DDevice9 || riid == IID_IDirect3DDevice9Ex) { + AddRef(); + *ppvObj = this; + return S_OK; + } + // Unrecognized-but-successful QueryInterface hands back an unwrapped real pointer. + return real_->QueryInterface(riid, ppvObj); +} + +ULONG WrappedDirect3DDevice9Ex::AddRef() +{ + return ++ref_count_; +} + +void WrappedDirect3DDevice9Ex::TeardownTextureClient() +{ + if (auto* client = TextureClient::CurrentClient()) + delete client; +} + +ULONG WrappedDirect3DDevice9Ex::Release() +{ + const ULONG count = --ref_count_; + if (count == 0) { + TeardownTextureClient(); + real_->Release(); + delete this; + return 0; + } + return count; +} + +HRESULT WrappedDirect3DDevice9Ex::TestCooperativeLevel() { return real_->TestCooperativeLevel(); } +UINT WrappedDirect3DDevice9Ex::GetAvailableTextureMem() { return real_->GetAvailableTextureMem(); } +HRESULT WrappedDirect3DDevice9Ex::EvictManagedResources() { return real_->EvictManagedResources(); } +HRESULT WrappedDirect3DDevice9Ex::GetDirect3D(IDirect3D9** ppD3D9) { return real_->GetDirect3D(ppD3D9); } +HRESULT WrappedDirect3DDevice9Ex::GetDeviceCaps(D3DCAPS9* pCaps) { return real_->GetDeviceCaps(pCaps); } +HRESULT WrappedDirect3DDevice9Ex::GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode) { return real_->GetDisplayMode(iSwapChain, pMode); } +HRESULT WrappedDirect3DDevice9Ex::GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS* pParameters) { return real_->GetCreationParameters(pParameters); } +HRESULT WrappedDirect3DDevice9Ex::SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap) { return real_->SetCursorProperties(XHotSpot, YHotSpot, pCursorBitmap); } +void WrappedDirect3DDevice9Ex::SetCursorPosition(int X, int Y, DWORD Flags) { real_->SetCursorPosition(X, Y, Flags); } +BOOL WrappedDirect3DDevice9Ex::ShowCursor(BOOL bShow) { return real_->ShowCursor(bShow); } +HRESULT WrappedDirect3DDevice9Ex::CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain) { return real_->CreateAdditionalSwapChain(pPresentationParameters, pSwapChain); } +HRESULT WrappedDirect3DDevice9Ex::GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain) { return real_->GetSwapChain(iSwapChain, pSwapChain); } +UINT WrappedDirect3DDevice9Ex::GetNumberOfSwapChains() { return real_->GetNumberOfSwapChains(); } +HRESULT WrappedDirect3DDevice9Ex::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) { return real_->Reset(pPresentationParameters); } +HRESULT WrappedDirect3DDevice9Ex::Present(const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion) { return real_->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); } +HRESULT WrappedDirect3DDevice9Ex::GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer) { return real_->GetBackBuffer(iSwapChain, iBackBuffer, Type, ppBackBuffer); } +HRESULT WrappedDirect3DDevice9Ex::GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus) { return real_->GetRasterStatus(iSwapChain, pRasterStatus); } +HRESULT WrappedDirect3DDevice9Ex::SetDialogBoxMode(BOOL bEnableDialogs) { return real_->SetDialogBoxMode(bEnableDialogs); } +void WrappedDirect3DDevice9Ex::SetGammaRamp(UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP* pRamp) { real_->SetGammaRamp(iSwapChain, Flags, pRamp); } +void WrappedDirect3DDevice9Ex::GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp) { real_->GetGammaRamp(iSwapChain, pRamp); } + +HRESULT WrappedDirect3DDevice9Ex::CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle) +{ + IDirect3DTexture9* real_texture = nullptr; + const HRESULT hr = real_->CreateTexture(Width, Height, Levels, Usage, Format, Pool, &real_texture, pSharedHandle); + if (FAILED(hr) || real_texture == nullptr) { + if (ppTexture) *ppTexture = nullptr; + return hr; + } + const auto wrapped = new WrappedTexture9(real_texture); + real_texture->Release(); + if (client_) client_->OnCreateTexture(wrapped, TexType::Tex2D); + *ppTexture = wrapped; + return hr; +} + +HRESULT WrappedDirect3DDevice9Ex::CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle) +{ + IDirect3DVolumeTexture9* real_texture = nullptr; + const HRESULT hr = real_->CreateVolumeTexture(Width, Height, Depth, Levels, Usage, Format, Pool, &real_texture, pSharedHandle); + if (FAILED(hr) || real_texture == nullptr) { + if (ppVolumeTexture) *ppVolumeTexture = nullptr; + return hr; + } + const auto wrapped = new WrappedVolumeTexture9(real_texture); + real_texture->Release(); + if (client_) client_->OnCreateTexture(wrapped, TexType::Volume); + *ppVolumeTexture = wrapped; + return hr; +} + +HRESULT WrappedDirect3DDevice9Ex::CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle) +{ + IDirect3DCubeTexture9* real_texture = nullptr; + const HRESULT hr = real_->CreateCubeTexture(EdgeLength, Levels, Usage, Format, Pool, &real_texture, pSharedHandle); + if (FAILED(hr) || real_texture == nullptr) { + if (ppCubeTexture) *ppCubeTexture = nullptr; + return hr; + } + const auto wrapped = new WrappedCubeTexture9(real_texture); + real_texture->Release(); + if (client_) client_->OnCreateTexture(wrapped, TexType::Cube); + *ppCubeTexture = wrapped; + return hr; +} + +HRESULT WrappedDirect3DDevice9Ex::CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle) { return real_->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle); } +HRESULT WrappedDirect3DDevice9Ex::CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle) { return real_->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, pSharedHandle); } +HRESULT WrappedDirect3DDevice9Ex::CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) { return real_->CreateRenderTarget(Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle); } +HRESULT WrappedDirect3DDevice9Ex::CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) { return real_->CreateDepthStencilSurface(Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle); } +HRESULT WrappedDirect3DDevice9Ex::UpdateSurface(IDirect3DSurface9* pSourceSurface, const RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface, const POINT* pDestPoint) { return real_->UpdateSurface(pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint); } + +HRESULT WrappedDirect3DDevice9Ex::UpdateTexture(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture) +{ + const HRESULT hr = real_->UpdateTexture(Unwrap(pSourceTexture), Unwrap(pDestinationTexture)); + if (SUCCEEDED(hr) && client_) + client_->OnUpdateTexture(pSourceTexture, pDestinationTexture); + return hr; +} + +HRESULT WrappedDirect3DDevice9Ex::GetRenderTargetData(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface) { return real_->GetRenderTargetData(pRenderTarget, pDestSurface); } +HRESULT WrappedDirect3DDevice9Ex::GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface) { return real_->GetFrontBufferData(iSwapChain, pDestSurface); } +HRESULT WrappedDirect3DDevice9Ex::StretchRect(IDirect3DSurface9* pSourceSurface, const RECT* pSourceRect, IDirect3DSurface9* pDestSurface, const RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter) { return real_->StretchRect(pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter); } +HRESULT WrappedDirect3DDevice9Ex::ColorFill(IDirect3DSurface9* pSurface, const RECT* pRect, D3DCOLOR color) { return real_->ColorFill(pSurface, pRect, color); } +HRESULT WrappedDirect3DDevice9Ex::CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) { return real_->CreateOffscreenPlainSurface(Width, Height, Format, Pool, ppSurface, pSharedHandle); } +HRESULT WrappedDirect3DDevice9Ex::SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget) { return real_->SetRenderTarget(RenderTargetIndex, pRenderTarget); } +HRESULT WrappedDirect3DDevice9Ex::GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget) { return real_->GetRenderTarget(RenderTargetIndex, ppRenderTarget); } +HRESULT WrappedDirect3DDevice9Ex::SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil) { return real_->SetDepthStencilSurface(pNewZStencil); } +HRESULT WrappedDirect3DDevice9Ex::GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface) { return real_->GetDepthStencilSurface(ppZStencilSurface); } + +HRESULT WrappedDirect3DDevice9Ex::BeginScene() +{ + if (client_) client_->OnBeginScene(); + return real_->BeginScene(); +} + +HRESULT WrappedDirect3DDevice9Ex::EndScene() { return real_->EndScene(); } +HRESULT WrappedDirect3DDevice9Ex::Clear(DWORD Count, const D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) { return real_->Clear(Count, pRects, Flags, Color, Z, Stencil); } +HRESULT WrappedDirect3DDevice9Ex::SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix) { return real_->SetTransform(State, pMatrix); } +HRESULT WrappedDirect3DDevice9Ex::GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) { return real_->GetTransform(State, pMatrix); } +HRESULT WrappedDirect3DDevice9Ex::MultiplyTransform(D3DTRANSFORMSTATETYPE state, const D3DMATRIX* matrix) { return real_->MultiplyTransform(state, matrix); } +HRESULT WrappedDirect3DDevice9Ex::SetViewport(const D3DVIEWPORT9* pViewport) { return real_->SetViewport(pViewport); } +HRESULT WrappedDirect3DDevice9Ex::GetViewport(D3DVIEWPORT9* pViewport) { return real_->GetViewport(pViewport); } +HRESULT WrappedDirect3DDevice9Ex::SetMaterial(const D3DMATERIAL9* pMaterial) { return real_->SetMaterial(pMaterial); } +HRESULT WrappedDirect3DDevice9Ex::GetMaterial(D3DMATERIAL9* pMaterial) { return real_->GetMaterial(pMaterial); } +HRESULT WrappedDirect3DDevice9Ex::SetLight(DWORD Index, const D3DLIGHT9* light) { return real_->SetLight(Index, light); } +HRESULT WrappedDirect3DDevice9Ex::GetLight(DWORD Index, D3DLIGHT9* light) { return real_->GetLight(Index, light); } +HRESULT WrappedDirect3DDevice9Ex::LightEnable(DWORD Index, BOOL Enable) { return real_->LightEnable(Index, Enable); } +HRESULT WrappedDirect3DDevice9Ex::GetLightEnable(DWORD Index, BOOL* pEnable) { return real_->GetLightEnable(Index, pEnable); } +HRESULT WrappedDirect3DDevice9Ex::SetClipPlane(DWORD Index, const float* pPlane) { return real_->SetClipPlane(Index, pPlane); } +HRESULT WrappedDirect3DDevice9Ex::GetClipPlane(DWORD Index, float* pPlane) { return real_->GetClipPlane(Index, pPlane); } +HRESULT WrappedDirect3DDevice9Ex::SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) { return real_->SetRenderState(State, Value); } +HRESULT WrappedDirect3DDevice9Ex::GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue) { return real_->GetRenderState(State, pValue); } +HRESULT WrappedDirect3DDevice9Ex::CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB) { return real_->CreateStateBlock(Type, ppSB); } +HRESULT WrappedDirect3DDevice9Ex::BeginStateBlock() { return real_->BeginStateBlock(); } +HRESULT WrappedDirect3DDevice9Ex::EndStateBlock(IDirect3DStateBlock9** ppSB) { return real_->EndStateBlock(ppSB); } +HRESULT WrappedDirect3DDevice9Ex::SetClipStatus(const D3DCLIPSTATUS9* pClipStatus) { return real_->SetClipStatus(pClipStatus); } +HRESULT WrappedDirect3DDevice9Ex::GetClipStatus(D3DCLIPSTATUS9* pClipStatus) { return real_->GetClipStatus(pClipStatus); } + +HRESULT WrappedDirect3DDevice9Ex::GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture) +{ + const HRESULT hr = real_->GetTexture(Stage, ppTexture); + if (FAILED(hr) || !ppTexture || !*ppTexture) return hr; + + auto* wrapper = FindWrapperForRealTexture(*ppTexture); + if (wrapper == nullptr) { + return hr; + } + (*ppTexture)->Release(); + IDirect3DBaseTexture9* result = wrapper; + + if (client_) { + if (auto* original = client_->ResolveOriginalFromFake(wrapper)) { + original->AddRef(); + result = original; + } + else { + wrapper->AddRef(); + } + } + else { + wrapper->AddRef(); + } + *ppTexture = result; + return hr; +} + +HRESULT WrappedDirect3DDevice9Ex::SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture) +{ + IDirect3DBaseTexture9* bind = client_ ? client_->ResolveBinding(pTexture) : pTexture; + return real_->SetTexture(Stage, Unwrap(bind)); +} + +HRESULT WrappedDirect3DDevice9Ex::GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) { return real_->GetTextureStageState(Stage, Type, pValue); } +HRESULT WrappedDirect3DDevice9Ex::SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) { return real_->SetTextureStageState(Stage, Type, Value); } +HRESULT WrappedDirect3DDevice9Ex::GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue) { return real_->GetSamplerState(Sampler, Type, pValue); } +HRESULT WrappedDirect3DDevice9Ex::SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) { return real_->SetSamplerState(Sampler, Type, Value); } +HRESULT WrappedDirect3DDevice9Ex::ValidateDevice(DWORD* pNumPasses) { return real_->ValidateDevice(pNumPasses); } +HRESULT WrappedDirect3DDevice9Ex::SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY* pEntries) { return real_->SetPaletteEntries(PaletteNumber, pEntries); } +HRESULT WrappedDirect3DDevice9Ex::GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries) { return real_->GetPaletteEntries(PaletteNumber, pEntries); } +HRESULT WrappedDirect3DDevice9Ex::SetCurrentTexturePalette(UINT PaletteNumber) { return real_->SetCurrentTexturePalette(PaletteNumber); } +HRESULT WrappedDirect3DDevice9Ex::GetCurrentTexturePalette(UINT* PaletteNumber) { return real_->GetCurrentTexturePalette(PaletteNumber); } +HRESULT WrappedDirect3DDevice9Ex::SetScissorRect(const RECT* pRect) { return real_->SetScissorRect(pRect); } +HRESULT WrappedDirect3DDevice9Ex::GetScissorRect(RECT* pRect) { return real_->GetScissorRect(pRect); } +HRESULT WrappedDirect3DDevice9Ex::SetSoftwareVertexProcessing(BOOL bSoftware) { return real_->SetSoftwareVertexProcessing(bSoftware); } +BOOL WrappedDirect3DDevice9Ex::GetSoftwareVertexProcessing() { return real_->GetSoftwareVertexProcessing(); } +HRESULT WrappedDirect3DDevice9Ex::SetNPatchMode(float nSegments) { return real_->SetNPatchMode(nSegments); } +float WrappedDirect3DDevice9Ex::GetNPatchMode() { return real_->GetNPatchMode(); } +HRESULT WrappedDirect3DDevice9Ex::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) { return real_->DrawPrimitive(PrimitiveType, StartVertex, PrimitiveCount); } +HRESULT WrappedDirect3DDevice9Ex::DrawIndexedPrimitive(D3DPRIMITIVETYPE type, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) { return real_->DrawIndexedPrimitive(type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); } +HRESULT WrappedDirect3DDevice9Ex::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) { return real_->DrawPrimitiveUP(PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); } +HRESULT WrappedDirect3DDevice9Ex::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void* pIndexData, D3DFORMAT IndexDataFormat, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) { return real_->DrawIndexedPrimitiveUP(PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); } +HRESULT WrappedDirect3DDevice9Ex::ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags) { return real_->ProcessVertices(SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags); } +HRESULT WrappedDirect3DDevice9Ex::CreateVertexDeclaration(const D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl) { return real_->CreateVertexDeclaration(pVertexElements, ppDecl); } +HRESULT WrappedDirect3DDevice9Ex::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl) { return real_->SetVertexDeclaration(pDecl); } +HRESULT WrappedDirect3DDevice9Ex::GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl) { return real_->GetVertexDeclaration(ppDecl); } +HRESULT WrappedDirect3DDevice9Ex::SetFVF(DWORD FVF) { return real_->SetFVF(FVF); } +HRESULT WrappedDirect3DDevice9Ex::GetFVF(DWORD* pFVF) { return real_->GetFVF(pFVF); } +HRESULT WrappedDirect3DDevice9Ex::CreateVertexShader(const DWORD* pFunction, IDirect3DVertexShader9** ppShader) { return real_->CreateVertexShader(pFunction, ppShader); } +HRESULT WrappedDirect3DDevice9Ex::SetVertexShader(IDirect3DVertexShader9* pShader) { return real_->SetVertexShader(pShader); } +HRESULT WrappedDirect3DDevice9Ex::GetVertexShader(IDirect3DVertexShader9** ppShader) { return real_->GetVertexShader(ppShader); } +HRESULT WrappedDirect3DDevice9Ex::SetVertexShaderConstantF(UINT StartRegister, const float* pConstantData, UINT Vector4fCount) { return real_->SetVertexShaderConstantF(StartRegister, pConstantData, Vector4fCount); } +HRESULT WrappedDirect3DDevice9Ex::GetVertexShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount) { return real_->GetVertexShaderConstantF(StartRegister, pConstantData, Vector4fCount); } +HRESULT WrappedDirect3DDevice9Ex::SetVertexShaderConstantI(UINT StartRegister, const int* pConstantData, UINT Vector4iCount) { return real_->SetVertexShaderConstantI(StartRegister, pConstantData, Vector4iCount); } +HRESULT WrappedDirect3DDevice9Ex::GetVertexShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount) { return real_->GetVertexShaderConstantI(StartRegister, pConstantData, Vector4iCount); } +HRESULT WrappedDirect3DDevice9Ex::SetVertexShaderConstantB(UINT StartRegister, const BOOL* pConstantData, UINT BoolCount) { return real_->SetVertexShaderConstantB(StartRegister, pConstantData, BoolCount); } +HRESULT WrappedDirect3DDevice9Ex::GetVertexShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) { return real_->GetVertexShaderConstantB(StartRegister, pConstantData, BoolCount); } +HRESULT WrappedDirect3DDevice9Ex::SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride) { return real_->SetStreamSource(StreamNumber, pStreamData, OffsetInBytes, Stride); } +HRESULT WrappedDirect3DDevice9Ex::GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* pOffsetInBytes, UINT* pStride) { return real_->GetStreamSource(StreamNumber, ppStreamData, pOffsetInBytes, pStride); } +HRESULT WrappedDirect3DDevice9Ex::SetStreamSourceFreq(UINT StreamNumber, UINT Setting) { return real_->SetStreamSourceFreq(StreamNumber, Setting); } +HRESULT WrappedDirect3DDevice9Ex::GetStreamSourceFreq(UINT StreamNumber, UINT* pSetting) { return real_->GetStreamSourceFreq(StreamNumber, pSetting); } +HRESULT WrappedDirect3DDevice9Ex::SetIndices(IDirect3DIndexBuffer9* pIndexData) { return real_->SetIndices(pIndexData); } +HRESULT WrappedDirect3DDevice9Ex::GetIndices(IDirect3DIndexBuffer9** ppIndexData) { return real_->GetIndices(ppIndexData); } +HRESULT WrappedDirect3DDevice9Ex::CreatePixelShader(const DWORD* pFunction, IDirect3DPixelShader9** ppShader) { return real_->CreatePixelShader(pFunction, ppShader); } +HRESULT WrappedDirect3DDevice9Ex::SetPixelShader(IDirect3DPixelShader9* pShader) { return real_->SetPixelShader(pShader); } +HRESULT WrappedDirect3DDevice9Ex::GetPixelShader(IDirect3DPixelShader9** ppShader) { return real_->GetPixelShader(ppShader); } +HRESULT WrappedDirect3DDevice9Ex::SetPixelShaderConstantF(UINT StartRegister, const float* pConstantData, UINT Vector4fCount) { return real_->SetPixelShaderConstantF(StartRegister, pConstantData, Vector4fCount); } +HRESULT WrappedDirect3DDevice9Ex::GetPixelShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount) { return real_->GetPixelShaderConstantF(StartRegister, pConstantData, Vector4fCount); } +HRESULT WrappedDirect3DDevice9Ex::SetPixelShaderConstantI(UINT StartRegister, const int* pConstantData, UINT Vector4iCount) { return real_->SetPixelShaderConstantI(StartRegister, pConstantData, Vector4iCount); } +HRESULT WrappedDirect3DDevice9Ex::GetPixelShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount) { return real_->GetPixelShaderConstantI(StartRegister, pConstantData, Vector4iCount); } +HRESULT WrappedDirect3DDevice9Ex::SetPixelShaderConstantB(UINT StartRegister, const BOOL* pConstantData, UINT BoolCount) { return real_->SetPixelShaderConstantB(StartRegister, pConstantData, BoolCount); } +HRESULT WrappedDirect3DDevice9Ex::GetPixelShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) { return real_->GetPixelShaderConstantB(StartRegister, pConstantData, BoolCount); } +HRESULT WrappedDirect3DDevice9Ex::DrawRectPatch(UINT Handle, const float* pNumSegs, const D3DRECTPATCH_INFO* pRectPatchInfo) { return real_->DrawRectPatch(Handle, pNumSegs, pRectPatchInfo); } +HRESULT WrappedDirect3DDevice9Ex::DrawTriPatch(UINT Handle, const float* pNumSegs, const D3DTRIPATCH_INFO* pTriPatchInfo) { return real_->DrawTriPatch(Handle, pNumSegs, pTriPatchInfo); } +HRESULT WrappedDirect3DDevice9Ex::DeletePatch(UINT Handle) { return real_->DeletePatch(Handle); } +HRESULT WrappedDirect3DDevice9Ex::CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) { return real_->CreateQuery(Type, ppQuery); } + +HRESULT WrappedDirect3DDevice9Ex::SetConvolutionMonoKernel(UINT width, UINT height, float* rows, float* columns) { return real_->SetConvolutionMonoKernel(width, height, rows, columns); } +HRESULT WrappedDirect3DDevice9Ex::ComposeRects(IDirect3DSurface9* pSrc, IDirect3DSurface9* pDst, IDirect3DVertexBuffer9* pSrcRectDescs, UINT NumRects, IDirect3DVertexBuffer9* pDstRectDescs, D3DCOMPOSERECTSOP Operation, int Xoffset, int Yoffset) { return real_->ComposeRects(pSrc, pDst, pSrcRectDescs, NumRects, pDstRectDescs, Operation, Xoffset, Yoffset); } +HRESULT WrappedDirect3DDevice9Ex::PresentEx(const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion, DWORD dwFlags) { return real_->PresentEx(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); } +HRESULT WrappedDirect3DDevice9Ex::GetGPUThreadPriority(INT* pPriority) { return real_->GetGPUThreadPriority(pPriority); } +HRESULT WrappedDirect3DDevice9Ex::SetGPUThreadPriority(INT Priority) { return real_->SetGPUThreadPriority(Priority); } +HRESULT WrappedDirect3DDevice9Ex::WaitForVBlank(UINT iSwapChain) { return real_->WaitForVBlank(iSwapChain); } +HRESULT WrappedDirect3DDevice9Ex::CheckResourceResidency(IDirect3DResource9** pResourceArray, UINT32 NumResources) { return real_->CheckResourceResidency(pResourceArray, NumResources); } +HRESULT WrappedDirect3DDevice9Ex::SetMaximumFrameLatency(UINT MaxLatency) { return real_->SetMaximumFrameLatency(MaxLatency); } +HRESULT WrappedDirect3DDevice9Ex::GetMaximumFrameLatency(UINT* pMaxLatency) { return real_->GetMaximumFrameLatency(pMaxLatency); } +HRESULT WrappedDirect3DDevice9Ex::CheckDeviceState(HWND hDestinationWindow) { return real_->CheckDeviceState(hDestinationWindow); } +HRESULT WrappedDirect3DDevice9Ex::CreateRenderTargetEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) { return real_->CreateRenderTargetEx(Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle, Usage); } +HRESULT WrappedDirect3DDevice9Ex::CreateOffscreenPlainSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) { return real_->CreateOffscreenPlainSurfaceEx(Width, Height, Format, Pool, ppSurface, pSharedHandle, Usage); } +HRESULT WrappedDirect3DDevice9Ex::CreateDepthStencilSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) { return real_->CreateDepthStencilSurfaceEx(Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle, Usage); } +HRESULT WrappedDirect3DDevice9Ex::ResetEx(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) { return real_->ResetEx(pPresentationParameters, pFullscreenDisplayMode); } +HRESULT WrappedDirect3DDevice9Ex::GetDisplayModeEx(UINT iSwapChain, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation) { return real_->GetDisplayModeEx(iSwapChain, pMode, pRotation); } diff --git a/source/D3D9TextureWrappers.cpp b/source/D3D9TextureWrappers.cpp new file mode 100644 index 0000000..6bdbd5e --- /dev/null +++ b/source/D3D9TextureWrappers.cpp @@ -0,0 +1,212 @@ +#include "Main.h" +#include "D3D9TextureWrappers.h" + +#include +#include + +import TextureClient; + +namespace { + std::mutex g_real_to_wrapper_mutex; + std::unordered_map g_real_to_wrapper; +} + +IDirect3DBaseTexture9* FindWrapperForRealTexture(IDirect3DBaseTexture9* real) +{ + if (real == nullptr) return nullptr; + std::lock_guard lk(g_real_to_wrapper_mutex); + const auto it = g_real_to_wrapper.find(real); + return it != g_real_to_wrapper.end() ? it->second : nullptr; +} + +void RegisterWrapperForRealTexture(IDirect3DBaseTexture9* real, IDirect3DBaseTexture9* wrapper) +{ + std::lock_guard lk(g_real_to_wrapper_mutex); + g_real_to_wrapper[real] = wrapper; +} + +void UnregisterWrapperForRealTexture(IDirect3DBaseTexture9* real) +{ + std::lock_guard lk(g_real_to_wrapper_mutex); + g_real_to_wrapper.erase(real); +} + +// ---- WrappedTexture9 ---------------------------------------------------- + +WrappedTexture9::WrappedTexture9(IDirect3DTexture9* real) : real_(real), ref_count_(1) +{ + real_->AddRef(); + RegisterWrapperForRealTexture(real_, this); +} + +HRESULT WrappedTexture9::QueryInterface(REFIID riid, void** ppvObj) +{ + if (riid == IID_IUnknown || riid == IID_IDirect3DTexture9) { + AddRef(); + *ppvObj = this; + return S_OK; + } + // Unrecognized-but-successful QueryInterface hands back an unwrapped real pointer. + return real_->QueryInterface(riid, ppvObj); +} + +ULONG WrappedTexture9::AddRef() +{ + return ++ref_count_; +} + +ULONG WrappedTexture9::Release() +{ + const ULONG count = --ref_count_; + if (count == 0) { + if (auto* client = TextureClient::CurrentClient()) + client->OnReleaseTexture(this); + UnregisterWrapperForRealTexture(real_); + real_->Release(); + delete this; + return 0; + } + return count; +} + +HRESULT WrappedTexture9::GetDevice(IDirect3DDevice9** ppDevice) { return real_->GetDevice(ppDevice); } +HRESULT WrappedTexture9::SetPrivateData(REFGUID refguid, const void* pData, DWORD SizeOfData, DWORD Flags) { return real_->SetPrivateData(refguid, pData, SizeOfData, Flags); } +HRESULT WrappedTexture9::GetPrivateData(REFGUID refguid, void* pData, DWORD* pSizeOfData) { return real_->GetPrivateData(refguid, pData, pSizeOfData); } +HRESULT WrappedTexture9::FreePrivateData(REFGUID refguid) { return real_->FreePrivateData(refguid); } +DWORD WrappedTexture9::SetPriority(DWORD PriorityNew) { return real_->SetPriority(PriorityNew); } +DWORD WrappedTexture9::GetPriority() { return real_->GetPriority(); } +void WrappedTexture9::PreLoad() { real_->PreLoad(); } +D3DRESOURCETYPE WrappedTexture9::GetType() { return real_->GetType(); } + +DWORD WrappedTexture9::SetLOD(DWORD LODNew) { return real_->SetLOD(LODNew); } +DWORD WrappedTexture9::GetLOD() { return real_->GetLOD(); } +DWORD WrappedTexture9::GetLevelCount() { return real_->GetLevelCount(); } +HRESULT WrappedTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) { return real_->SetAutoGenFilterType(FilterType); } +D3DTEXTUREFILTERTYPE WrappedTexture9::GetAutoGenFilterType() { return real_->GetAutoGenFilterType(); } +void WrappedTexture9::GenerateMipSubLevels() { real_->GenerateMipSubLevels(); } + +HRESULT WrappedTexture9::GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) { return real_->GetLevelDesc(Level, pDesc); } +HRESULT WrappedTexture9::GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel) { return real_->GetSurfaceLevel(Level, ppSurfaceLevel); } +HRESULT WrappedTexture9::LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, const RECT* pRect, DWORD Flags) { return real_->LockRect(Level, pLockedRect, pRect, Flags); } +HRESULT WrappedTexture9::UnlockRect(UINT Level) { return real_->UnlockRect(Level); } +HRESULT WrappedTexture9::AddDirtyRect(const RECT* pDirtyRect) { return real_->AddDirtyRect(pDirtyRect); } + +// ---- WrappedVolumeTexture9 ----------------------------------------------- + +WrappedVolumeTexture9::WrappedVolumeTexture9(IDirect3DVolumeTexture9* real) : real_(real), ref_count_(1) +{ + real_->AddRef(); + RegisterWrapperForRealTexture(real_, this); +} + +HRESULT WrappedVolumeTexture9::QueryInterface(REFIID riid, void** ppvObj) +{ + if (riid == IID_IUnknown || riid == IID_IDirect3DVolumeTexture9) { + AddRef(); + *ppvObj = this; + return S_OK; + } + // Unrecognized-but-successful QueryInterface hands back an unwrapped real pointer. + return real_->QueryInterface(riid, ppvObj); +} + +ULONG WrappedVolumeTexture9::AddRef() +{ + return ++ref_count_; +} + +ULONG WrappedVolumeTexture9::Release() +{ + const ULONG count = --ref_count_; + if (count == 0) { + if (auto* client = TextureClient::CurrentClient()) + client->OnReleaseTexture(this); + UnregisterWrapperForRealTexture(real_); + real_->Release(); + delete this; + return 0; + } + return count; +} + +HRESULT WrappedVolumeTexture9::GetDevice(IDirect3DDevice9** ppDevice) { return real_->GetDevice(ppDevice); } +HRESULT WrappedVolumeTexture9::SetPrivateData(REFGUID refguid, const void* pData, DWORD SizeOfData, DWORD Flags) { return real_->SetPrivateData(refguid, pData, SizeOfData, Flags); } +HRESULT WrappedVolumeTexture9::GetPrivateData(REFGUID refguid, void* pData, DWORD* pSizeOfData) { return real_->GetPrivateData(refguid, pData, pSizeOfData); } +HRESULT WrappedVolumeTexture9::FreePrivateData(REFGUID refguid) { return real_->FreePrivateData(refguid); } +DWORD WrappedVolumeTexture9::SetPriority(DWORD PriorityNew) { return real_->SetPriority(PriorityNew); } +DWORD WrappedVolumeTexture9::GetPriority() { return real_->GetPriority(); } +void WrappedVolumeTexture9::PreLoad() { real_->PreLoad(); } +D3DRESOURCETYPE WrappedVolumeTexture9::GetType() { return real_->GetType(); } + +DWORD WrappedVolumeTexture9::SetLOD(DWORD LODNew) { return real_->SetLOD(LODNew); } +DWORD WrappedVolumeTexture9::GetLOD() { return real_->GetLOD(); } +DWORD WrappedVolumeTexture9::GetLevelCount() { return real_->GetLevelCount(); } +HRESULT WrappedVolumeTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) { return real_->SetAutoGenFilterType(FilterType); } +D3DTEXTUREFILTERTYPE WrappedVolumeTexture9::GetAutoGenFilterType() { return real_->GetAutoGenFilterType(); } +void WrappedVolumeTexture9::GenerateMipSubLevels() { real_->GenerateMipSubLevels(); } + +HRESULT WrappedVolumeTexture9::GetLevelDesc(UINT Level, D3DVOLUME_DESC* pDesc) { return real_->GetLevelDesc(Level, pDesc); } +HRESULT WrappedVolumeTexture9::GetVolumeLevel(UINT Level, IDirect3DVolume9** ppVolumeLevel) { return real_->GetVolumeLevel(Level, ppVolumeLevel); } +HRESULT WrappedVolumeTexture9::LockBox(UINT Level, D3DLOCKED_BOX* pLockedVolume, const D3DBOX* pBox, DWORD Flags) { return real_->LockBox(Level, pLockedVolume, pBox, Flags); } +HRESULT WrappedVolumeTexture9::UnlockBox(UINT Level) { return real_->UnlockBox(Level); } +HRESULT WrappedVolumeTexture9::AddDirtyBox(const D3DBOX* pDirtyBox) { return real_->AddDirtyBox(pDirtyBox); } + +// ---- WrappedCubeTexture9 ------------------------------------------------- + +WrappedCubeTexture9::WrappedCubeTexture9(IDirect3DCubeTexture9* real) : real_(real), ref_count_(1) +{ + real_->AddRef(); + RegisterWrapperForRealTexture(real_, this); +} + +HRESULT WrappedCubeTexture9::QueryInterface(REFIID riid, void** ppvObj) +{ + if (riid == IID_IUnknown || riid == IID_IDirect3DCubeTexture9) { + AddRef(); + *ppvObj = this; + return S_OK; + } + // Unrecognized-but-successful QueryInterface hands back an unwrapped real pointer. + return real_->QueryInterface(riid, ppvObj); +} + +ULONG WrappedCubeTexture9::AddRef() +{ + return ++ref_count_; +} + +ULONG WrappedCubeTexture9::Release() +{ + const ULONG count = --ref_count_; + if (count == 0) { + if (auto* client = TextureClient::CurrentClient()) + client->OnReleaseTexture(this); + UnregisterWrapperForRealTexture(real_); + real_->Release(); + delete this; + return 0; + } + return count; +} + +HRESULT WrappedCubeTexture9::GetDevice(IDirect3DDevice9** ppDevice) { return real_->GetDevice(ppDevice); } +HRESULT WrappedCubeTexture9::SetPrivateData(REFGUID refguid, const void* pData, DWORD SizeOfData, DWORD Flags) { return real_->SetPrivateData(refguid, pData, SizeOfData, Flags); } +HRESULT WrappedCubeTexture9::GetPrivateData(REFGUID refguid, void* pData, DWORD* pSizeOfData) { return real_->GetPrivateData(refguid, pData, pSizeOfData); } +HRESULT WrappedCubeTexture9::FreePrivateData(REFGUID refguid) { return real_->FreePrivateData(refguid); } +DWORD WrappedCubeTexture9::SetPriority(DWORD PriorityNew) { return real_->SetPriority(PriorityNew); } +DWORD WrappedCubeTexture9::GetPriority() { return real_->GetPriority(); } +void WrappedCubeTexture9::PreLoad() { real_->PreLoad(); } +D3DRESOURCETYPE WrappedCubeTexture9::GetType() { return real_->GetType(); } + +DWORD WrappedCubeTexture9::SetLOD(DWORD LODNew) { return real_->SetLOD(LODNew); } +DWORD WrappedCubeTexture9::GetLOD() { return real_->GetLOD(); } +DWORD WrappedCubeTexture9::GetLevelCount() { return real_->GetLevelCount(); } +HRESULT WrappedCubeTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) { return real_->SetAutoGenFilterType(FilterType); } +D3DTEXTUREFILTERTYPE WrappedCubeTexture9::GetAutoGenFilterType() { return real_->GetAutoGenFilterType(); } +void WrappedCubeTexture9::GenerateMipSubLevels() { real_->GenerateMipSubLevels(); } + +HRESULT WrappedCubeTexture9::GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) { return real_->GetLevelDesc(Level, pDesc); } +HRESULT WrappedCubeTexture9::GetCubeMapSurface(D3DCUBEMAP_FACES FaceType, UINT Level, IDirect3DSurface9** ppCubeMapSurface) { return real_->GetCubeMapSurface(FaceType, Level, ppCubeMapSurface); } +HRESULT WrappedCubeTexture9::LockRect(D3DCUBEMAP_FACES FaceType, UINT Level, D3DLOCKED_RECT* pLockedRect, const RECT* pRect, DWORD Flags) { return real_->LockRect(FaceType, Level, pLockedRect, pRect, Flags); } +HRESULT WrappedCubeTexture9::UnlockRect(D3DCUBEMAP_FACES FaceType, UINT Level) { return real_->UnlockRect(FaceType, Level); } +HRESULT WrappedCubeTexture9::AddDirtyRect(D3DCUBEMAP_FACES FaceType, const RECT* pDirtyRect) { return real_->AddDirtyRect(FaceType, pDirtyRect); } diff --git a/source/D3D9Wrappers.cpp b/source/D3D9Wrappers.cpp new file mode 100644 index 0000000..a719d52 --- /dev/null +++ b/source/D3D9Wrappers.cpp @@ -0,0 +1,166 @@ +#include "Main.h" +#include "D3D9Wrappers.h" +#include "D3D9DeviceWrapper.h" + +import TextureClient; + +namespace { + + // Constructs the device wrapper + its TextureClient. The client must be built with + // the wrapper pointer (not the real device) so DirectX::CreateDDSTextureFromMemoryEx's + // internal CreateTexture call re-enters the wrapper's intercepted CreateTexture, which + // is what makes loading_fake-gated registration (see TextureClient::OnCreateTexture) + // see that call at all. + template + Wrapper* WrapDevice(Real* real_device) + { + const auto wrapper = new Wrapper(real_device); + const auto client = new TextureClient(wrapper); + wrapper->SetClient(client); + client->Initialize(); + return wrapper; + } + +} + +WrappedDirect3D9::WrappedDirect3D9(IDirect3D9* real) : real_(real), ref_count_(1) +{ + real_->AddRef(); +} + +HRESULT WrappedDirect3D9::QueryInterface(REFIID riid, void** ppvObj) +{ + if (riid == IID_IUnknown || riid == IID_IDirect3D9) { + AddRef(); + *ppvObj = this; + return S_OK; + } + // Unrecognized-but-successful QueryInterface hands back an unwrapped real pointer. + return real_->QueryInterface(riid, ppvObj); +} + +ULONG WrappedDirect3D9::AddRef() +{ + return ++ref_count_; +} + +ULONG WrappedDirect3D9::Release() +{ + const ULONG count = --ref_count_; + if (count == 0) { + real_->Release(); + delete this; + return 0; + } + return count; +} + +HRESULT WrappedDirect3D9::RegisterSoftwareDevice(void* pInitializeFunction) { return real_->RegisterSoftwareDevice(pInitializeFunction); } +UINT WrappedDirect3D9::GetAdapterCount() { return real_->GetAdapterCount(); } +HRESULT WrappedDirect3D9::GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier) { return real_->GetAdapterIdentifier(Adapter, Flags, pIdentifier); } +UINT WrappedDirect3D9::GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) { return real_->GetAdapterModeCount(Adapter, Format); } +HRESULT WrappedDirect3D9::EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode) { return real_->EnumAdapterModes(Adapter, Format, Mode, pMode); } +HRESULT WrappedDirect3D9::GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) { return real_->GetAdapterDisplayMode(Adapter, pMode); } +HRESULT WrappedDirect3D9::CheckDeviceType(UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) { return real_->CheckDeviceType(Adapter, DevType, AdapterFormat, BackBufferFormat, bWindowed); } +HRESULT WrappedDirect3D9::CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) { return real_->CheckDeviceFormat(Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat); } +HRESULT WrappedDirect3D9::CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) { return real_->CheckDeviceMultiSampleType(Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType, pQualityLevels); } +HRESULT WrappedDirect3D9::CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) { return real_->CheckDepthStencilMatch(Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat); } +HRESULT WrappedDirect3D9::CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) { return real_->CheckDeviceFormatConversion(Adapter, DeviceType, SourceFormat, TargetFormat); } +HRESULT WrappedDirect3D9::GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps) { return real_->GetDeviceCaps(Adapter, DeviceType, pCaps); } +HMONITOR WrappedDirect3D9::GetAdapterMonitor(UINT Adapter) { return real_->GetAdapterMonitor(Adapter); } + +HRESULT WrappedDirect3D9::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) +{ + IDirect3DDevice9* real_device = nullptr; + const HRESULT hr = real_->CreateDevice(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, &real_device); + if (FAILED(hr) || real_device == nullptr) { + if (ppReturnedDeviceInterface) *ppReturnedDeviceInterface = nullptr; + return hr; + } + const auto wrapped = WrapDevice(real_device); + real_device->Release(); // the wrapper holds its own AddRef'd reference + *ppReturnedDeviceInterface = wrapped; + return hr; +} + +// ---- WrappedDirect3D9Ex --------------------------------------------------- + +WrappedDirect3D9Ex::WrappedDirect3D9Ex(IDirect3D9Ex* real) : real_(real), ref_count_(1) +{ + real_->AddRef(); +} + +HRESULT WrappedDirect3D9Ex::QueryInterface(REFIID riid, void** ppvObj) +{ + if (riid == IID_IUnknown || riid == IID_IDirect3D9 || riid == IID_IDirect3D9Ex) { + AddRef(); + *ppvObj = this; + return S_OK; + } + // Unrecognized-but-successful QueryInterface hands back an unwrapped real pointer. + return real_->QueryInterface(riid, ppvObj); +} + +ULONG WrappedDirect3D9Ex::AddRef() +{ + return ++ref_count_; +} + +ULONG WrappedDirect3D9Ex::Release() +{ + const ULONG count = --ref_count_; + if (count == 0) { + real_->Release(); + delete this; + return 0; + } + return count; +} + +HRESULT WrappedDirect3D9Ex::RegisterSoftwareDevice(void* pInitializeFunction) { return real_->RegisterSoftwareDevice(pInitializeFunction); } +UINT WrappedDirect3D9Ex::GetAdapterCount() { return real_->GetAdapterCount(); } +HRESULT WrappedDirect3D9Ex::GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier) { return real_->GetAdapterIdentifier(Adapter, Flags, pIdentifier); } +UINT WrappedDirect3D9Ex::GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) { return real_->GetAdapterModeCount(Adapter, Format); } +HRESULT WrappedDirect3D9Ex::EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode) { return real_->EnumAdapterModes(Adapter, Format, Mode, pMode); } +HRESULT WrappedDirect3D9Ex::GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) { return real_->GetAdapterDisplayMode(Adapter, pMode); } +HRESULT WrappedDirect3D9Ex::CheckDeviceType(UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) { return real_->CheckDeviceType(Adapter, DevType, AdapterFormat, BackBufferFormat, bWindowed); } +HRESULT WrappedDirect3D9Ex::CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) { return real_->CheckDeviceFormat(Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat); } +HRESULT WrappedDirect3D9Ex::CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) { return real_->CheckDeviceMultiSampleType(Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType, pQualityLevels); } +HRESULT WrappedDirect3D9Ex::CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) { return real_->CheckDepthStencilMatch(Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat); } +HRESULT WrappedDirect3D9Ex::CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) { return real_->CheckDeviceFormatConversion(Adapter, DeviceType, SourceFormat, TargetFormat); } +HRESULT WrappedDirect3D9Ex::GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps) { return real_->GetDeviceCaps(Adapter, DeviceType, pCaps); } +HMONITOR WrappedDirect3D9Ex::GetAdapterMonitor(UINT Adapter) { return real_->GetAdapterMonitor(Adapter); } + +HRESULT WrappedDirect3D9Ex::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) +{ + IDirect3DDevice9* real_device = nullptr; + const HRESULT hr = real_->CreateDevice(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, &real_device); + if (FAILED(hr) || real_device == nullptr) { + if (ppReturnedDeviceInterface) *ppReturnedDeviceInterface = nullptr; + return hr; + } + const auto wrapped = WrapDevice(real_device); + real_device->Release(); + *ppReturnedDeviceInterface = wrapped; + return hr; +} + +UINT WrappedDirect3D9Ex::GetAdapterModeCountEx(UINT Adapter, const D3DDISPLAYMODEFILTER* pFilter) { return real_->GetAdapterModeCountEx(Adapter, pFilter); } +HRESULT WrappedDirect3D9Ex::EnumAdapterModesEx(UINT Adapter, const D3DDISPLAYMODEFILTER* pFilter, UINT Mode, D3DDISPLAYMODEEX* pMode) { return real_->EnumAdapterModesEx(Adapter, pFilter, Mode, pMode); } +HRESULT WrappedDirect3D9Ex::GetAdapterDisplayModeEx(UINT Adapter, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation) { return real_->GetAdapterDisplayModeEx(Adapter, pMode, pRotation); } + +HRESULT WrappedDirect3D9Ex::CreateDeviceEx(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode, IDirect3DDevice9Ex** ppReturnedDeviceInterface) +{ + IDirect3DDevice9Ex* real_device = nullptr; + const HRESULT hr = real_->CreateDeviceEx(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, pFullscreenDisplayMode, &real_device); + if (FAILED(hr) || real_device == nullptr) { + if (ppReturnedDeviceInterface) *ppReturnedDeviceInterface = nullptr; + return hr; + } + const auto wrapped = WrapDevice(real_device); + real_device->Release(); + *ppReturnedDeviceInterface = wrapped; + return hr; +} + +HRESULT WrappedDirect3D9Ex::GetAdapterLUID(UINT Adapter, LUID* pLUID) { return real_->GetAdapterLUID(Adapter, pLUID); } diff --git a/source/dll_main.cpp b/source/dll_main.cpp index d359b72..3314754 100644 --- a/source/dll_main.cpp +++ b/source/dll_main.cpp @@ -2,6 +2,7 @@ #include #include "MinHook.h" #include "D3D9Hooks.h" +#include "D3D9Wrappers.h" #include import TextureClient; @@ -148,9 +149,11 @@ IDirect3D9* APIENTRY Direct3DCreate9(UINT SDKVersion) creating_d3d9 = false; - // Hook the vtable and hand the game back the real object untouched. - InstallD3D9Hooks(pIDirect3D9_orig, false); - return pIDirect3D9_orig; + // Hand the game a wrapper object instead of the real one: CreateDevice is intercepted + // via ordinary virtual dispatch, so nothing here is ever patched (see D3D9Wrappers.h). + const auto wrapped = new WrappedDirect3D9(pIDirect3D9_orig); + pIDirect3D9_orig->Release(); // the wrapper holds its own AddRef'd reference + return wrapped; } HRESULT APIENTRY Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D) @@ -172,9 +175,11 @@ HRESULT APIENTRY Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D) if (ret != S_OK) return ret; - // Hook the vtable (CreateDevice + CreateDeviceEx) and return the real object untouched. - InstallD3D9Hooks(pIDirect3D9Ex_orig, true); - *ppD3D = pIDirect3D9Ex_orig; + // Hand the game a wrapper object instead of the real one: CreateDevice/CreateDeviceEx + // are intercepted via ordinary virtual dispatch, so nothing here is ever patched. + const auto wrapped = new WrappedDirect3D9Ex(pIDirect3D9Ex_orig); + pIDirect3D9Ex_orig->Release(); // the wrapper holds its own AddRef'd reference + *ppD3D = wrapped; return ret; } From 2705ceda7beb763b62171dd64cc6eb6f0779cbaf Mon Sep 17 00:00:00 2001 From: GWToolbox Bot Date: Tue, 7 Jul 2026 10:55:30 +0000 Subject: [PATCH 2/2] Refuse late-attach if a device is already active RegisterExistingDevice deduped against D3D9Hooks.cpp's own g_devices map, but the cold Direct3DCreate9(Ex) path (D3D9Wrappers.cpp) never touches that map. If gMod is early-injected and something (e.g. GWToolbox adopting a pre-loaded gMod) also calls SetDevice on the resulting wrapper device, RegisterExistingDevice would treat it as new: MinHook-patch the wrapper's own vtable on top, and construct a second TextureClient, hitting its single-instance ASSERT. Check TextureClient::CurrentClient() first so any already-active device (via either path) is a no-op. --- source/D3D9Hooks.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/D3D9Hooks.cpp b/source/D3D9Hooks.cpp index 7b9cfda..673d14d 100644 --- a/source/D3D9Hooks.cpp +++ b/source/D3D9Hooks.cpp @@ -357,6 +357,11 @@ void InstallD3D9Hooks(IDirect3D9* d3d9, const bool is_ex) bool RegisterExistingDevice(IDirect3DDevice9* device) { if (device == nullptr) return false; + // Already active, whether registered via this path before or already wrapped by the + // cold Direct3DCreate9(Ex) path (D3D9Wrappers.cpp) - that path never touches g_devices, + // so without this check we'd double-hook the wrapper's own vtable and construct a second + // TextureClient, hitting its single-instance ASSERT. + if (TextureClient::CurrentClient() != nullptr) return false; { std::lock_guard lk(g_devices_mutex); if (g_devices.contains(device)) return false; // already known