Initial re-upload of spice2x-24-08-24

This commit is contained in:
2024-08-28 11:10:34 -04:00
commit caa9e02285
1181 changed files with 380065 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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

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;
};

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -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));
}

View File

@@ -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;
};

View File

@@ -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));
}

View File

@@ -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;
};

View File

@@ -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
};

View File

@@ -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;
}

1034
hooks/graphics/graphics.cpp Normal file

File diff suppressed because it is too large Load Diff

94
hooks/graphics/graphics.h Normal file
View File

@@ -0,0 +1,94 @@
#pragma once
#include <string>
#include <vector>
#include <optional>
#include <cstdint>
#include <windows.h>
#include <d3d9.h>
#include "external/toojpeg/toojpeg.h"
// order must match spice2x_AutoOrientation UI enum order
enum graphics_orientation {
ORIENTATION_CW = 0,
ORIENTATION_CCW = 1,
ORIENTATION_NORMAL = 2,
};
enum graphics_dx9on12_state {
DX9ON12_AUTO,
DX9ON12_FORCE_OFF,
DX9ON12_FORCE_ON,
};
// 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 graphics_orientation GRAPHICS_ADJUST_ORIENTATION;
extern std::vector<HWND> GRAPHICS_WINDOWS;
extern UINT GRAPHICS_FORCE_REFRESH;
extern bool GRAPHICS_FORCE_SINGLE_ADAPTER;
extern bool GRAPHICS_PREVENT_SECONDARY_WINDOW;
extern graphics_dx9on12_state GRAPHICS_9_ON_12_STATE;
extern bool GRAPHICS_9_ON_12_REQUESTED_BY_GAME;
extern std::optional<int> GRAPHICS_WINDOW_STYLE;
extern std::optional<std::string> GRAPHICS_WINDOW_SIZE;
extern std::optional<std::string> GRAPHICS_WINDOW_POS;
extern bool GRAPHICS_WINDOW_ALWAYS_ON_TOP;
extern bool GRAPHICS_IIDX_WSUB;
extern std::optional<std::string> GRAPHICS_IIDX_WSUB_SIZE;
extern std::optional<std::string> GRAPHICS_IIDX_WSUB_POS;
extern int GRAPHICS_IIDX_WSUB_WIDTH;
extern int GRAPHICS_IIDX_WSUB_HEIGHT;
extern int GRAPHICS_IIDX_WSUB_X;
extern int GRAPHICS_IIDX_WSUB_Y;
extern HWND TDJ_SUBSCREEN_WINDOW;
extern HWND SDVX_SUBSCREEN_WINDOW;
extern bool SUBSCREEN_FORCE_REDRAW;
// 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;
extern bool D3D9_DEVICE_HOOK_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_hook_subscreen_window(HWND hWnd);
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();
// graphics_windowed.cpp
void graphics_windowed_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void graphics_capture_initial_window(HWND hWnd);
void graphics_update_window_style(HWND hWnd);
void graphics_update_z_order(HWND hWnd);
void graphics_move_resize_window(HWND hWnd);
bool graphics_window_change_crashes_game();
void graphics_load_windowed_subscreen_parameters();

View File

@@ -0,0 +1,485 @@
#include "graphics.h"
#include "avs/game.h"
#include "cfg/screen_resize.h"
#include "overlay/overlay.h"
#include "util/logging.h"
#include "util/utils.h"
#include "touch/touch.h"
#if 0
#define log_debug(module, format_str, ...) logger::push( \
LOG_FORMAT("M", module, format_str, ## __VA_ARGS__), logger::Style::GREY)
#else
#define log_debug(module, format_str, ...)
#endif
void graphics_load_windowed_parameters();
void graphics_wm_style_changed(HWND hWnd, bool changed);
void graphics_wm_sizing_aspect_ratio(int edge, RECT& rect);
std::optional<int> GRAPHICS_WINDOW_STYLE;
std::optional<std::string> GRAPHICS_WINDOW_SIZE;
std::optional<std::string> GRAPHICS_WINDOW_POS;
bool GRAPHICS_WINDOW_ALWAYS_ON_TOP = false;
// IIDX Windowed Subscreen - starts out as false, enabled by IIDX module on pre-attach as needed
bool GRAPHICS_IIDX_WSUB = false;
std::optional<std::string> GRAPHICS_IIDX_WSUB_SIZE;
std::optional<std::string> GRAPHICS_IIDX_WSUB_POS;
int GRAPHICS_IIDX_WSUB_WIDTH = 1280;
int GRAPHICS_IIDX_WSUB_HEIGHT = 720;
int GRAPHICS_IIDX_WSUB_X = 0;
int GRAPHICS_IIDX_WSUB_Y = 0;
// these flags are carefully constructed to ensure maximum compatibility
// (e.g., DDR likes to hang when SetWindowPos is called with certain params)
static const DWORD SETWINDOWPOS_NOOP =
SWP_NOMOVE |
SWP_NOSIZE |
SWP_NOREDRAW |
SWP_NOCOPYBITS |
SWP_NOACTIVATE |
SWP_NOSENDCHANGING |
SWP_DEFERERASE |
SWP_NOZORDER |
SWP_ASYNCWINDOWPOS;
void graphics_capture_initial_window(HWND hWnd) {
if (!GRAPHICS_WINDOWED) {
return;
}
graphics_load_windowed_parameters();
cfg::SCREENRESIZE->init_window_style = GetWindowLong(hWnd, GWL_STYLE);
log_debug("graphics-windowed", "graphics_capture_initial_window called");
RECT rect;
if (!GetClientRect(hWnd, &rect)) {
log_warning(
"graphics",
"graphics_capture_initial_window - GetClientRect failed, GLE: {}",
GetLastError());
return;
}
const int client_w = rect.right - rect.left;
const int client_h = rect.bottom - rect.top;
cfg::SCREENRESIZE->init_client_width = client_w;
cfg::SCREENRESIZE->init_client_height = client_h;
cfg::SCREENRESIZE->init_client_aspect_ratio = (float)client_w / (float)client_h;
log_debug(
"graphics-windowed",
"graphics_capture_initial_window initial window size {}x{}, ratio {}",
client_w, client_h, cfg::SCREENRESIZE->init_client_aspect_ratio);
// ensure frame size is captured
graphics_wm_style_changed(hWnd, false);
// if there was no user-supplied dimension, seed it with the current size
// so that the next resize operation will work
if (cfg::SCREENRESIZE->client_width == 0) {
cfg::SCREENRESIZE->client_width = client_w;
}
if (cfg::SCREENRESIZE->client_height == 0) {
cfg::SCREENRESIZE->client_height = client_h;
}
// apply the config that was loaded from disk
// resize must be done before applying the border
if (cfg::SCREENRESIZE->enable_window_resize) {
log_info(
"graphics-windowed", "change window rect - window offset: {}x{}, client size: {}x{}",
cfg::SCREENRESIZE->window_offset_x,
cfg::SCREENRESIZE->window_offset_y,
cfg::SCREENRESIZE->client_width,
cfg::SCREENRESIZE->client_height);
graphics_move_resize_window(hWnd);
}
// ddr hangs when window frame doesn't have overlapped
if (cfg::SCREENRESIZE->window_decoration != cfg::WindowDecorationMode::Default) {
log_info(
"graphics-windowed", "change window style - decoration: {}",
cfg::SCREENRESIZE->window_decoration);
graphics_update_window_style(hWnd);
}
if (cfg::SCREENRESIZE->window_always_on_top) {
log_info("graphics-windowed", "change window z-order - always on top");
graphics_update_z_order(hWnd);
}
// ensure spictetouch coordinates are initialized
update_spicetouch_window_dimensions(hWnd);
log_debug("graphics-windowed", "graphics_capture_initial_window returned");
}
void graphics_load_windowed_parameters() {
if (!GRAPHICS_WINDOWED) {
return;
}
log_debug("graphics-windowed", "graphics_load_windowed_parameters called");
const auto remove_spaces = [](const char& c) {
return c == ' ';
};
if (GRAPHICS_WINDOW_STYLE.has_value()) {
log_debug(
"graphics-windowed",
"graphics_load_windowed_parameters - load GRAPHICS_WINDOW_STYLE");
cfg::SCREENRESIZE->window_decoration = GRAPHICS_WINDOW_STYLE.value();
}
if (GRAPHICS_WINDOW_SIZE.has_value()) {
log_debug(
"graphics-windowed",
"graphics_load_windowed_parameters - load GRAPHICS_WINDOW_SIZE");
uint32_t w, h;
auto s = GRAPHICS_WINDOW_SIZE.value();
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
if (sscanf(s.c_str(), "%u,%u", &w, &h) == 2) {
cfg::SCREENRESIZE->enable_window_resize = true;
cfg::SCREENRESIZE->client_keep_aspect_ratio = false;
cfg::SCREENRESIZE->client_width = w;
cfg::SCREENRESIZE->client_height = h;
} else {
log_warning("graphics-windowed", "failed to parse -windowsize");
}
}
if (GRAPHICS_WINDOW_POS.has_value()) {
log_debug(
"graphics-windowed",
"graphics_load_windowed_parameters - load GRAPHICS_WINDOW_POS");
int32_t x, y;
auto s = GRAPHICS_WINDOW_POS.value();
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
if (sscanf(s.c_str(), "%d,%d", &x, &y) == 2) {
cfg::SCREENRESIZE->enable_window_resize = true;
cfg::SCREENRESIZE->window_offset_x = x;
cfg::SCREENRESIZE->window_offset_y = y;
} else {
log_warning("graphics-windowed", "failed to parse -windowpos");
}
}
// only override if true; don't stomp on user setting
if (GRAPHICS_WINDOW_ALWAYS_ON_TOP) {
cfg::SCREENRESIZE->window_always_on_top = true;
}
log_debug("graphics-windowed", "graphics_load_windowed_parameters returned");
}
void graphics_load_windowed_subscreen_parameters() {
if (!GRAPHICS_WINDOWED) {
return;
}
log_debug("graphics-windowed", "graphics_load_windowed_subscreen_parameters called");
const auto remove_spaces = [](const char& c) {
return c == ' ';
};
if (GRAPHICS_IIDX_WSUB_SIZE.has_value()) {
log_debug(
"graphics-windowed",
"graphics_load_windowed_parameters - load GRAPHICS_IIDX_WSUB_SIZE");
uint32_t w, h;
auto s = GRAPHICS_IIDX_WSUB_SIZE.value();
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
if (sscanf(s.c_str(), "%u,%u", &w, &h) == 2) {
GRAPHICS_IIDX_WSUB_WIDTH = w;
GRAPHICS_IIDX_WSUB_HEIGHT = h;
} else {
log_warning("graphics-windowed", "failed to parse -wsubsize");
}
}
if (GRAPHICS_IIDX_WSUB_POS.has_value()) {
log_debug(
"graphics-windowed",
"graphics_load_windowed_parameters - load GRAPHICS_IIDX_WSUB_POS");
int32_t x, y;
auto s = GRAPHICS_IIDX_WSUB_POS.value();
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
if (sscanf(s.c_str(), "%d,%d", &x, &y) == 2) {
GRAPHICS_IIDX_WSUB_X = x;
GRAPHICS_IIDX_WSUB_Y = y;
} else {
log_warning("graphics-windowed", "failed to parse -wsubpos");
}
}
}
void graphics_windowed_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (!GRAPHICS_WINDOWED) {
return;
}
switch (uMsg) {
case WM_MOVE: {
log_debug("graphics-windowed", "graphics_windowed_wndproc called with WM_MOVE");
RECT rect;
if (GetWindowRect(hWnd, &rect)) {
cfg::SCREENRESIZE->window_offset_x = rect.left;
cfg::SCREENRESIZE->window_offset_y = rect.top;
}
break;
}
case WM_SIZE: {
log_debug("graphics-windowed", "graphics_windowed_wndproc called with WM_SIZE");
if (wParam == SIZE_MINIMIZED) {
break;
}
RECT rect;
if (GetClientRect(hWnd, &rect)) {
cfg::SCREENRESIZE->client_width = rect.right - rect.left;
cfg::SCREENRESIZE->client_height = rect.bottom - rect.top;
}
break;
}
case WM_SIZING: {
if (cfg::SCREENRESIZE->client_keep_aspect_ratio) {
graphics_wm_sizing_aspect_ratio(
static_cast<int>(wParam), *reinterpret_cast<LPRECT>(lParam));
}
break;
}
case WM_STYLECHANGED: {
graphics_wm_style_changed(hWnd, true);
break;
}
case WM_GETMINMAXINFO: {
if (cfg::SCREENRESIZE->client_keep_aspect_ratio) {
auto info = reinterpret_cast<MINMAXINFO *>(lParam);
info->ptMinTrackSize.y =
cfg::SCREENRESIZE->window_deco_height +
((info->ptMinTrackSize.x - cfg::SCREENRESIZE->window_deco_width) /
cfg::SCREENRESIZE->init_client_aspect_ratio);
}
break;
}
}
}
void graphics_wm_style_changed(HWND hWnd, bool changed) {
log_debug("graphics-windowed", "graphics_wm_style_changed called");
RECT rect;
// ensure the style change takes in effect before doing the calculations
if (changed) {
// ensure client size doesn't change as a result of this
// since SetWindowPos will still send WM_SIZE and WM_MOVE
const auto client_w = cfg::SCREENRESIZE->client_width;
const auto client_h = cfg::SCREENRESIZE->client_height;
const auto flags = SETWINDOWPOS_NOOP | SWP_FRAMECHANGED;
SetWindowPos(
hWnd,
nullptr,
0, 0, 0, 0,
flags);
cfg::SCREENRESIZE->client_width = client_w;
cfg::SCREENRESIZE->client_height = client_h;
}
// get window size with decoration...
if (!GetWindowRect(hWnd, &rect)) {
log_warning(
"graphics",
"graphics_wm_style_changed - GetWindowRect failed, GLE: {}",
GetLastError());
return;
}
const int window_w = rect.right - rect.left;
const int window_h = rect.bottom - rect.top;
// get client area (without decoration)...
if (!GetClientRect(hWnd, &rect)) {
return;
}
const int client_w = rect.right - rect.left;
const int client_h = rect.bottom - rect.top;
// update window decoration size
cfg::SCREENRESIZE->window_deco_width = window_w - client_w;
cfg::SCREENRESIZE->window_deco_height = window_h - client_h;
log_debug(
"graphics-windowed",
"graphics_wm_style_changed updating frame dimensions {}x{}",
cfg::SCREENRESIZE->window_deco_width,
cfg::SCREENRESIZE->window_deco_height);
// adjust window to ensure client area remains the same
if (changed) {
graphics_move_resize_window(hWnd);
}
log_debug("graphics-windowed", "graphics_wm_style_changed returned");
}
void graphics_wm_sizing_aspect_ratio(int edge, RECT& rect) {
log_debug("graphics-windowed", "graphics_wm_sizing_aspect_ratio called");
const auto deco_w = cfg::SCREENRESIZE->window_deco_width;
const auto deco_h = cfg::SCREENRESIZE->window_deco_height;
const LONG desired_w = (rect.right - rect.left) - deco_w;
const LONG desired_h = (rect.bottom - rect.top) - deco_h;
const auto aspect_ratio = cfg::SCREENRESIZE->init_client_aspect_ratio;
// based on http://playtechs.blogspot.com/2007/10/forcing-window-to-maintain-particular.html
switch (edge) {
case WMSZ_BOTTOM:
case WMSZ_TOP: {
const LONG w = deco_w + (desired_h * aspect_ratio);
rect.right = rect.left + w;
break;
}
case WMSZ_LEFT:
case WMSZ_RIGHT: {
const LONG h = deco_h + (desired_w / aspect_ratio);
rect.bottom = rect.top + h;
break;
}
case WMSZ_TOPLEFT:
case WMSZ_TOPRIGHT:
case WMSZ_BOTTOMLEFT:
case WMSZ_BOTTOMRIGHT: {
int w;
int h;
if (desired_h * aspect_ratio < desired_w) {
w = rect.right - rect.left;
h = deco_h + (desired_w / aspect_ratio);
} else {
w = deco_w + (desired_h * aspect_ratio);
h = rect.bottom - rect.top;
}
if (edge == WMSZ_TOPLEFT) {
rect.left = rect.right - w;
rect.top = rect.bottom - h;
} else if (edge == WMSZ_TOPRIGHT) {
rect.right = rect.left + w;
rect.top = rect.bottom - h;
} else if (edge == WMSZ_BOTTOMLEFT) {
rect.left = rect.right - w;
rect.bottom = rect.top + h;
} else if (edge == WMSZ_BOTTOMRIGHT) {
rect.right = rect.left + w;
rect.bottom = rect.top + h;
}
break;
}
default:
break;
}
log_debug("graphics-windowed", "graphics_wm_sizing_aspect_ratio returned");
}
void graphics_update_window_style(HWND hWnd) {
if (!GRAPHICS_WINDOWED) {
return;
}
if (graphics_window_change_crashes_game()) {
return;
}
log_debug("graphics-windowed", "graphics_update_window_style called");
// update frame style
auto style = cfg::SCREENRESIZE->init_window_style;
switch (cfg::SCREENRESIZE->window_decoration) {
case cfg::WindowDecorationMode::Borderless:
style &= ~WS_OVERLAPPEDWINDOW;
break;
case cfg::WindowDecorationMode::ResizableFrame:
style |= WS_OVERLAPPEDWINDOW;
break;
case cfg::WindowDecorationMode::Default:
default:
break;
}
log_debug(
"graphics-windowed",
"graphics_update_window_style - calling SetWindowLong with Mode {}, style 0x{:x}",
static_cast<int>(cfg::SCREENRESIZE->window_decoration),
style);
SetWindowLong(hWnd, GWL_STYLE, style);
// SetWindowPos must be called after SetWindowLong if the frame style changed
// this will be done in WM_STYLECHANGED handler
log_debug("graphics-windowed", "graphics_update_window_style returned");
}
void graphics_update_z_order(HWND hWnd) {
if (!GRAPHICS_WINDOWED) {
return;
}
log_debug("graphics-windowed", "graphics_update_z_order called");
HWND insert_after = nullptr;
if (cfg::SCREENRESIZE->window_always_on_top) {
insert_after = HWND_TOPMOST;
} else {
insert_after = HWND_NOTOPMOST;
}
auto flags = SETWINDOWPOS_NOOP;
flags &= ~SWP_NOZORDER;
SetWindowPos(
hWnd,
insert_after,
0, 0, 0, 0,
flags);
log_debug("graphics-windowed", "graphics_update_z_order returned");
}
void graphics_move_resize_window(HWND hWnd) {
if (!GRAPHICS_WINDOWED) {
return;
}
log_debug("graphics-windowed", "graphics_move_resize_window called");
cfg::SCREENRESIZE->client_width =
CLAMP(cfg::SCREENRESIZE->client_width, 640, 1920 * 8);
cfg::SCREENRESIZE->client_height =
CLAMP(cfg::SCREENRESIZE->client_height, 480, 1080 * 8);
const auto w = cfg::SCREENRESIZE->client_width + cfg::SCREENRESIZE->window_deco_width;
const auto h = cfg::SCREENRESIZE->client_height + cfg::SCREENRESIZE->window_deco_height;
auto flags = SETWINDOWPOS_NOOP;
flags &= ~SWP_NOSIZE;
flags &= ~SWP_NOMOVE;
SetWindowPos(
hWnd,
nullptr,
cfg::SCREENRESIZE->window_offset_x,
cfg::SCREENRESIZE->window_offset_y,
w, h,
flags);
log_debug("graphics-windowed", "graphics_move_resize_window returned");
}
bool graphics_window_change_crashes_game() {
static std::once_flag flag;
static bool result = false;
std::call_once(flag, []() {
// ddr crashes when frame style changes
result = avs::game::is_model("MDX");
if (result) {
log_warning(
"graphics-windowed",
"ignoring changes to window style due to incompatibility with this game");
}
});
return result;
}

View File

@@ -0,0 +1,59 @@
#include "external/nvapi/nvapi.h"
#include "external/nvapi/NvApiDriverSettings.h"
#include "hooks/libraryhook.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "nvapi_hook.h"
namespace nvapi_hook {
bool BYPASS_NVAPI = false;
typedef uintptr_t *(*NvAPI_QueryInterface_t)(unsigned int);
static NvAPI_QueryInterface_t NvAPI_QueryInterface_orig = nullptr;
static uintptr_t* __cdecl NvAPI_QueryInterface_hook(unsigned int func_code);
static NvAPI_Status __cdecl NvAPI_DISP_SetDisplayConfig_hook(
NvU32 pathInfoCount, NV_DISPLAYCONFIG_PATH_INFO *pathInfo, NvU32 flags);
void initialize(HINSTANCE dll) {
#ifdef SPICE64
std::string nvapi_dll = "nvapi64.dll";
#else
std::string nvapi_dll = "nvapi.dll";
#endif
detour::trampoline_try(
nvapi_dll.c_str(), "nvapi_QueryInterface",
NvAPI_QueryInterface_hook, &NvAPI_QueryInterface_orig);
}
uintptr_t* __cdecl NvAPI_QueryInterface_hook(unsigned int func_code) {
if (BYPASS_NVAPI) {
log_misc(
"nvapi_hook",
"NvAPI_QueryInterface(0x{:x}) - block all calls to nvapi (-nonvapi)",
func_code);
return nullptr;
}
// NvAPI_DISP_SetDisplayConfig
if (func_code == 0x5D8CF8DE) {
log_misc("nvapi_hook", "NvAPI_QueryInterface(NvAPI_DISP_SetDisplayConfig) - hooked");
return (uintptr_t *)NvAPI_DISP_SetDisplayConfig_hook;
}
// all others: let the game call nvapi directly
log_misc("nvapi_hook", "NvAPI_QueryInterface(0x{:x}) - pass through to nvapi", func_code);
return NvAPI_QueryInterface_orig(func_code);
}
NvAPI_Status __cdecl NvAPI_DISP_SetDisplayConfig_hook(
NvU32 pathInfoCount, NV_DISPLAYCONFIG_PATH_INFO *pathInfo, NvU32 flags) {
log_misc("nvapi_hook", "NvAPI_DISP_SetDisplayConfig_hook - do nothing and return");
return NVAPI_OK;
}
}

View File

@@ -0,0 +1,6 @@
#pragma once
namespace nvapi_hook {
extern bool BYPASS_NVAPI;
void initialize(HINSTANCE dll);
}

View File

@@ -0,0 +1,87 @@
#include <d3d9.h>
#include "avs/game.h"
#include "external/nvenc/nvEncodeAPI.h"
#include "hooks/libraryhook.h"
#include "hooks/graphics/backends/d3d9/d3d9_device.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "nvenc_hook.h"
#ifdef SPICE64
typedef NVENCSTATUS(NVENCAPI *NvEncodeAPICreateInstance_Type)(NV_ENCODE_API_FUNCTION_LIST*);
static NvEncodeAPICreateInstance_Type NvEncodeAPICreateInstance_orig = nullptr;
static PNVENCOPENENCODESESSIONEX nvEncOpenEncodeSessionEx_orig = nullptr;
static BOOL initialized = false;
namespace nvenc_hook {
NVENCSTATUS nvEncOpenEncodeSessionEx_hook(
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS *openSessionExParams,
void **encoder
) {
WrappedIDirect3DDevice9 *wrappedDevice;
try {
wrappedDevice = (WrappedIDirect3DDevice9*)openSessionExParams->device;
// log_misc("nvenc_hook",
// "nvEncOpenEncodeSessionEx hook hit (wrapped: {}) (real: {})",
// fmt::ptr(wrappedDevice),
// fmt::ptr(wrappedDevice->pReal)
// );
openSessionExParams->device = wrappedDevice->pReal;
} catch (const std::exception &ex) {
// log_misc("nvenc_hook", "Cannot cast to WrappedIDirect3DDevice9. D3D9 hooks might be disabled.");
}
return nvEncOpenEncodeSessionEx_orig(openSessionExParams, encoder);
}
NVENCSTATUS NvEncodeAPICreateInstance_hook(NV_ENCODE_API_FUNCTION_LIST *pFunctionList) {
// log_misc("nvenc_hook", "NvEncodeAPICreateInstance hook hit");
auto status = NvEncodeAPICreateInstance_orig(pFunctionList);
// The game will call NvEncodeAPICreateInstance multiple times
// Using a flag to avoid creating trampoline repeatedly
if (!initialized) {
// hook functions
detour::trampoline_try(
pFunctionList->nvEncOpenEncodeSessionEx,
nvEncOpenEncodeSessionEx_hook,
&nvEncOpenEncodeSessionEx_orig);
// log_misc("nvenc_hook", "Created hook for nvEncOpenEncodeSessionEx");
initialized = true;
}
return status;
}
void initialize() {
HMODULE nvenc = libutils::try_library("nvEncodeAPI64.dll");
if (nvenc == nullptr) {
log_warning("nvenc_hook", "Failed to find nvEncodeAPI64.dll");
return;
}
bool success = detour::trampoline_try(
(NvEncodeAPICreateInstance_Type)libutils::try_proc(nvenc, "NvEncodeAPICreateInstance"),
NvEncodeAPICreateInstance_hook,
&NvEncodeAPICreateInstance_orig
);
if (success) {
log_misc("nvenc_hook", "Created hook for NvEncodeAPICreateInstance");
} else {
log_warning("nvenc_hook", "Failed to hook NvEncodeAPICreateInstance");
}
}
}
#else
namespace nvenc_hook {
void initialize() {
return;
}
}
#endif

View File

@@ -0,0 +1,5 @@
#pragma once
namespace nvenc_hook {
void initialize();
}