Let us start here, from square one. No, from Zero!

This commit is contained in:
smpn2
2022-09-30 22:45:51 +09:00
parent 14215af0d1
commit b7a60638a4
1005 changed files with 303069 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
#pragma once
#include <d3d9.h>
// {EEE9CCF6-53D6-4326-9AE5-60921B3DB394}
static const GUID IID_WrappedIDirect3D9 = {
0xeee9ccf6, 0x53d6, 0x4326, { 0x9a, 0xe5, 0x60, 0x92, 0x1b, 0x3d, 0xb3, 0x94 }
};
void graphics_d3d9_init();
void graphics_d3d9_on_present(
HWND hFocusWindow,
IDirect3DDevice9 *device,
IDirect3DDevice9 *wrapped_device);
IDirect3DSurface9 *graphics_d3d9_ldj_get_sub_screen();
struct WrappedIDirect3D9 : IDirect3D9Ex {
explicit WrappedIDirect3D9(IDirect3D9 *orig) : pReal(orig), is_d3d9ex(false) {}
explicit WrappedIDirect3D9(IDirect3D9Ex *orig) : pReal(orig), is_d3d9ex(true) {}
WrappedIDirect3D9(const WrappedIDirect3D9 &) = delete;
WrappedIDirect3D9 &operator=(const WrappedIDirect3D9 &) = delete;
virtual ~WrappedIDirect3D9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirect3D9
virtual HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void *pInitializeFunction) override;
virtual UINT STDMETHODCALLTYPE GetAdapterCount() override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier) override;
virtual UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) override;
virtual HRESULT STDMETHODCALLTYPE EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceType(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels) override;
virtual HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps) override;
virtual HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter) override;
virtual HRESULT STDMETHODCALLTYPE CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9 **ppReturnedDeviceInterface) override;
#pragma endregion
#pragma region IDirect3D9Ex
virtual UINT STDMETHODCALLTYPE GetAdapterModeCountEx(UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter) override;
virtual HRESULT STDMETHODCALLTYPE EnumAdapterModesEx(UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter, UINT Mode, D3DDISPLAYMODEEX *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterDisplayModeEx(UINT Adapter, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
virtual HRESULT STDMETHODCALLTYPE CreateDeviceEx(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode, IDirect3DDevice9Ex **ppReturnedDeviceInterface) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterLUID(UINT Adapter, LUID *pLUID) override;
#pragma endregion
private:
IDirect3D9 *pReal;
bool is_d3d9ex = false;
//bool attempted_sub_swap_chain_acquire = false;
//IDirect3DSwapChain9 *sub_swap_chain = nullptr;
};
File diff suppressed because it is too large Load Diff
+210
View File
@@ -0,0 +1,210 @@
#pragma once
#include <atomic>
#include <initguid.h>
#include <d3d9.h>
#include "util/logging.h"
#include "d3d9_fake_swapchain.h"
#include "d3d9_swapchain.h"
/*
* Logging Helpers
*/
#if 0
#define WRAP_VERBOSE log_misc("graphics::d3d9", "{}", __FUNCTION__)
#define WRAP_VERBOSE_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_VERBOSE do {} while (0)
#define WRAP_VERBOSE_FMT(format, ...) do {} while (0)
#endif
#if 0
#define WRAP_DEBUG log_misc("graphics::d3d9", "{}", __FUNCTION__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
// {6DEC0D40-1339-4BDA-A5F2-2231D4010FD1}
static const GUID IID_WrappedIDirect3DDevice9 = {
0x6dec0d40, 0x1339, 0x4bda, { 0xa5, 0xf2, 0x22, 0x31, 0xd4, 0x1, 0xf, 0xd1 }
};
struct WrappedIDirect3DDevice9 : IDirect3DDevice9Ex {
explicit WrappedIDirect3DDevice9(HWND hFocusWindow, IDirect3DDevice9 *orig)
: hFocusWindow(hFocusWindow), pReal(orig), is_d3d9ex(false) {
IDirect3DDevice9Ex *device = nullptr;
// attempt to upgrade handle
if (SUCCEEDED(this->QueryInterface(IID_PPV_ARGS(&device))) && device != nullptr) {
device->Release();
}
}
explicit WrappedIDirect3DDevice9(HWND hFocusWindow, IDirect3DDevice9Ex *orig)
: hFocusWindow(hFocusWindow), pReal(orig), is_d3d9ex(true) {}
WrappedIDirect3DDevice9(const WrappedIDirect3DDevice9 &) = delete;
WrappedIDirect3DDevice9 &operator=(const WrappedIDirect3DDevice9 &) = delete;
virtual ~WrappedIDirect3DDevice9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirect3DDevice9
virtual HRESULT STDMETHODCALLTYPE TestCooperativeLevel() override;
virtual UINT STDMETHODCALLTYPE GetAvailableTextureMem() override;
virtual HRESULT STDMETHODCALLTYPE EvictManagedResources() override;
virtual HRESULT STDMETHODCALLTYPE GetDirect3D(IDirect3D9 **ppD3D9) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceCaps(D3DCAPS9 *pCaps) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters) override;
virtual HRESULT STDMETHODCALLTYPE SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9 *pCursorBitmap) override;
virtual void STDMETHODCALLTYPE SetCursorPosition(int X, int Y, DWORD Flags) override;
virtual BOOL STDMETHODCALLTYPE ShowCursor(BOOL bShow) override;
virtual HRESULT STDMETHODCALLTYPE CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **ppSwapChain) override;
virtual HRESULT STDMETHODCALLTYPE GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9 **ppSwapChain) override;
virtual UINT STDMETHODCALLTYPE GetNumberOfSwapChains() override;
virtual HRESULT STDMETHODCALLTYPE Reset(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE SetDialogBoxMode(BOOL bEnableDialogs) override;
virtual void STDMETHODCALLTYPE SetGammaRamp(UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP *pRamp) override;
virtual void STDMETHODCALLTYPE GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP *pRamp) override;
virtual HRESULT STDMETHODCALLTYPE CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9 **ppTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9 **ppVolumeTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9 **ppCubeTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9 **ppVertexBuffer, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9 **ppIndexBuffer, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE UpdateSurface(IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestinationSurface, const POINT *pDestPoint) override;
virtual HRESULT STDMETHODCALLTYPE UpdateTexture(IDirect3DBaseTexture9 *pSourceTexture, IDirect3DBaseTexture9 *pDestinationTexture) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderTargetData(IDirect3DSurface9 *pRenderTarget, IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE StretchRect(IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestSurface, const RECT *pDestRect, D3DTEXTUREFILTERTYPE Filter) override;
virtual HRESULT STDMETHODCALLTYPE ColorFill(IDirect3DSurface9 *pSurface, const RECT *pRect, D3DCOLOR color) override;
virtual HRESULT STDMETHODCALLTYPE CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 *pRenderTarget) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 **ppRenderTarget) override;
virtual HRESULT STDMETHODCALLTYPE SetDepthStencilSurface(IDirect3DSurface9 *pNewZStencil) override;
virtual HRESULT STDMETHODCALLTYPE GetDepthStencilSurface(IDirect3DSurface9 **ppZStencilSurface) override;
virtual HRESULT STDMETHODCALLTYPE BeginScene() override;
virtual HRESULT STDMETHODCALLTYPE EndScene() override;
virtual HRESULT STDMETHODCALLTYPE Clear(DWORD Count, const D3DRECT *pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) override;
virtual HRESULT STDMETHODCALLTYPE SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE MultiplyTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE SetViewport(const D3DVIEWPORT9 *pViewport) override;
virtual HRESULT STDMETHODCALLTYPE GetViewport(D3DVIEWPORT9 *pViewport) override;
virtual HRESULT STDMETHODCALLTYPE SetMaterial(const D3DMATERIAL9 *pMaterial) override;
virtual HRESULT STDMETHODCALLTYPE GetMaterial(D3DMATERIAL9 *pMaterial) override;
virtual HRESULT STDMETHODCALLTYPE SetLight(DWORD Index, const D3DLIGHT9 *pLight) override;
virtual HRESULT STDMETHODCALLTYPE GetLight(DWORD Index, D3DLIGHT9 *pLight) override;
virtual HRESULT STDMETHODCALLTYPE LightEnable(DWORD Index, BOOL Enable) override;
virtual HRESULT STDMETHODCALLTYPE GetLightEnable(DWORD Index, BOOL *pEnable) override;
virtual HRESULT STDMETHODCALLTYPE SetClipPlane(DWORD Index, const float *pPlane) override;
virtual HRESULT STDMETHODCALLTYPE GetClipPlane(DWORD Index, float *pPlane) override;
virtual HRESULT STDMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderState(D3DRENDERSTATETYPE State, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9 **ppSB) override;
virtual HRESULT STDMETHODCALLTYPE BeginStateBlock() override;
virtual HRESULT STDMETHODCALLTYPE EndStateBlock(IDirect3DStateBlock9 **ppSB) override;
virtual HRESULT STDMETHODCALLTYPE SetClipStatus(const D3DCLIPSTATUS9 *pClipStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetClipStatus(D3DCLIPSTATUS9 *pClipStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetTexture(DWORD Stage, IDirect3DBaseTexture9 **ppTexture) override;
virtual HRESULT STDMETHODCALLTYPE SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture) override;
virtual HRESULT STDMETHODCALLTYPE GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE ValidateDevice(DWORD *pNumPasses) override;
virtual HRESULT STDMETHODCALLTYPE SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY *pEntries) override;
virtual HRESULT STDMETHODCALLTYPE GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY *pEntries) override;
virtual HRESULT STDMETHODCALLTYPE SetCurrentTexturePalette(UINT PaletteNumber) override;
virtual HRESULT STDMETHODCALLTYPE GetCurrentTexturePalette(UINT *PaletteNumber) override;
virtual HRESULT STDMETHODCALLTYPE SetScissorRect(const RECT *pRect) override;
virtual HRESULT STDMETHODCALLTYPE GetScissorRect(RECT *pRect) override;
virtual HRESULT STDMETHODCALLTYPE SetSoftwareVertexProcessing(BOOL bSoftware) override;
virtual BOOL STDMETHODCALLTYPE GetSoftwareVertexProcessing() override;
virtual HRESULT STDMETHODCALLTYPE SetNPatchMode(float nSegments) override;
virtual float STDMETHODCALLTYPE GetNPatchMode() override;
virtual HRESULT STDMETHODCALLTYPE DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride) override;
virtual HRESULT STDMETHODCALLTYPE DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void *pIndexData, D3DFORMAT IndexDataFormat, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride) override;
virtual HRESULT STDMETHODCALLTYPE ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9 *pDestBuffer, IDirect3DVertexDeclaration9 *pVertexDecl, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexDeclaration(const D3DVERTEXELEMENT9 *pVertexElements, IDirect3DVertexDeclaration9 **ppDecl) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexDeclaration(IDirect3DVertexDeclaration9 *pDecl) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexDeclaration(IDirect3DVertexDeclaration9 **ppDecl) override;
virtual HRESULT STDMETHODCALLTYPE SetFVF(DWORD FVF) override;
virtual HRESULT STDMETHODCALLTYPE GetFVF(DWORD *pFVF) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexShader(const DWORD *pFunction, IDirect3DVertexShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShader(IDirect3DVertexShader9 *pShader) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShader(IDirect3DVertexShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantF(UINT StartRegister, const float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantI(UINT StartRegister, const int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantB(UINT StartRegister, const BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride) override;
virtual HRESULT STDMETHODCALLTYPE GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 **ppStreamData, UINT *OffsetInBytes, UINT *pStride) override;
virtual HRESULT STDMETHODCALLTYPE SetStreamSourceFreq(UINT StreamNumber, UINT Divider) override;
virtual HRESULT STDMETHODCALLTYPE GetStreamSourceFreq(UINT StreamNumber, UINT *Divider) override;
virtual HRESULT STDMETHODCALLTYPE SetIndices(IDirect3DIndexBuffer9 *pIndexData) override;
virtual HRESULT STDMETHODCALLTYPE GetIndices(IDirect3DIndexBuffer9 **ppIndexData) override;
virtual HRESULT STDMETHODCALLTYPE CreatePixelShader(const DWORD *pFunction, IDirect3DPixelShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShader(IDirect3DPixelShader9 *pShader) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShader(IDirect3DPixelShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantF(UINT StartRegister, const float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantI(UINT StartRegister, const int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantB(UINT StartRegister, const BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawRectPatch(UINT Handle, const float *pNumSegs, const D3DRECTPATCH_INFO *pRectPatchInfo) override;
virtual HRESULT STDMETHODCALLTYPE DrawTriPatch(UINT Handle, const float *pNumSegs, const D3DTRIPATCH_INFO *pTriPatchInfo) override;
virtual HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle) override;
virtual HRESULT STDMETHODCALLTYPE CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery) override;
#pragma endregion
#pragma region IDirect3DDevice9Ex
virtual HRESULT STDMETHODCALLTYPE SetConvolutionMonoKernel(UINT width, UINT height, float *rows, float *columns) override;
virtual HRESULT STDMETHODCALLTYPE ComposeRects(IDirect3DSurface9 *pSrc, IDirect3DSurface9 *pDst, IDirect3DVertexBuffer9 *pSrcRectDescs, UINT NumRects, IDirect3DVertexBuffer9 *pDstRectDescs, D3DCOMPOSERECTSOP Operation, int Xoffset, int Yoffset) override;
virtual HRESULT STDMETHODCALLTYPE PresentEx(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetGPUThreadPriority(INT *pPriority) override;
virtual HRESULT STDMETHODCALLTYPE SetGPUThreadPriority(INT Priority) override;
virtual HRESULT STDMETHODCALLTYPE WaitForVBlank(UINT iSwapChain) override;
virtual HRESULT STDMETHODCALLTYPE CheckResourceResidency(IDirect3DResource9 **pResourceArray, UINT32 NumResources) override;
virtual HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(UINT MaxLatency) override;
virtual HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(UINT *pMaxLatency) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceState(HWND hDestinationWindow) override;
virtual HRESULT STDMETHODCALLTYPE CreateRenderTargetEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE CreateOffscreenPlainSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE ResetEx(D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(UINT iSwapChain, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
HWND const hFocusWindow;
IDirect3DDevice9 *pReal;
bool is_d3d9ex = false;
std::atomic_ulong refs = 1;
WrappedIDirect3DSwapChain9 *main_swapchain = nullptr;
WrappedIDirect3DSwapChain9 *sub_swapchain = nullptr;
FakeIDirect3DSwapChain9 *fake_sub_swapchain = nullptr;
IDirect3DVertexShader9 *vertex_shader = nullptr;
};
@@ -0,0 +1,130 @@
#include "d3d9_fake_swapchain.h"
#include <cassert>
#include <mutex>
#include "util/logging.h"
#if 1
#define WRAP_VERBOSE log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::{}", __FUNCTION__)
#define WRAP_VERBOSE_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_VERBOSE
#define WRAP_VERBOSE_FMT(format, ...)
#endif
// IDirect3DSwapChain9
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IUnknown ||
riid == IID_IDirect3DSwapChain9 ||
riid == IID_IDirect3DSwapChain9Ex)
{
#pragma region Update to IDirect3DSwapChain9Ex interface
if (!is_d3d9ex && riid == IID_IDirect3DSwapChain9Ex) {
is_d3d9ex = true;
}
#pragma endregion
AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE FakeIDirect3DSwapChain9::AddRef(void) {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE FakeIDirect3DSwapChain9::Release(void) {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::Present(const RECT *pSourceRect, const RECT *pDestRect,
HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::Present");
});
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetFrontBufferData(IDirect3DSurface9 *pDestSurface) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type,
IDirect3DSurface9 **ppBackBuffer)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::GetBackBuffer");
});
if (iBackBuffer >= render_targets.size() || Type != D3DBACKBUFFER_TYPE_MONO || !ppBackBuffer) {
return D3DERR_INVALIDCALL;
}
auto &render_target = render_targets[iBackBuffer];
render_target->AddRef();
*ppBackBuffer = render_target;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDisplayMode(D3DDISPLAYMODE *pMode) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDevice(IDirect3DDevice9 **ppDevice) {
WRAP_VERBOSE;
if (ppDevice == nullptr) {
return D3DERR_INVALIDCALL;
}
pDev->AddRef();
*ppDevice = pDev;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetPresentParameters(
D3DPRESENT_PARAMETERS *pPresentationParameters)
{
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
// IDirect3DSwapChain9Ex
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetLastPresentCount(UINT *pLastPresentCount) {
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) {
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDisplayModeEx(D3DDISPLAYMODEEX *pMode,
D3DDISPLAYROTATION *pRotation)
{
WRAP_VERBOSE;
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
@@ -0,0 +1,86 @@
#pragma once
// this file uses the C++ interface of Direct3D9
#ifdef CINTERFACE
#undef CINTERFACE
#endif
#include <atomic>
#include <d3d9.h>
#include "util/logging.h"
struct FakeIDirect3DSwapChain9 : IDirect3DSwapChain9Ex {
FakeIDirect3DSwapChain9(IDirect3DDevice9 *pDev, D3DPRESENT_PARAMETERS *present_params, bool is_d3d9ex) :
pDev(pDev), is_d3d9ex(is_d3d9ex)
{
// copy presentation parameters
memcpy(&this->present_params, present_params, sizeof(this->present_params));
// From MSDN https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dpresent-parameters:
// Values of 0 are treated as 1
if (this->present_params.BackBufferCount == 0) {
this->present_params.BackBufferCount = 1;
}
for (size_t i = 0; i < this->present_params.BackBufferCount; i++) {
IDirect3DSurface9 *render_target = nullptr;
HRESULT hr = pDev->CreateRenderTarget(
this->present_params.BackBufferWidth,
this->present_params.BackBufferHeight,
this->present_params.BackBufferFormat,
this->present_params.MultiSampleType,
this->present_params.MultiSampleQuality,
FALSE,
&render_target,
nullptr
);
if (SUCCEEDED(hr)) {
this->render_targets.push_back(render_target);
} else {
log_warning("graphics::d3d9", "failed to create backing render target for fake swap chain, hr={}",
FMT_HRESULT(hr));
}
}
}
FakeIDirect3DSwapChain9(const FakeIDirect3DSwapChain9 &) = delete;
FakeIDirect3DSwapChain9 &operator=(const FakeIDirect3DSwapChain9 &) = delete;
virtual ~FakeIDirect3DSwapChain9(void) {
for (auto &render_target : this->render_targets) {
render_target->Release();
}
}
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DSwapChain9
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
#pragma endregion
#pragma region IDirect3DSwapChain9Ex
virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
IDirect3DDevice9 *const pDev;
bool is_d3d9ex;
std::atomic<ULONG> ref_cnt = 1;
D3DPRESENT_PARAMETERS present_params {};
std::vector<IDirect3DSurface9 *> render_targets;
};
@@ -0,0 +1,141 @@
#include "d3d9_swapchain.h"
#include <cassert>
#include <mutex>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "d3d9_backend.h"
#include "d3d9_device.h"
// std::min
#ifdef min
#undef min
#endif
#define CHECK_RESULT(x) \
HRESULT ret = (x); \
if (GRAPHICS_LOG_HRESULT && FAILED(ret)) [[unlikely]] { \
log_warning("graphics::d3d9", "{} failed, hr={}", __FUNCTION__, FMT_HRESULT(ret)); \
} \
return ret
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (//riid == __uuidof(IUnknown) || Ignore IUnknown, it's often queried to test object equality between different interfaces
riid == IID_IDirect3DSwapChain9 ||
riid == IID_IDirect3DSwapChain9Ex)
{
#pragma region Update to IDirect3DSwapChain9Ex interface
if (!is_d3d9ex && riid == IID_IDirect3DSwapChain9Ex) {
IDirect3DSwapChain9Ex *swapchainex = nullptr;
if (FAILED(pReal->QueryInterface(IID_PPV_ARGS(&swapchainex)))) {
return E_NOINTERFACE;
}
pReal->Release();
pReal = swapchainex;
is_d3d9ex = true;
}
#pragma endregion
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::AddRef(void) {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::Release(void) {
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
// Metal Gear Arcade expects the swap chain to only have one reference. The parent
// `WrappedIDirect3DDevice9` holds a strong reference to this swap chain which means
// the reference count will be above one. Workaround this by returning a maximum of one.
if (avs::game::is_model("I36")) {
return std::min(refs, 1lu);
}
return refs;
}
/*
* IDirect3DSwapChain9
*/
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::Present(const RECT *pSourceRect, const RECT *pDestRect,
HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "WrappedIDirect3DSwapChain9::Present");
});
if (should_run_hooks) {
graphics_d3d9_on_present(pDev->hFocusWindow, pDev->pReal, pDev);
}
CHECK_RESULT(pReal->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetFrontBufferData(IDirect3DSurface9 *pDestSurface) {
CHECK_RESULT(pReal->GetFrontBufferData(pDestSurface));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type,
IDirect3DSurface9 **ppBackBuffer)
{
CHECK_RESULT(pReal->GetBackBuffer(iBackBuffer, Type, ppBackBuffer));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) {
CHECK_RESULT(pReal->GetRasterStatus(pRasterStatus));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDisplayMode(D3DDISPLAYMODE *pMode) {
CHECK_RESULT(pReal->GetDisplayMode(pMode));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDevice(IDirect3DDevice9 **ppDevice) {
if (ppDevice == nullptr) {
return D3DERR_INVALIDCALL;
}
pDev->AddRef();
*ppDevice = pDev;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetPresentParameters(
D3DPRESENT_PARAMETERS *pPresentationParameters)
{
CHECK_RESULT(pReal->GetPresentParameters(pPresentationParameters));
}
/*
* IDirect3DSwapChain9Ex
*/
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetLastPresentCount(UINT *pLastPresentCount) {
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetLastPresentCount(pLastPresentCount));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) {
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetPresentStats(pPresentationStatistics));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDisplayModeEx(D3DDISPLAYMODEEX *pMode,
D3DDISPLAYROTATION *pRotation)
{
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetDisplayModeEx(pMode, pRotation));
}
@@ -0,0 +1,58 @@
#pragma once
#include <d3d9.h>
interface WrappedIDirect3DDevice9;
struct WrappedIDirect3DSwapChain9 : IDirect3DSwapChain9Ex {
WrappedIDirect3DSwapChain9(WrappedIDirect3DDevice9 *dev, IDirect3DSwapChain9 *orig) :
pDev(dev), pReal(orig), is_d3d9ex(false)
{
IDirect3DSwapChain9Ex *swapchain = nullptr;
// attempt to upgrade handle
if (SUCCEEDED(this->QueryInterface(IID_PPV_ARGS(&swapchain))) && swapchain != nullptr) {
swapchain->Release();
}
}
WrappedIDirect3DSwapChain9(WrappedIDirect3DDevice9 *dev, IDirect3DSwapChain9Ex *orig) :
pDev(dev), pReal(orig), is_d3d9ex(true)
{
}
virtual ~WrappedIDirect3DSwapChain9(void) {
}
WrappedIDirect3DSwapChain9(const WrappedIDirect3DSwapChain9 &) = delete;
WrappedIDirect3DSwapChain9 &operator=(const WrappedIDirect3DSwapChain9 &) = delete;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DSwapChain9
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
#pragma endregion
#pragma region IDirect3DSwapChain9Ex
virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
WrappedIDirect3DDevice9 *const pDev;
IDirect3DSwapChain9 *pReal;
bool is_d3d9ex = false;
bool should_run_hooks = true;
};
@@ -0,0 +1,127 @@
#include "d3d9_texture.h"
#include "hooks/graphics/graphics.h"
#include "util/logging.h"
#include "util/utils.h"
#if 0
#define WRAP_DEBUG log_misc("graphics::d3d9::texture", "{}", __FUNCTION__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("graphics::d3d9::texture", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
#define CHECK_RESULT(x) \
HRESULT ret = (x); \
if (GRAPHICS_LOG_HRESULT && FAILED(ret)) [[unlikely]] { \
log_warning("graphics::d3d9::texture", "{} failed, hr={}", __FUNCTION__, FMT_HRESULT(ret)); \
} \
return ret;
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::QueryInterface(REFIID riid, void **ppvObj) {
#ifndef __GNUC__
// fast path without incrementing the reference count for texture updates
if (riid == IID_WrappedIDirect3DTexture9) {
return S_OK;
}
#endif
if (ppvObj == nullptr) {
return E_POINTER;
}
if (/* riid == IID_IUnknown || */
riid == IID_IDirect3DResource9 ||
riid == IID_IDirect3DBaseTexture9 ||
riid == IID_IDirect3DTexture9)
{
this->AddRef();
*ppvObj = this;
log_info("graphics::d3d9::texture", "WrappedIDirect3DTexture9::QueryInterface({})", guid2s(riid));
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DTexture9::AddRef(void) {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DTexture9::Release(void) {
ULONG refs = (pReal != nullptr) ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IDirect3DResource9 methods
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetDevice(IDirect3DDevice9 **ppDevice) {
CHECK_RESULT(pReal->GetDevice(ppDevice));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetPrivateData(REFGUID refguid, const void *pData, DWORD SizeOfData,
DWORD Flags)
{
CHECK_RESULT(pReal->SetPrivateData(refguid, pData, SizeOfData, Flags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetPrivateData(REFGUID refguid, void *pData, DWORD* pSizeOfData) {
CHECK_RESULT(pReal->GetPrivateData(refguid, pData, pSizeOfData));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::FreePrivateData(REFGUID refguid) {
CHECK_RESULT(pReal->FreePrivateData(refguid));
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetPriority(DWORD PriorityNew) {
return pReal->SetPriority(PriorityNew);
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetPriority(void) {
return pReal->GetPriority();
}
void STDMETHODCALLTYPE WrappedIDirect3DTexture9::PreLoad(void) {
return pReal->PreLoad();
}
D3DRESOURCETYPE STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetType(void) {
return pReal->GetType();
}
// IDirect3DBaseTexture9 methods
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetLOD(DWORD LODNew) {
return pReal->SetLOD(LODNew);
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLOD(void) {
return pReal->GetLOD();
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLevelCount(void) {
return pReal->GetLevelCount();
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) {
CHECK_RESULT(pReal->SetAutoGenFilterType(FilterType));
}
D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetAutoGenFilterType(void) {
return pReal->GetAutoGenFilterType();
}
void STDMETHODCALLTYPE WrappedIDirect3DTexture9::GenerateMipSubLevels(void) {
return pReal->GenerateMipSubLevels();
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) {
CHECK_RESULT(pReal->GetLevelDesc(Level, pDesc));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetSurfaceLevel(UINT Level, IDirect3DSurface9 **ppSurfaceLevel) {
CHECK_RESULT(pReal->GetSurfaceLevel(Level, ppSurfaceLevel));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::LockRect(UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) {
WRAP_DEBUG_FMT("LockRect({}, {}, {}, 0x{:x})", Level, fmt::ptr(pLockedRect), fmt::ptr(pRect), Flags);
CHECK_RESULT(pReal->LockRect(Level, pLockedRect, pRect, Flags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::UnlockRect(UINT Level) {
CHECK_RESULT(pReal->UnlockRect(Level));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::AddDirtyRect(const RECT *pDirtyRect) {
CHECK_RESULT(pReal->AddDirtyRect(pDirtyRect));
}
@@ -0,0 +1,58 @@
#pragma once
#include <d3d9.h>
#include "util/logging.h"
// {22E9B203-6506-4BC5-B304-A48F3001630F}
static const GUID IID_WrappedIDirect3DTexture9 = {
0x22e9b203, 0x6506, 0x4bc5, { 0xb3, 0x04, 0xa4, 0x8f, 0x30, 0x01, 0x63, 0x0f }
};
struct WrappedIDirect3DTexture9 : IDirect3DTexture9 {
explicit WrappedIDirect3DTexture9(IDirect3DDevice9 *dev, IDirect3DTexture9 *orig) : pDev(dev), pReal(orig) {
log_misc("graphics::d3d9::texture", "Creating texture wrapper around {} => {}", fmt::ptr(orig), fmt::ptr(this));
}
WrappedIDirect3DTexture9(const WrappedIDirect3DTexture9 &) = delete;
WrappedIDirect3DTexture9 &operator=(const WrappedIDirect3DTexture9 &) = delete;
virtual ~WrappedIDirect3DTexture9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DResource9
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID refguid, void *pData, DWORD* pSizeOfData) override;
virtual HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) override;
virtual DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) override;
virtual DWORD STDMETHODCALLTYPE GetPriority(void) override;
virtual void STDMETHODCALLTYPE PreLoad(void) override;
virtual D3DRESOURCETYPE STDMETHODCALLTYPE GetType(void) override;
#pragma endregion
#pragma region IDirect3DBaseTexture9
virtual DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) override;
virtual DWORD STDMETHODCALLTYPE GetLOD(void) override;
virtual DWORD STDMETHODCALLTYPE GetLevelCount(void) override;
virtual HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) override;
virtual D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType(void) override;
virtual void STDMETHODCALLTYPE GenerateMipSubLevels(void) override;
#pragma endregion
#pragma region IDirect3DTexture9
virtual HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) override;
virtual HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface9 **ppSurfaceLevel) override;
virtual HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level) override;
virtual HRESULT STDMETHODCALLTYPE AddDirtyRect(const RECT *pDirtyRect) override;
#pragma endregion
IDirect3DDevice9 *const pDev;
IDirect3DTexture9 *const pReal;
};
@@ -0,0 +1,111 @@
#if 0
//
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
//
// Parameters:
//
// float4 ColorMultiply;
// float2 ConstantHalfTexelFixupOffset;
// float4x4 WorldViewProjection;
//
//
// Registers:
//
// Name Reg Size
// ---------------------------- ----- ----
// WorldViewProjection c0 4
// ColorMultiply c4 1
// ConstantHalfTexelFixupOffset c63 1
//
vs_1_1
dcl_position v0
dcl_color v1
dcl_texcoord v2
dp4 oPos.z, v0, c2
mul oD0, v1, c4
dp4 r0.x, v0, c0
dp4 r0.y, v0, c1
dp4 r0.z, v0, c3
mad oPos.xy, c63, r0.z, r0
mov oPos.w, r0.z
mov oT0.xy, v2
// approximately 8 instruction slots used
#endif
const BYTE g_vs11_vs_main[] =
{
1, 1, 254, 255, 254, 255,
64, 0, 67, 84, 65, 66,
28, 0, 0, 0, 211, 0,
0, 0, 1, 1, 254, 255,
3, 0, 0, 0, 28, 0,
0, 0, 0, 1, 0, 0,
204, 0, 0, 0, 88, 0,
0, 0, 2, 0, 4, 0,
1, 0, 18, 0, 104, 0,
0, 0, 0, 0, 0, 0,
120, 0, 0, 0, 2, 0,
63, 0, 1, 0, 254, 0,
152, 0, 0, 0, 0, 0,
0, 0, 168, 0, 0, 0,
2, 0, 0, 0, 4, 0,
2, 0, 188, 0, 0, 0,
0, 0, 0, 0, 67, 111,
108, 111, 114, 77, 117, 108,
116, 105, 112, 108, 121, 0,
171, 171, 1, 0, 3, 0,
1, 0, 4, 0, 1, 0,
0, 0, 0, 0, 0, 0,
67, 111, 110, 115, 116, 97,
110, 116, 72, 97, 108, 102,
84, 101, 120, 101, 108, 70,
105, 120, 117, 112, 79, 102,
102, 115, 101, 116, 0, 171,
171, 171, 1, 0, 3, 0,
1, 0, 2, 0, 1, 0,
0, 0, 0, 0, 0, 0,
87, 111, 114, 108, 100, 86,
105, 101, 119, 80, 114, 111,
106, 101, 99, 116, 105, 111,
110, 0, 3, 0, 3, 0,
4, 0, 4, 0, 1, 0,
0, 0, 0, 0, 0, 0,
118, 115, 95, 49, 95, 49,
0, 77, 105, 99, 114, 111,
115, 111, 102, 116, 32, 40,
82, 41, 32, 72, 76, 83,
76, 32, 83, 104, 97, 100,
101, 114, 32, 67, 111, 109,
112, 105, 108, 101, 114, 32,
49, 48, 46, 49, 0, 171,
31, 0, 0, 0, 0, 0,
0, 128, 0, 0, 15, 144,
31, 0, 0, 0, 10, 0,
0, 128, 1, 0, 15, 144,
31, 0, 0, 0, 5, 0,
0, 128, 2, 0, 15, 144,
9, 0, 0, 0, 0, 0,
4, 192, 0, 0, 228, 144,
2, 0, 228, 160, 5, 0,
0, 0, 0, 0, 15, 208,
1, 0, 228, 144, 4, 0,
228, 160, 9, 0, 0, 0,
0, 0, 1, 128, 0, 0,
228, 144, 0, 0, 228, 160,
9, 0, 0, 0, 0, 0,
2, 128, 0, 0, 228, 144,
1, 0, 228, 160, 9, 0,
0, 0, 0, 0, 4, 128,
0, 0, 228, 144, 3, 0,
228, 160, 4, 0, 0, 0,
0, 0, 3, 192, 63, 0,
228, 160, 0, 0, 170, 128,
0, 0, 228, 128, 1, 0,
0, 0, 0, 0, 8, 192,
0, 0, 170, 128, 1, 0,
0, 0, 0, 0, 3, 224,
2, 0, 228, 144, 255, 255,
0, 0
};
@@ -0,0 +1,40 @@
/*
* original source
* vs.1.1 //Shader version 1.1
* dcl_position v0;
* dcl_color v1;
* dcl_texcoord0 v2;
* m4x4 oPos, v0, c0
* mul oD0, v1, c4
* mov oT0.xy, v2
*
* build command
* fxc.exe /Vi vertex-shader.hlsl /Fh vertex-shader.h /T vs_1_1 /E vs_main
*/
float4x4 WorldViewProjection : register(c0);
float4 ColorMultiply : register(c4);
float2 ConstantHalfTexelFixupOffset : register(c63);
struct VS {
float4 Position : POSITION; // dcl_position v0;
float4 Color : COLOR; // dcl_color v1;
float2 TexCoord : TEXCOORD0; // dcl_texcoord0 v2;
};
VS vs_main(VS input)
{
VS output;
output.Position = mul(input.Position, WorldViewProjection); // m4x4 oPos, v0, c0
output.Color.x = mul(input.Color.x, ColorMultiply.x); // mul oD0, v1, c4
output.Color.y = mul(input.Color.y, ColorMultiply.y);
output.Color.z = mul(input.Color.z, ColorMultiply.z);
output.Color.w = mul(input.Color.w, ColorMultiply.w);
output.TexCoord = input.TexCoord; // mov oT0.xy, v2
// fix texture position
output.Position.xy += ConstantHalfTexelFixupOffset.xy * output.Position.w;
return output;
}
+870
View File
@@ -0,0 +1,870 @@
#include <initguid.h>
#include "graphics.h"
#include <set>
#include <vector>
#include <mutex>
#include <condition_variable>
#include "avs/game.h"
#include "cfg/icon.h"
#include "cfg/screen_resize.h"
#include "hooks/graphics/backends/d3d9/d3d9_backend.h"
#include "launcher/shutdown.h"
#include "overlay/overlay.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/fileutils.h"
#include "util/utils.h"
#include "util/time.h"
struct CaptureData {
std::shared_ptr<uint8_t[]> data;
unsigned short width, height;
uint64_t timestamp;
};
// icon
static HICON WINDOW_ICON = LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(MAINICON));
// state
static WNDPROC WNDPROC_ORIG = nullptr;
static std::vector<WNDPROC> WNDPROC_CUSTOM {};
static bool GRAPHICS_SCREENSHOT_TRIGGER = false;
static std::set<int> GRAPHICS_SCREENS { 0 };
static std::mutex GRAPHICS_SCREENS_M {};
static std::vector<int> GRAPHICS_CAPTURE_SCREENS;
static const size_t GRAPHICS_CAPTURE_SCREEN_NO = 4;
static std::mutex GRAPHICS_CAPTURE_SCREENS_M {};
static CaptureData GRAPHICS_CAPTURE_BUFFER[GRAPHICS_CAPTURE_SCREEN_NO] {};
static std::mutex GRAPHICS_CAPTURE_BUFFER_M[GRAPHICS_CAPTURE_SCREEN_NO] {};
static std::condition_variable GRAPHICS_CAPTURE_CV[GRAPHICS_CAPTURE_SCREEN_NO] {};
// flag settings
bool GRAPHICS_CAPTURE_CURSOR = false;
bool GRAPHICS_LOG_HRESULT = false;
bool GRAPHICS_SDVX_FORCE_720 = false;
bool GRAPHICS_SHOW_CURSOR = false;
bool GRAPHICS_WINDOWED = false;
bool GRAPHICS_ADJUST_ORIENTATION = false;
std::vector<HWND> GRAPHICS_WINDOWS;
UINT GRAPHICS_FORCE_REFRESH = 0;
bool GRAPHICS_FORCE_SINGLE_ADAPTER = false;
bool GRAPHICS_9_ON_12 = false;
// settings
std::string GRAPHICS_DEVICEID = "PCI\\VEN_1002&DEV_7146";
std::string GRAPHICS_SCREENSHOT_DIR = ".\\screenshots";
static decltype(ChangeDisplaySettingsA) *ChangeDisplaySettingsA_orig = nullptr;
static decltype(ChangeDisplaySettingsExA) *ChangeDisplaySettingsExA_orig = nullptr;
static decltype(ClipCursor) *ClipCursor_orig = nullptr;
static decltype(CreateWindowExA) *CreateWindowExA_orig = nullptr;
static decltype(CreateWindowExW) *CreateWindowExW_orig = nullptr;
static decltype(EnableWindow) *EnableWindow_orig = nullptr;
static decltype(EnumDisplayDevicesA) *EnumDisplayDevicesA_orig = nullptr;
static decltype(MoveWindow) *MoveWindow_orig = nullptr;
static decltype(PeekMessageA) *PeekMessageA_orig = nullptr;
static decltype(RegisterClassA) *RegisterClassA_orig = nullptr;
static decltype(RegisterClassExA) *RegisterClassExA_orig = nullptr;
static decltype(RegisterClassW) *RegisterClassW_orig = nullptr;
static decltype(RegisterClassExW) *RegisterClassExW_orig = nullptr;
static decltype(ShowCursor) *ShowCursor_orig = nullptr;
static decltype(SetCursor) *SetCursor_orig = nullptr;
static decltype(SetWindowLongA) *SetWindowLongA_orig = nullptr;
static decltype(SetWindowLongW) *SetWindowLongW_orig = nullptr;
static decltype(SetWindowPos) *SetWindowPos_orig = nullptr;
static void reset_window_hook(HWND hWnd) {
overlay::destroy(hWnd);
if (WNDPROC_ORIG) {
SetWindowLongPtrA(hWnd, GWLP_WNDPROC, (LONG_PTR) WNDPROC_ORIG);
WNDPROC_ORIG = nullptr;
}
}
// window procedure
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// terminate
if (uMsg == WM_CLOSE) {
log_info("graphics", "detected WM_CLOSE, terminating...");
launcher::shutdown(0);
return false;
}
// overlay specific
if (overlay::OVERLAY) {
switch (uMsg) {
case WM_CHAR: {
// input characters if overlay is active
if (overlay::OVERLAY->has_focus()) {
overlay::OVERLAY->input_char((unsigned int) wParam);
return true;
}
break;
}
case WM_DESTROY: {
auto wndproc = WNDPROC_ORIG;
reset_window_hook(hWnd);
return CallWindowProcA(wndproc, hWnd, uMsg, wParam, lParam);
}
case WM_SETCURSOR: {
// set cursor back to the overlay one
if (LOWORD(lParam) == HTCLIENT && overlay::OVERLAY->update_cursor()) {
return true;
}
break;
}
default:
break;
}
}
// call custom procedures
for (WNDPROC wndProc : WNDPROC_CUSTOM) {
wndProc(hWnd, uMsg, wParam, lParam);
}
// capture mouse
if (GRAPHICS_CAPTURE_CURSOR) {
switch (uMsg) {
case WM_SETFOCUS: {
// capture mouse
RECT WINDOW_RECT;
GetWindowRect(hWnd, &WINDOW_RECT);
ClipCursor(&WINDOW_RECT);
return true;
}
case WM_KILLFOCUS: {
// free mouse
ClipCursor(0);
return true;
}
default:
break;
}
}
// drop keydown messages
switch (uMsg) {
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
return true;
default:
break;
}
// update the size of an emulated touch window is the window changes size or moves
if (SPICETOUCH_TOUCH_HWND) {
switch (uMsg) {
case WM_MOVE:
case WM_SIZE: {
// get window rect
RECT windowRect {};
GetWindowRect(hWnd, &windowRect);
// adjust to client area
POINT p {};
ClientToScreen(hWnd, &p);
windowRect.top = p.y;
int new_x = windowRect.left;
int new_y = windowRect.top;
int new_width = windowRect.right - new_x;
int new_height = windowRect.bottom - new_y;
log_misc("graphics", "detected window change ({}x{} @ {}, {} -> {}x{} @ {}, {}), updating touch window to match",
SPICETOUCH_TOUCH_WIDTH, SPICETOUCH_TOUCH_HEIGHT, SPICETOUCH_TOUCH_X, SPICETOUCH_TOUCH_Y,
new_width, new_height, new_x, new_y);
SPICETOUCH_TOUCH_X = new_x;
SPICETOUCH_TOUCH_Y = new_y;
SPICETOUCH_TOUCH_WIDTH = new_width;
SPICETOUCH_TOUCH_HEIGHT = new_height;
SetWindowPos(SPICETOUCH_TOUCH_HWND, HWND_TOP,
new_x, new_y,
new_width, new_height,
SWP_NOZORDER | SWP_NOREDRAW | SWP_NOREPOSITION | SWP_NOACTIVATE);
}
default:
break;
}
}
// call default
return CallWindowProcA(WNDPROC_ORIG, hWnd, uMsg, wParam, lParam);
}
static LONG WINAPI ChangeDisplaySettingsA_hook(DEVMODEA *lpDevMode, DWORD dwflags) {
log_misc("graphics", "ChangeDisplaySettingsA hook hit");
// ignore display settings changes when running windowed
if (GRAPHICS_WINDOWED) {
return DISP_CHANGE_SUCCESSFUL;
}
// call original
return ChangeDisplaySettingsA_orig(lpDevMode, dwflags);
}
static LONG WINAPI ChangeDisplaySettingsExA_hook(LPCSTR lpszDeviceName, DEVMODEA *lpDevMode, HWND hwnd,
DWORD dwflags, LPVOID lParam)
{
log_misc("graphics", "ChangeDisplaySettingsExA hook hit");
// ignore display settings changes when running windowed
if (GRAPHICS_WINDOWED) {
return DISP_CHANGE_SUCCESSFUL;
}
// call original
return ChangeDisplaySettingsExA_orig(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
}
static BOOL WINAPI ClipCursor_hook(const RECT *lpRect) {
log_misc("graphics", "ClipCursor hook hit");
// ignore cursor confine when having no explicit cursor confine
if (!GRAPHICS_CAPTURE_CURSOR) {
return TRUE;
}
// call original
return ClipCursor_orig(lpRect);
}
static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName,
DWORD dwStyle, int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
LPVOID lpParam)
{
log_misc("graphics", "CreateWindowExA hook hit (0x{:08x}, {}, {}, 0x{:08x}, {}, {}, {}, {}, {}, {}, {}, {})",
dwExStyle,
fmt::ptr(lpClassName),
lpWindowName != nullptr ? lpWindowName : "(null)",
dwStyle,
x,
y,
nWidth,
nHeight,
fmt::ptr(hWndParent),
fmt::ptr(hMenu),
fmt::ptr(hInstance),
fmt::ptr(lpParam));
// set display orientation
if (GRAPHICS_ADJUST_ORIENTATION) {
if (nHeight > nWidth) {
DEVMODE mode {};
// get display settings
if (EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &mode)) {
log_misc("graphics", "rotating display");
mode.dmPelsWidth = nWidth;
mode.dmPelsHeight = nHeight;
mode.dmDisplayOrientation = DMDO_90;
auto disp_res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
if (disp_res != DISP_CHANGE_SUCCESSFUL) {
log_warning("graphics", "failed to change display settings: {}", disp_res);
}
} else {
log_warning("graphics", "failed to get display settings");
}
}
}
// call original
HWND result = CreateWindowExA_orig(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight,
hWndParent, hMenu, hInstance, lpParam);
GRAPHICS_WINDOWS.push_back(result);
return result;
}
static HWND WINAPI CreateWindowExW_hook(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName,
DWORD dwStyle, int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
LPVOID lpParam)
{
log_misc("graphics", "CreateWindowExW hook hit ({:x}, {}, {}, {:x}, {}, {}, {}, {}, {}, {}, {}, {})",
dwExStyle,
fmt::ptr(lpClassName),
lpWindowName != nullptr ? ws2s(lpWindowName) : "(null)",
dwStyle,
x,
y,
nWidth,
nHeight,
fmt::ptr(hWndParent),
fmt::ptr(hMenu),
fmt::ptr(hInstance),
fmt::ptr(lpParam));
// DDR specific stuff
if (avs::game::is_model("MDX")) {
// set window name
if (!lpWindowName) {
lpWindowName = L"Dance Dance Revolution";
}
// windowed mode adjustments
if (GRAPHICS_WINDOWED) {
// change window style
dwExStyle = 0;
dwStyle |= WS_OVERLAPPEDWINDOW;
// adjust window size to include window decoration
RECT rect {};
SetRect(&rect, 0, 0, 1280, 720);
AdjustWindowRect(&rect, dwStyle, (hMenu != nullptr));
nWidth = rect.right - rect.left;
nHeight = rect.bottom - rect.top;
}
}
// DanEvo specific stuff
if (avs::game::is_model("KDM")) {
// set window name
if (!lpWindowName) {
lpWindowName = L"Dance Evolution";
}
}
// call original
HWND result = CreateWindowExW_orig(
dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight,
hWndParent, hMenu, hInstance, lpParam);
GRAPHICS_WINDOWS.push_back(result);
return result;
}
static BOOL WINAPI EnableWindow_hook(HWND hWnd, BOOL bEnable) {
return TRUE;
}
static BOOL WINAPI EnumDisplayDevicesA_hook(LPCTSTR lpDevice, DWORD iDevNum,
PDISPLAY_DEVICE lpDisplayDevice, DWORD dwFlags) {
// call original
BOOL value = EnumDisplayDevicesA_orig(lpDevice, iDevNum, lpDisplayDevice, dwFlags);
// device ID override
if (value) {
memcpy(&lpDisplayDevice->DeviceID, GRAPHICS_DEVICEID.c_str(), GRAPHICS_DEVICEID.size() + 1);
}
// return original result
return value;
}
static BOOL WINAPI MoveWindow_hook(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint) {
log_misc("graphics", "MoveWindow hook hit ({}, {}, {}, {}, {}, {})",
fmt::ptr(hWnd),
X,
Y,
nWidth,
nHeight,
bRepaint);
// sound voltex windowed mode adjustments
if (GRAPHICS_WINDOWED && GRAPHICS_SDVX_FORCE_720 && avs::game::is_model("KFC")) {
RECT rect {};
DWORD dwStyle;
dwStyle = GetWindowLongA(hWnd, GWL_STYLE);
// luckily, SDVX does not draw a menu. So we can leave the last
// argument to `AdjustWindowRect` as `0`.
SetRect(&rect, 0, 0, 720, 1280);
AdjustWindowRect(&rect, dwStyle, 0);
nWidth = rect.right - rect.left;
nHeight = rect.bottom - rect.top;
}
// call original
return MoveWindow_orig(hWnd, X, Y, nWidth, nHeight, bRepaint);
}
static BOOL WINAPI PeekMessageA_hook(
LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg) {
// SDVX polls for messages too slowly
if (avs::game::is_model("KFC")) {
// process remaining messages
BOOL ret;
while ((ret = PeekMessageA_orig(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, PM_REMOVE)) != 0) {
if (ret == -1) {
return ret;
} else {
TranslateMessage(lpMsg);
DispatchMessageA(lpMsg);
}
}
// return no message
return FALSE;
}
return PeekMessageA_orig(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
}
static int WINAPI ShowCursor_hook(BOOL bShow) {
// prevent game from hiding cursor when option is enabled
if (GRAPHICS_SHOW_CURSOR && !bShow) {
return 1;
}
// call original
return ShowCursor_orig(bShow);
}
static HCURSOR WINAPI SetCursor_hook(HCURSOR hCursor) {
if (GRAPHICS_SHOW_CURSOR && hCursor == NULL) {
return GetCursor();
}
return SetCursor_orig(hCursor);
}
static LONG WINAPI SetWindowLongA_hook(HWND hWnd, int nIndex, LONG dwNewLong) {
// DDR window style fix
if (nIndex == GWL_STYLE && avs::game::is_model("MDX")) {
dwNewLong |= WS_OVERLAPPEDWINDOW;
}
// call original
return SetWindowLongA_orig(hWnd, nIndex, dwNewLong);
}
static LONG WINAPI SetWindowLongW_hook(HWND hWnd, int nIndex, LONG dwNewLong) {
// DDR overlapped window fix
if (nIndex == GWL_STYLE && avs::game::is_model("MDX")) {
dwNewLong |= WS_OVERLAPPEDWINDOW;
}
// call original
return SetWindowLongW_orig(hWnd, nIndex, dwNewLong);
}
static BOOL WINAPI SetWindowPos_hook(HWND hWnd, HWND hWndInsertAfter,
int X, int Y, int cx, int cy, UINT uFlags) {
// windowed mode adjustments
if (GRAPHICS_WINDOWED && (avs::game::is_model("LMA") || avs::game::is_model("MDX"))) {
return TRUE;
}
// call original
return SetWindowPos_orig(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
}
static ATOM WINAPI RegisterClassA_hook(const WNDCLASSA *lpWndClass) {
// check for null
if (!lpWndClass) {
return RegisterClassA_orig(lpWndClass);
}
// copy struct and use own icon
WNDCLASSA wnd = *lpWndClass;
wnd.hIcon = WINDOW_ICON;
// call original
return RegisterClassA_orig(&wnd);
}
static ATOM WINAPI RegisterClassExA_hook(const WNDCLASSEXA *Arg1) {
// check for null
if (!Arg1) {
return RegisterClassExA_orig(Arg1);
}
// copy struct and use own icon
WNDCLASSEXA wnd = *Arg1;
wnd.hIcon = WINDOW_ICON;
wnd.hIconSm = WINDOW_ICON;
// call original
return RegisterClassExA_orig(&wnd);
}
static ATOM WINAPI RegisterClassW_hook(const WNDCLASSW *lpWndClass) {
// check for null
if (!lpWndClass) {
return RegisterClassW_orig(lpWndClass);
}
// copy struct and use own icon
WNDCLASSW wnd = *lpWndClass;
wnd.hIcon = WINDOW_ICON;
// call original
return RegisterClassW_orig(&wnd);
}
static ATOM WINAPI RegisterClassExW_hook(const WNDCLASSEXW *Arg1) {
// check for null
if (!Arg1) {
return RegisterClassExW_orig(Arg1);
}
// copy struct and use own icon
WNDCLASSEXW wnd = *Arg1;
wnd.hIcon = WINDOW_ICON;
wnd.hIconSm = WINDOW_ICON;
// call original
return RegisterClassExW_orig(&wnd);
}
static HHOOK WINAPI SetWindowsHookExA_hook(int, HOOKPROC, HINSTANCE, DWORD) {
log_misc("graphics", "SetWindowsHookExA hook hit");
// we don't do hooks
return nullptr;
}
static BOOL WINAPI SetCursorPos_hook(int, int) {
// prevent games from messing with the cursor position themselves
return TRUE;
}
static int WINAPI MessageBoxA_hook(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
auto text = lpText != nullptr ? lpText : "(null)";
auto title = lpCaption != nullptr ? lpCaption : "(null)";
log_info("graphics", "MessageBoxA: {} - {}", title, text);
return IDOK;
}
static int WINAPI MessageBoxExA_hook(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId) {
auto text = lpText != nullptr ? lpText : "(null)";
auto title = lpCaption != nullptr ? lpCaption : "(null)";
log_info("graphics", "MessageBoxExA: {} - {}", title, text);
return IDOK;
}
static int WINAPI MessageBoxW_hook(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) {
auto text = lpText != nullptr ? lpText : L"(null)";
auto title = lpCaption != nullptr ? lpCaption : L"(null)";
log_info("graphics", "MessageBoxW: {} - {}", ws2s(title), ws2s(text));
return IDOK;
}
static int WINAPI MessageBoxExW_hook(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId) {
auto text = lpText != nullptr ? lpText : L"(null)";
auto title = lpCaption != nullptr ? lpCaption : L"(null)";
log_info("graphics", "MessageBoxExW: {} - {}", ws2s(title), ws2s(text));
return IDOK;
}
void graphics_init() {
log_info("graphics", "initializing");
// init screen resize
log_info("ScreenResize", "initializing");
if(cfg::SCREENRESIZE == nullptr){
cfg::SCREENRESIZE = std::make_unique<cfg::ScreenResize>();
}
// init backends
graphics_d3d9_init();
// general hooks
ChangeDisplaySettingsA_orig = detour::iat_try("ChangeDisplaySettingsA", ChangeDisplaySettingsA_hook);
ChangeDisplaySettingsExA_orig = detour::iat_try("ChangeDisplaySettingsExA", ChangeDisplaySettingsExA_hook);
ClipCursor_orig = detour::iat_try("ClipCursor", ClipCursor_hook);
CreateWindowExA_orig = detour::iat_try("CreateWindowExA", CreateWindowExA_hook);
CreateWindowExW_orig = detour::iat_try("CreateWindowExW", CreateWindowExW_hook);
EnableWindow_orig = detour::iat_try("EnableWindow", EnableWindow_hook);
EnumDisplayDevicesA_orig = detour::iat_try("EnumDisplayDevicesA", EnumDisplayDevicesA_hook);
MoveWindow_orig = detour::iat_try("MoveWindow", MoveWindow_hook);
PeekMessageA_orig = detour::iat_try("PeekMessageA", PeekMessageA_hook);
RegisterClassA_orig = detour::iat_try("RegisterClassA", RegisterClassA_hook);
RegisterClassExA_orig = detour::iat_try("RegisterClassExA", RegisterClassExA_hook);
RegisterClassW_orig = detour::iat_try("RegisterClassW", RegisterClassW_hook);
RegisterClassExW_orig = detour::iat_try("RegisterClassExW", RegisterClassExW_hook);
ShowCursor_orig = detour::iat_try("ShowCursor", ShowCursor_hook);
SetCursor_orig = detour::iat_try("SetCursor", SetCursor_hook);
SetWindowLongA_orig = detour::iat_try("SetWindowLongA", SetWindowLongA_hook);
SetWindowLongW_orig = detour::iat_try("SetWindowLongW", SetWindowLongW_hook);
SetWindowPos_orig = detour::iat_try("SetWindowPos", SetWindowPos_hook);
detour::iat_try("MessageBoxA", MessageBoxA_hook);
detour::iat_try("MessageBoxExA", MessageBoxExA_hook);
detour::iat_try("MessageBoxW", MessageBoxW_hook);
detour::iat_try("MessageBoxExW", MessageBoxExW_hook);
detour::iat_try("SetWindowsHookExA", SetWindowsHookExA_hook);
detour::iat_try("SetCursorPos", SetCursorPos_hook);
}
void graphics_hook_window(HWND hWnd, D3DPRESENT_PARAMETERS *pPresentationParameters) {
// update window size for a few games
// TODO: make this work on everything
if (pPresentationParameters != nullptr && GRAPHICS_WINDOWED
&& (avs::game::is_model({ "K39", "L39", "M39", "JMP", "LDJ" }))) {
// check dimensions
auto new_width = pPresentationParameters->BackBufferWidth;
auto new_height = pPresentationParameters->BackBufferHeight;
if (new_width != 0 && new_height != 0) {
RECT rect {};
GetWindowRect(hWnd, &rect);
auto width = rect.right - rect.left;
auto height = rect.bottom - rect.top;
log_info("graphics", "resized window: {}x{} -> {}x{}", width, height, new_width, new_height);
DWORD dwStyle = GetWindowLongA(hWnd, GWL_STYLE);
DWORD dwExStyle = GetWindowLongA(hWnd, GWL_EXSTYLE);
HMENU menu = GetMenu(hWnd);
SetRect(&rect, 0, 0, new_width, new_height);
AdjustWindowRectEx(&rect, dwStyle, (menu != nullptr), dwExStyle);
// make sure the window does not go off the screen
if (rect.top < 0) {
rect.bottom += -rect.top;
rect.top = 0;
}
width = rect.right - rect.left;
height = rect.bottom - rect.top;
SetWindowPos(hWnd, HWND_TOP, rect.left, rect.top, width, height, 0);
}
}
// show cursor
if (GRAPHICS_SHOW_CURSOR) {
ShowCursor(TRUE);
}
// capture mouse
if (GRAPHICS_CAPTURE_CURSOR) {
RECT rect {};
GetWindowRect(hWnd, &rect);
ClipCursor(&rect);
}
// hook window procedure
if (WNDPROC_ORIG == nullptr) {
WNDPROC_ORIG = reinterpret_cast<WNDPROC>(GetWindowLongPtrA(hWnd, GWLP_WNDPROC));
SetWindowLongPtrA(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc));
}
}
void graphics_add_wnd_proc(WNDPROC wnd_proc) {
WNDPROC_CUSTOM.push_back(wnd_proc);
}
void graphics_remove_wnd_proc(WNDPROC wndProc) {
for (size_t x = 0; x < WNDPROC_CUSTOM.size(); x++) {
if (WNDPROC_CUSTOM[x] == wndProc) {
WNDPROC_CUSTOM.erase(WNDPROC_CUSTOM.begin() + x);
}
}
}
void graphics_screens_register(int screen) {
std::lock_guard<std::mutex> lock(GRAPHICS_SCREENS_M);
GRAPHICS_SCREENS.insert(screen);
}
void graphics_screens_unregister(int screen) {
std::lock_guard<std::mutex> lock(GRAPHICS_SCREENS_M);
GRAPHICS_SCREENS.erase(screen);
}
void graphics_screens_get(std::vector<int> &screens) {
std::lock_guard<std::mutex> lock(GRAPHICS_SCREENS_M);
screens.insert(screens.end(), GRAPHICS_SCREENS.begin(), GRAPHICS_SCREENS.end());
}
void graphics_screenshot_trigger() {
GRAPHICS_SCREENSHOT_TRIGGER = true;
}
bool graphics_screenshot_consume() {
auto flag = GRAPHICS_SCREENSHOT_TRIGGER;
GRAPHICS_SCREENSHOT_TRIGGER = false;
return flag;
}
void graphics_capture_trigger(int screen) {
std::lock_guard<std::mutex> lock(GRAPHICS_CAPTURE_SCREENS_M);
GRAPHICS_CAPTURE_SCREENS.push_back(screen);
}
bool graphics_capture_consume(int *screen) {
auto flag = !GRAPHICS_CAPTURE_SCREENS.empty();
if (flag) {
std::lock_guard<std::mutex> lock(GRAPHICS_CAPTURE_SCREENS_M);
*screen = GRAPHICS_CAPTURE_SCREENS.back();
GRAPHICS_CAPTURE_SCREENS.pop_back();
}
return flag;
}
void graphics_capture_enqueue(int screen, uint8_t *data, size_t width, size_t height) {
GRAPHICS_CAPTURE_BUFFER_M[screen].lock();
auto &capture = GRAPHICS_CAPTURE_BUFFER[screen];
capture.data.reset(data);
capture.width = width;
capture.height = height;
capture.timestamp = get_performance_milliseconds();
GRAPHICS_CAPTURE_BUFFER_M[screen].unlock();
GRAPHICS_CAPTURE_CV[screen].notify_one();
}
void graphics_capture_skip(int screen) {
GRAPHICS_CAPTURE_CV[screen].notify_one();
}
bool graphics_capture_receive_jpeg(int screen, TooJpeg::WRITE_ONE_BYTE receiver,
bool rgb, int quality, bool downsample, int divide, uint64_t *timestamp,
int *width, int *height) {
// wait for capture event
std::unique_lock<std::mutex> lock(GRAPHICS_CAPTURE_BUFFER_M[screen]);
GRAPHICS_CAPTURE_CV[screen].wait(lock, [screen] {
return GRAPHICS_CAPTURE_BUFFER[screen].data != nullptr;
});
auto &capture = GRAPHICS_CAPTURE_BUFFER[screen];
auto capture_data = capture.data;
auto capture_width = capture.width;
auto capture_height = capture.height;
auto capture_timestamp = capture.timestamp;
lock.unlock();
// validate data
if (!capture_data || !capture_width || !capture_height) {
return false;
}
// divide image size
if (divide > 1) {
// get new resolution (round up)
int width_new = (capture_width + divide - 1) / divide;
int height_new = (capture_height + divide - 1) / divide;
// allocate new data
auto data_old = capture_data.get();
auto data_new = new uint8_t[width_new * height_new * 3];
// copy pixel data
int data_y = 0;
for (int y = 0; y < capture_height; y += divide) {
int data_y_offset_old = y * capture_width;
int data_y_offset = data_y * width_new;
int data_x = 0;
for (int x = 0; x < capture_width; x += divide) {
auto pixel_new = &data_new[(data_x + data_y_offset) * 3];
auto pixel_old = &data_old[(data_y_offset_old + x) * 3];
memcpy(pixel_new, pixel_old, 3);
data_x++;
}
data_y++;
}
// update capture data
capture_data.reset(data_new);
capture_width = width_new;
capture_height = height_new;
}
// compress
auto success = TooJpeg::writeJpeg(
receiver, capture_data.get(),
capture_width, capture_height,
rgb, quality, downsample);
// status
if (timestamp) {
*timestamp = capture_timestamp;
}
if (width) {
*width = capture_width;
}
if (height) {
*height = capture_height;
}
// clean up
return success;
}
std::string graphics_screenshot_genpath() {
// verify dir path
if (GRAPHICS_SCREENSHOT_DIR.empty()) {
return "";
} else {
auto last_char = GRAPHICS_SCREENSHOT_DIR.back();
if (last_char == '\\' || last_char == '/') {
GRAPHICS_SCREENSHOT_DIR.pop_back();
}
}
// ensure the output directory exists
if (!fileutils::dir_exists(GRAPHICS_SCREENSHOT_DIR)) {
if (!fileutils::dir_create_recursive(GRAPHICS_SCREENSHOT_DIR)) {
log_warning("graphics", "could not create screenshot dir: {}", GRAPHICS_SCREENSHOT_DIR);
return "";
}
}
// generate date prefix
auto t_now = std::time(nullptr);
auto tm_now = *std::gmtime(&t_now);
auto prefix = to_string(std::put_time(&tm_now, "%Y%m%d"));
// find next filename
size_t id = 0;
while (true) {
auto filepath = fmt::format("{}\\{}_{}.png", GRAPHICS_SCREENSHOT_DIR, prefix, id);
if (!fileutils::file_exists(filepath)) {
return filepath;
}
id++;
}
}
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include <string>
#include <vector>
#include <optional>
#include <windows.h>
#include <d3d9.h>
#include "external/toojpeg/toojpeg.h"
// flag settings
extern bool GRAPHICS_CAPTURE_CURSOR;
extern bool GRAPHICS_LOG_HRESULT;
extern bool GRAPHICS_SDVX_FORCE_720;
extern bool GRAPHICS_SHOW_CURSOR;
extern bool GRAPHICS_WINDOWED;
extern bool GRAPHICS_ADJUST_ORIENTATION;
extern std::vector<HWND> GRAPHICS_WINDOWS;
extern UINT GRAPHICS_FORCE_REFRESH;
extern bool GRAPHICS_FORCE_SINGLE_ADAPTER;
extern bool GRAPHICS_9_ON_12;
// settings
extern std::string GRAPHICS_DEVICEID;
extern std::string GRAPHICS_SCREENSHOT_DIR;
// Direct3D 9 settings
extern std::optional<UINT> D3D9_ADAPTER;
extern DWORD D3D9_BEHAVIOR_DISABLE;
void graphics_init();
void graphics_hook_window(HWND hWnd, D3DPRESENT_PARAMETERS *pPresentationParameters);
void graphics_add_wnd_proc(WNDPROC wndProc);
void graphics_remove_wnd_proc(WNDPROC wndProc);
void graphics_screens_register(int screen);
void graphics_screens_unregister(int screen);
void graphics_screens_get(std::vector<int> &screens);
void graphics_screenshot_trigger();
bool graphics_screenshot_consume();
void graphics_capture_trigger(int screen);
bool graphics_capture_consume(int *screen);
void graphics_capture_enqueue(int screen, uint8_t *data, size_t width, size_t height);
void graphics_capture_skip(int screen);
bool graphics_capture_receive_jpeg(int screen, TooJpeg::WRITE_ONE_BYTE receiver,
bool rgb = true, int quality = 80, bool downsample = true, int divide = 0,
uint64_t *timestamp = nullptr,
int *width = nullptr, int *height = nullptr);
std::string graphics_screenshot_genpath();