├── Software_d3d9 ├── d3d9.rc ├── Overlay │ ├── FontMap.tga │ ├── Overlay_WelcomeScreen.cpp │ └── DebugOverlay.h ├── SimpleFont256x256.png ├── resource.h ├── ShaderJIT.h ├── d3d9include.h ├── ShaderJIT_PrefixFile.cpp ├── FixedFuncEmu │ ├── FFPS │ │ └── Include │ │ │ ├── FFPS_TexLoad.fxh │ │ │ ├── FFPS_ArgumentSelector.fxh │ │ │ └── FFPS_ApplyColorStage.fxh │ └── FFVS │ │ └── Include │ │ └── FFVS_CalculateSingleLight.fxh ├── IDirect3DQuery9Hook.h ├── IDirect3DResource9Hook.h ├── Source.def ├── IDirect3DPixelShader9Hook.h ├── IDirect3DVolume9Hook.h ├── SimpleInstrumentedProfiler.h ├── IDirect3DBaseTexture9Hook.h ├── IDirect3DSwapChain9Hook.h ├── IDirect3D9Hook.h ├── IDirect3DVolume9Hook.cpp ├── DitherTables.h ├── FixedFunctionToShader.h ├── SemanticMappings.h ├── IDirect3DResource9Hook.cpp ├── IDirect3DCubeTexture9Hook.h ├── IDirect3DVertexShader9Hook.h ├── IDirect3DVolumeTexture9Hook.h ├── IDirect3DBaseTexture9Hook.cpp ├── IDirect3DVertexDeclaration9Hook.h ├── FixedFunctionToShader.cpp ├── IDirect3DVertexBuffer9Hook.h ├── ShaderEngineBase.h ├── GlobalToggles.h ├── PShaderEngine.h ├── IDirect3DPixelShader9Hook.cpp ├── IDirect3DVolumeTexture9Hook.cpp ├── IDirect3DCubeTexture9Hook.cpp ├── IDirect3DTexture9Hook.h ├── IDirect3DIndexBuffer9Hook.h ├── IDirect3DVertexShader9Hook.cpp ├── ShaderJIT.cpp ├── IDirect3DVertexBuffer9Hook.cpp ├── IDirect3DQuery9Hook.cpp ├── IDirect3DIndexBuffer9Hook.cpp └── IDirect3DVertexDeclaration9Hook.cpp ├── LICENSE.txt ├── Software_d3d9.sln ├── .gitignore └── README.md /Software_d3d9/d3d9.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-tom-code/Software_D3D9/HEAD/Software_d3d9/d3d9.rc -------------------------------------------------------------------------------- /Software_d3d9/Overlay/FontMap.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-tom-code/Software_D3D9/HEAD/Software_d3d9/Overlay/FontMap.tga -------------------------------------------------------------------------------- /Software_d3d9/SimpleFont256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-tom-code/Software_D3D9/HEAD/Software_d3d9/SimpleFont256x256.png -------------------------------------------------------------------------------- /Software_d3d9/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by d3d9.rc 4 | // 5 | #define IDR_CPP1 103 6 | #define IDR_HLSL_FFPS_SRC 107 7 | #define IDR_HLSL_FFVS_SRC 108 8 | #define IDR_TGA1 109 9 | 10 | // Next default values for new objects 11 | // 12 | #ifdef APSTUDIO_INVOKED 13 | #ifndef APSTUDIO_READONLY_SYMBOLS 14 | #define _APS_NEXT_RESOURCE_VALUE 110 15 | #define _APS_NEXT_COMMAND_VALUE 40001 16 | #define _APS_NEXT_CONTROL_VALUE 1001 17 | #define _APS_NEXT_SYMED_VALUE 101 18 | #endif 19 | #endif 20 | -------------------------------------------------------------------------------- /Software_d3d9/Overlay/Overlay_WelcomeScreen.cpp: -------------------------------------------------------------------------------- 1 | #include "DebugOverlay.h" 2 | #include "..\IDirect3DDevice9Hook.h" 3 | 4 | void UpdateAndDrawOverlay_WelcomeScreen(class IDirect3DDevice9Hook* const hookDev) 5 | { 6 | OverlaySetDeviceStateForText(hookDev); 7 | 8 | OverlayDrawString(hookDev, "Welcome!\n" 9 | "Press Ctrl + Shift + F8 at any time to disable all\n" 10 | "overlays.\n" 11 | "\n" 12 | "Overlays menu:\n" 13 | "0: Welcome Screen\n" 14 | "1: Device State\n", 0, 0, D3DCOLOR_ARGB(255, 255, 255, 255) ); 15 | 16 | if (GetAsyncKeyState('0') & 0x1) 17 | SetOverlayScreenState(hookDev, overlay_welcomeScreen); 18 | else if (GetAsyncKeyState('1') & 0x1) 19 | SetOverlayScreenState(hookDev, overlay_deviceState); 20 | } 21 | -------------------------------------------------------------------------------- /Software_d3d9/ShaderJIT.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ShaderAnalysis.h" 4 | 5 | static const char* const shaderEntrypointName = "ShaderMain"; 6 | static const char* const shaderJITTempDirectory = 7 | #ifdef _DEBUG 8 | "shaderjitd"; 9 | #else 10 | "shaderjit"; 11 | #endif 12 | 13 | // Not multithread-safe! 14 | const char* const ConstructShaderJITName(const ShaderInfo& shaderInfo); 15 | 16 | const bool JITNewShader(const ShaderInfo& shaderInfo, const char* const shaderFilename); 17 | 18 | static inline void AppendString(std::vector& cppfile, const char* const str) 19 | { 20 | const unsigned len = strlen(str); 21 | 22 | for (unsigned x = 0; x < len; ++x) 23 | cppfile.push_back(str[x]); 24 | } 25 | 26 | // Internal functions, do not call: 27 | void LoadPrefixFileInternal(std::vector& cppfile); 28 | const bool JITCPPFileInternal(const ShaderInfo& shaderInfo, const char* const shaderFilename); 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) June 2016 (first work) / February 2019 (first open-sourced on GitHub) by Tom Lopes 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /Software_d3d9/d3d9include.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _DEBUG 4 | #define D3D_DEBUG_INFO 1 5 | #else 6 | #undef D3D_DEBUG_INFO 7 | #endif 8 | 9 | // warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc 10 | #pragma warning(disable:4530) 11 | 12 | #undef UNICODE 13 | #undef _UNICODE 14 | #define WIN32_LEAN_AND_MEAN 15 | #include 16 | 17 | // Note: For this project (implemented as a d3d9.dll hook), we do *not* want to link against d3d9.lib because it would force 18 | // our output-generated d3d9.dll to be itself dependent on the real d3d9.dll. 19 | // #pragma comment(lib, "d3d9.lib") 20 | 21 | #include 22 | #ifdef _DEBUG 23 | #pragma comment(lib, "d3dx9d.lib") 24 | #else 25 | #pragma comment(lib, "d3dx9.lib") 26 | #endif 27 | 28 | #define STRINGIFY(x) #x 29 | #define TOSTRING(x) STRINGIFY(x) 30 | 31 | #define DbgPrint(x) OutputDebugStringA(x " (" __FILE__ ":" TOSTRING(__LINE__) ")\n") 32 | 33 | #ifdef _DEBUG 34 | #define DbgBreakPrint(x) MessageBoxA(NULL, __FILE__ ":" TOSTRING(__LINE__) "\n" x, "Error", NULL); DbgPrint(x) 35 | #else 36 | #define DbgBreakPrint(x) DbgPrint(x) 37 | #endif 38 | -------------------------------------------------------------------------------- /Software_d3d9.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.28307.1525 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d3d9", "Software_d3d9\Software_d3d9.vcxproj", "{FFDB895B-11C0-4996-8C2E-194D85FFFAE6}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Win32 = Debug|Win32 10 | Debug|x64 = Debug|x64 11 | Release|Win32 = Release|Win32 12 | Release|x64 = Release|x64 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {FFDB895B-11C0-4996-8C2E-194D85FFFAE6}.Debug|Win32.ActiveCfg = Debug|Win32 16 | {FFDB895B-11C0-4996-8C2E-194D85FFFAE6}.Debug|Win32.Build.0 = Debug|Win32 17 | {FFDB895B-11C0-4996-8C2E-194D85FFFAE6}.Debug|x64.ActiveCfg = Debug|x64 18 | {FFDB895B-11C0-4996-8C2E-194D85FFFAE6}.Debug|x64.Build.0 = Debug|x64 19 | {FFDB895B-11C0-4996-8C2E-194D85FFFAE6}.Release|Win32.ActiveCfg = Release|Win32 20 | {FFDB895B-11C0-4996-8C2E-194D85FFFAE6}.Release|Win32.Build.0 = Release|Win32 21 | {FFDB895B-11C0-4996-8C2E-194D85FFFAE6}.Release|x64.ActiveCfg = Release|x64 22 | {FFDB895B-11C0-4996-8C2E-194D85FFFAE6}.Release|x64.Build.0 = Release|x64 23 | EndGlobalSection 24 | GlobalSection(SolutionProperties) = preSolution 25 | HideSolutionNode = FALSE 26 | EndGlobalSection 27 | GlobalSection(ExtensibilityGlobals) = postSolution 28 | SolutionGuid = {5E04EDFD-1D25-4070-891C-F7243B95D719} 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /Software_d3d9/ShaderJIT_PrefixFile.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #undef UNICODE 4 | #undef _UNICODE 5 | #define WIN32_LEAN_AND_MEAN 6 | 7 | // Needed for DisableThreadLibraryCalls() 8 | #pragma comment(lib, "Kernel32.lib") 9 | 10 | // TODO: Don't hardcode these paths, it won't work on other people's computers as-is 11 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\VShaderEngine.h" 12 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\PShaderEngine.h" 13 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\ShaderAnalysis.h" 14 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\IDirect3DDevice9Hook.h" 15 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\IDirect3DPixelShader9Hook.h" 16 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\IDirect3DVertexShader9Hook.h" 17 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\IDirect3DTexture9Hook.h" 18 | 19 | #pragma pack(1) 20 | 21 | extern "C" { 22 | 23 | // This dummy symbol is needed if we're not linking against the CRT 24 | int _fltused = 0; 25 | 26 | BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID) 27 | { 28 | switch (reason) 29 | { 30 | case DLL_PROCESS_ATTACH: 31 | DisableThreadLibraryCalls(hInst); 32 | break; 33 | case DLL_PROCESS_DETACH: 34 | break; 35 | } 36 | return TRUE; 37 | } 38 | 39 | // ShaderMain goes here 40 | -------------------------------------------------------------------------------- /Software_d3d9/Overlay/DebugOverlay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum overlayState 4 | { 5 | overlay_uninitialized = -1, 6 | overlay_welcomeScreen = 0, 7 | overlay_deviceState = 1, 8 | 9 | // This enum member must always be last 10 | overlay_NUM_SCREENS 11 | }; 12 | 13 | static const unsigned textCharWidth = 12u; 14 | static const unsigned textCharHeight = textCharWidth; 15 | 16 | typedef void (*UpdateAndDrawOverlayFunc)(class IDirect3DDevice9Hook* const hookDev); 17 | 18 | void UpdateOverlay(class IDirect3DDevice9Hook* const hookDev); 19 | void DeleteOverlay(const class IDirect3DDevice9Hook* const hookDev); 20 | void ResetOverlay(const class IDirect3DDevice9Hook* const hookDev); 21 | 22 | void SetOverlayScreenState(const class IDirect3DDevice9Hook* const hookDev, const overlayState newState); 23 | void SetOverlayPerScreenData(const class IDirect3DDevice9Hook* const hookDev, void* const newScreenData); 24 | void* const GetOverlayPerScreenData(const class IDirect3DDevice9Hook* const hookDev); 25 | 26 | void OverlaySetDeviceStateForText(class IDirect3DDevice9Hook* const hookDev); 27 | void OverlayDrawString(class IDirect3DDevice9Hook* const hookDev, const char* const str, const unsigned xLeftChars, const unsigned yTopChars, const unsigned long color = 0xFFFFFFFF); 28 | void OverlayDrawPrintString(class IDirect3DDevice9Hook* const hookDev, const unsigned xLeftChars, const unsigned yTopChars, const unsigned long color, const char* const formatStr, ...); 29 | 30 | // Add screen-specific overlay functions here: 31 | void UpdateAndDrawOverlay_WelcomeScreen(class IDirect3DDevice9Hook* const hookDev); 32 | void UpdateAndDrawOverlay_DeviceState(class IDirect3DDevice9Hook* const hookDev); 33 | -------------------------------------------------------------------------------- /Software_d3d9/FixedFuncEmu/FFPS/Include/FFPS_TexLoad.fxh: -------------------------------------------------------------------------------- 1 | #define MAKE_TEXLOAD_NAME(x) TexLoad##x 2 | #define TEXTURENAME(x) texture##x 3 | 4 | inline const float4 MAKE_TEXLOAD_NAME(STAGE_NUM)(in const float4 texcoords) 5 | { 6 | #ifndef HAS_TEX_BOUND 7 | return float4(1.0f, 1.0f, 1.0f, 1.0f); 8 | #else // #ifndef HAS_TEX_BOUND 9 | #if (TEXTYPE & TEXTYPEPROJ) != 0 10 | #if ( (TEXTYPE & 0x3) == TEXTYPE1D) 11 | float a; 12 | return tex1Dproj(TEXTURENAME(STAGE_NUM), texcoords); 13 | #elif ( (TEXTYPE & 0x3) == TEXTYPE2D) 14 | float b; 15 | return tex2Dproj(TEXTURENAME(STAGE_NUM), texcoords); 16 | #elif ( (TEXTYPE & 0x3) == TEXTYPE3D) 17 | float c; 18 | return tex3Dproj(TEXTURENAME(STAGE_NUM), texcoords); 19 | #elif ( (TEXTYPE & 0x3) == TEXTYPECUBE) 20 | float d; 21 | return texCUBEproj(TEXTURENAME(STAGE_NUM), texcoords); 22 | #else // // #if ( (TEXTYPE & 0x3) == TEXTYPE1D) 23 | #error INVALID TEXTYPE FOR PROJ TYPE! 24 | #endif // #if ( (TEXTYPE & 0x3) == TEXTYPE1D) 25 | #else // #if (TEXTYPE & TEXTYPEPROJ) != 0 26 | #if TEXTYPE == TEXTYPE1D 27 | float e; 28 | return tex1D(TEXTURENAME(STAGE_NUM), texcoords.x); 29 | #elif TEXTYPE == TEXTYPE2D 30 | float f; 31 | return tex2D(TEXTURENAME(STAGE_NUM), texcoords.xy); 32 | #elif TEXTYPE == TEXTYPE3D 33 | float g; 34 | return tex3D(TEXTURENAME(STAGE_NUM), texcoords.xyz); 35 | #elif TEXTYPE == TEXTYPECUBE 36 | float h; 37 | return texCUBE(TEXTURENAME(STAGE_NUM), texcoords.xyz); 38 | #else // #if TEXTYPE == TEXTYPE1D 39 | #error INVALID TEXTYPE FOR NON-PROJ TYPE! 40 | #endif // #if TEXTYPE == TEXTYPE1D 41 | #endif // #if (TEXTYPE & TEXTYPEPROJ) != 0 42 | #endif // #ifndef HAS_TEX_BOUND 43 | } 44 | 45 | #undef TEXTURENAME 46 | #undef MAKE_TEXLOAD_NAME 47 | #undef HAS_TEX_BOUND 48 | #undef TEXTYPE 49 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DQuery9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DQuery9Hook : public IDirect3DQuery9 6 | { 7 | public: 8 | IDirect3DQuery9Hook(LPDIRECT3DQUERY9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1), queryType( (const D3DQUERYTYPE)0), 9 | occlusionQueryStartPixelsPassed_Begin(0), occlusionQueryStartPixelsPassed_End(0) 10 | { 11 | } 12 | 13 | inline LPDIRECT3DQUERY9 GetUnderlyingQuery(void) const 14 | { 15 | return realObject; 16 | } 17 | 18 | virtual ~IDirect3DQuery9Hook() 19 | { 20 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 21 | memset(this, 0x00000000, sizeof(*this) ); 22 | #endif 23 | } 24 | 25 | /*** IUnknown methods ***/ 26 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 27 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 28 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 29 | 30 | /*** IDirect3DQuery9 methods ***/ 31 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 32 | virtual COM_DECLSPEC_NOTHROW D3DQUERYTYPE STDMETHODCALLTYPE GetType(THIS) override; 33 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetDataSize(THIS) override; 34 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Issue(THIS_ DWORD dwIssueFlags) override; 35 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetData(THIS_ void* pData, DWORD dwSize, DWORD dwGetDataFlags) override; 36 | 37 | void CreateQuery(const D3DQUERYTYPE _queryType); 38 | 39 | protected: 40 | LPDIRECT3DQUERY9 realObject; 41 | IDirect3DDevice9Hook* parentDevice; 42 | unsigned __int64 refCount; 43 | 44 | D3DQUERYTYPE queryType; 45 | 46 | DWORD occlusionQueryStartPixelsPassed_Begin; 47 | DWORD occlusionQueryStartPixelsPassed_End; 48 | }; 49 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DResource9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DResourceHook9 : public IDirect3DResource9 6 | { 7 | public: 8 | 9 | IDirect3DResourceHook9(LPDIRECT3DRESOURCE9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1) 10 | { 11 | } 12 | 13 | virtual ~IDirect3DResourceHook9() 14 | { 15 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 16 | memset(this, 0x00000000, sizeof(*this) ); 17 | #endif 18 | } 19 | 20 | /*** IUnknown methods ***/ 21 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 22 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 23 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 24 | 25 | /*** IDirect3DResource9 methods ***/ 26 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 27 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) override; 28 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) override; 29 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE FreePrivateData(THIS_ REFGUID refguid) override; 30 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetPriority(THIS_ DWORD PriorityNew) override; 31 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetPriority(THIS) override; 32 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE PreLoad(THIS) override; 33 | virtual COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE GetType(THIS) override; 34 | 35 | protected: 36 | LPDIRECT3DRESOURCE9 realObject; 37 | IDirect3DDevice9Hook* parentDevice; 38 | unsigned __int64 refCount; 39 | }; 40 | 41 | BYTE* const PageAllocWithNoAccessPage(const unsigned lenBytes); 42 | -------------------------------------------------------------------------------- /Software_d3d9/Source.def: -------------------------------------------------------------------------------- 1 | LIBRARY d3d9 2 | EXPORTS 3 | 4 | ; Export ordinal numbers taken from the Windows 10 1809 version of d3d9.dll 5 | 6 | ; Functions exported by name go here: 7 | D3DPERF_BeginEvent=HookD3DPERF_BeginEvent @27 8 | D3DPERF_EndEvent=HookD3DPERF_EndEvent @28 9 | D3DPERF_GetStatus=HookD3DPERF_GetStatus @29 10 | D3DPERF_QueryRepeatFrame=HookD3DPERF_QueryRepeatFrame @30 11 | D3DPERF_SetMarker=HookD3DPERF_SetMarker @31 12 | D3DPERF_SetOptions=HookD3DPERF_SetOptions @32 13 | D3DPERF_SetRegion=HookD3DPERF_SetRegion @33 14 | DebugSetLevel=HookDebugSetLevel @34 15 | DebugSetMute=HookDebugSetMute @35 16 | Direct3D9EnableMaximizedWindowedModeShim=HookDirect3D9EnableMaximizedWindowedModeShim @36 17 | Direct3DCreate9=HookDirect3DCreate9 @37 18 | Direct3DCreate9Ex=HookDirect3DCreate9Ex @38 19 | Direct3DShaderValidatorCreate9=HookDirect3DShaderValidatorCreate9 @24 20 | PSGPError=HookPSGPError @25 21 | PSGPSampleTexture=HookPSGPSampleTexture @26 22 | 23 | ; Functions exported only by ordinal go here: 24 | 25 | ; Ordinal 16 = Direct3D9ForceHybridEnumeration 26 | Direct3D9ForceHybridEnumeration=HookDirect3D9ForceHybridEnumeration @16 27 | 28 | ; Ordinal 17 = Direct3D9SetMaximizedWindowedModeShim 29 | Direct3D9SetMaximizedWindowedModeShim=HookDirect3D9SetMaximizedWindowedModeShim @17 30 | 31 | ; Ordinal 18 = Direct3D9SetSwapEffectUpgradeShim 32 | Direct3D9SetSwapEffectUpgradeShim=HookDirect3D9SetSwapEffectUpgradeShim @18 33 | 34 | ; Ordinal 19 = Direct3D9Force9On12 35 | Direct3D9Force9On12=HookDirect3D9Force9On12 @19 36 | 37 | ; Ordinal 20 = Direct3DCreate9On12 38 | Direct3DCreate9On12=HookDirect3DCreate9On12 @20 39 | 40 | ; Ordinal 21 = Direct3DCreate9On12Ex 41 | Direct3DCreate9On12Ex=HookDirect3DCreate9On12Ex @21 42 | 43 | ; Ordinal 22 = Direct3D9SetMaximizedWindowHwndOverride 44 | Direct3D9SetMaximizedWindowHwndOverride=HookDirect3D9SetMaximizedWindowHwndOverride @22 45 | 46 | ; Ordinal 23 = Direct3D9SetVendorIDLieFor9On12 47 | Direct3D9SetVendorIDLieFor9On12=HookDirect3D9SetVendorIDLieFor9On12 @23 48 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DPixelShader9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | #include "ShaderAnalysis.h" 5 | 6 | class PShaderEngine; 7 | 8 | class IDirect3DPixelShader9Hook : public IDirect3DPixelShader9 9 | { 10 | public: 11 | IDirect3DPixelShader9Hook(LPDIRECT3DPIXELSHADER9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1), jitShaderMain(NULL), triedJit(false) 12 | { 13 | #ifdef _DEBUG 14 | memcpy(&Version, &realObject->Version, (char*)&realObject - (char*)&Version); 15 | #endif 16 | } 17 | 18 | inline LPDIRECT3DPIXELSHADER9 GetUnderlyingPixelShader(void) const 19 | { 20 | return realObject; 21 | } 22 | 23 | virtual ~IDirect3DPixelShader9Hook(); 24 | 25 | /*** IUnknown methods ***/ 26 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 27 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 28 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 29 | 30 | /*** IDirect3DPixelShader9 methods ***/ 31 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 32 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetFunction(THIS_ void* pData,UINT* pSizeOfData) override; 33 | 34 | void CreatePixelShader(const DWORD* const pFunction); 35 | 36 | inline const ShaderInfo& GetShaderInfo() const 37 | { 38 | return pixelShaderInfo; 39 | } 40 | 41 | inline ShaderInfo& GetModifyShaderInfo() 42 | { 43 | return pixelShaderInfo; 44 | } 45 | 46 | void JitLoadShader(); 47 | 48 | protected: 49 | LPDIRECT3DPIXELSHADER9 realObject; 50 | IDirect3DDevice9Hook* parentDevice; 51 | unsigned __int64 refCount; 52 | 53 | public: 54 | typedef void (__fastcall *PSEntry)(PShaderEngine& ps); 55 | PSEntry jitShaderMain; 56 | 57 | bool triedJit; 58 | protected: 59 | 60 | std::vector shaderBytecode; 61 | ShaderInfo pixelShaderInfo; 62 | }; 63 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVolume9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DVolume9Hook : public IDirect3DVolume9 6 | { 7 | public: 8 | IDirect3DVolume9Hook(LPDIRECT3DVOLUME9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1) 9 | { 10 | #ifdef _DEBUG 11 | memcpy(&Name, &realObject->Name, (char*)&realObject - (char*)&Name); 12 | #endif 13 | } 14 | 15 | virtual ~IDirect3DVolume9Hook() 16 | { 17 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 18 | memset(this, 0x00000000, sizeof(*this) ); 19 | #endif 20 | } 21 | 22 | /*** IUnknown methods ***/ 23 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 24 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 25 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 26 | 27 | /*** IDirect3DVolume9 methods ***/ 28 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 29 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) override; 30 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) override; 31 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE FreePrivateData(THIS_ REFGUID refguid) override; 32 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetContainer(THIS_ REFIID riid,void** ppContainer) override; 33 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDesc(THIS_ D3DVOLUME_DESC *pDesc) override; 34 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE LockBox(THIS_ D3DLOCKED_BOX * pLockedVolume,CONST D3DBOX* pBox,DWORD Flags) override; 35 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE UnlockBox(THIS) override; 36 | 37 | protected: 38 | LPDIRECT3DVOLUME9 realObject; 39 | IDirect3DDevice9Hook* parentDevice; 40 | unsigned __int64 refCount; 41 | }; 42 | -------------------------------------------------------------------------------- /Software_d3d9/SimpleInstrumentedProfiler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ENABLE_SIMPLE_PROFILER 0 4 | 5 | #ifdef _M_X64 // The new PIX profiler only works for x64 targets 6 | #define ENABLE_PIX_PROFILER 1 7 | #endif 8 | 9 | #if ENABLE_SIMPLE_PROFILER 10 | // TODO: Don't hardcode this path 11 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2017\\Projects\\SimpleHFileProfiler\\SimpleHFileProfiler\\SimpleProfiler.h" 12 | #elif ENABLE_PIX_PROFILER 13 | #define USE_PIX 1 14 | // TODO: Don't hardcode this path 15 | #include "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\WinPixEventRuntime\\pix3.h" 16 | #pragma comment(lib, "C:\\Users\\Tom\\Documents\\Visual Studio 2013\\Projects\\Software_d3d9\\trunk\\Software_d3d9\\WinPixEventRuntime\\WinPixEventRuntime.lib") 17 | 18 | #define SIMPLE_DYNAMIC_STRING_SCOPE(dynamicStringScopeName) PIXScopedEvent(PIX_COLOR_DEFAULT, dynamicStringScopeName) 19 | #define SIMPLE_NAME_SCOPE(scopeName) PIXScopedEvent(PIX_COLOR_DEFAULT, scopeName) 20 | #define SIMPLE_FUNC_SCOPE() PIXScopedEvent(PIX_COLOR_DEFAULT, __FUNCTION__) 21 | #define SIMPLE_FRAME_END_MARKER() PIXSetMarker(PIX_COLOR_DEFAULT, "END FRAME MARKER") 22 | struct PIX_CONDITIONAL_SCOPE_WRAPPER 23 | { 24 | PIX_CONDITIONAL_SCOPE_WRAPPER(const char* const scopeName, const bool _conditional) : conditional(_conditional) 25 | { 26 | if (conditional == true) 27 | { 28 | PIXBeginEvent(PIX_COLOR_DEFAULT, scopeName); 29 | } 30 | } 31 | ~PIX_CONDITIONAL_SCOPE_WRAPPER() 32 | { 33 | if (conditional == true) 34 | { 35 | PIXEndEvent(); 36 | } 37 | } 38 | private: 39 | const bool conditional; 40 | }; 41 | #define SIMPLE_DYNAMIC_STRING_SCOPE_CONDITIONAL(dynamicStringScopeName, conditional) PIX_CONDITIONAL_SCOPE_WRAPPER _conditionalAutoNameDynamicNameScope(dynamicStringScopeName, (conditional) ) 42 | #define SIMPLE_NAME_SCOPE_CONDITIONAL(scopeName, conditional) PIX_CONDITIONAL_SCOPE_WRAPPER _conditionalAutoNameDynamicNameScope(scopeName, (conditional) ) 43 | #define SIMPLE_FUNC_SCOPE_CONDITIONAL(conditional) PIX_CONDITIONAL_SCOPE_WRAPPER _conditionalAutoNameDynamicNameScope(__FUNCTION__, (conditional) ) 44 | #else 45 | #define SIMPLE_DYNAMIC_STRING_SCOPE(dynamicStringScopeName) dynamicStringScopeName 46 | #define SIMPLE_DYNAMIC_STRING_SCOPE_CONDITIONAL(dynamicStringScopeName, conditional) dynamicStringScopeName; (conditional) 47 | #define SIMPLE_NAME_SCOPE(scopeName) scopeName 48 | #define SIMPLE_NAME_SCOPE_CONDITIONAL(scopeName, conditional) scopeName; (conditional) 49 | #define SIMPLE_FUNC_SCOPE() 50 | #define SIMPLE_FUNC_SCOPE_CONDITIONAL(conditional) (conditional) 51 | #define SIMPLE_FRAME_END_MARKER() 52 | #endif 53 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DBaseTexture9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DBaseTexture9Hook : public IDirect3DBaseTexture9 6 | { 7 | public: 8 | 9 | IDirect3DBaseTexture9Hook(LPDIRECT3DBASETEXTURE9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1) 10 | { 11 | } 12 | 13 | virtual ~IDirect3DBaseTexture9Hook() 14 | { 15 | realObject = NULL; 16 | parentDevice = NULL; 17 | refCount = 0; 18 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 19 | memset(this, 0x00000000, sizeof(*this) ); 20 | #endif 21 | } 22 | 23 | /*** IUnknown methods ***/ 24 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 25 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 26 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 27 | 28 | /*** IDirect3DResource9 methods ***/ 29 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 30 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) override; 31 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) override; 32 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE FreePrivateData(THIS_ REFGUID refguid) override; 33 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetPriority(THIS_ DWORD PriorityNew) override; 34 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetPriority(THIS) override; 35 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE PreLoad(THIS) override; 36 | virtual COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE GetType(THIS) override; 37 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetLOD(THIS_ DWORD LODNew) override; 38 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetLOD(THIS) override; 39 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetLevelCount(THIS) override; 40 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(THIS_ D3DTEXTUREFILTERTYPE FilterType) override; 41 | virtual COM_DECLSPEC_NOTHROW D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType(THIS) override; 42 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE GenerateMipSubLevels(THIS) override; 43 | 44 | inline LPDIRECT3DBASETEXTURE9 GetUnderlyingBaseTexture(void) const 45 | { 46 | return realObject; 47 | } 48 | 49 | protected: 50 | LPDIRECT3DBASETEXTURE9 realObject; 51 | IDirect3DDevice9Hook* parentDevice; 52 | unsigned __int64 refCount; 53 | }; 54 | -------------------------------------------------------------------------------- /Software_d3d9/FixedFuncEmu/FFPS/Include/FFPS_ArgumentSelector.fxh: -------------------------------------------------------------------------------- 1 | #define MAKE_ARGSELECTOR_NAME(x) ArgumentSelect##x 2 | 3 | inline const float4 MAKE_ARGSELECTOR_NAME(ARGNAME)(in const float4 diffuse, in const float4 specular, 4 | in const float4 CURRENT, in const float4 currentStageTexture, in const float4 currentStateConstant, in const float4 TEMP, in const float TextureLumaScale) 5 | { 6 | #if ( (ARG) & (D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT) ) == 0 7 | #if (ARG) == D3DTA_DIFFUSE 8 | return diffuse; 9 | #elif (ARG) == D3DTA_CURRENT 10 | #if STAGE_NUM == 0 11 | return diffuse; 12 | #else 13 | return CURRENT; 14 | #endif 15 | #elif (ARG) == D3DTA_TEXTURE 16 | #if STAGE_NUM == 0 17 | return currentStageTexture; 18 | #else 19 | return currentStageTexture * TextureLumaScale; 20 | #endif 21 | #elif (ARG) == D3DTA_TFACTOR 22 | return TFACTOR; 23 | #elif (ARG) == D3DTA_SPECULAR 24 | return specular; 25 | #elif (ARG) == D3DTA_TEMP 26 | return TEMP; 27 | #elif (ARG) == D3DTA_CONSTANT 28 | return currentStateConstant; 29 | #else 30 | #error ERROR: Invalid D3DTA type passed to ArgumentSelect! 31 | #endif 32 | #else // #if (ARG & (D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT) ) == 0 33 | float4 arg; 34 | #if ( (ARG) & D3DTA_SELECTMASK) == D3DTA_DIFFUSE 35 | arg = diffuse; 36 | #elif ( (ARG) & D3DTA_SELECTMASK) == D3DTA_CURRENT 37 | #if STAGE_NUM == 0 38 | arg = diffuse; 39 | #else 40 | arg = CURRENT; 41 | #endif 42 | #elif ( (ARG) & D3DTA_SELECTMASK) == D3DTA_TEXTURE 43 | arg = currentStageTexture; 44 | #elif ( (ARG) & D3DTA_SELECTMASK) == D3DTA_TFACTOR 45 | arg = TFACTOR; 46 | #elif ( (ARG) & D3DTA_SELECTMASK) == D3DTA_SPECULAR 47 | arg = specular; 48 | #elif ( (ARG) & D3DTA_SELECTMASK) == D3DTA_TEMP 49 | arg = TEMP; 50 | #if ARG == (D3DTA_ALPHAREPLICATE | D3DTA_TEMP) // This is some crazy strange undocumented behavior. 51 | arg.a = 1.0f; 52 | #endif // #if ARG == (D3DTA_ALPHAREPLICATE | TEMP) 53 | #elif ( (ARG) & D3DTA_SELECTMASK) == D3DTA_CONSTANT 54 | arg = currentStateConstant; 55 | #else 56 | #error ERROR: Invalid D3DTA type passed to ArgumentSelect! 57 | #endif 58 | 59 | // Note that the order of D3DTA_ALPHAREPLICATE and D3DTA_COMPLEMENT doesn't matter because these two modifiers act commutatively with one another: 60 | // args = 1.0 - args.aaaa; 61 | // is the same as: 62 | // args = args.a; args = 1.0f - args; 63 | #if ( ( (ARG) & (D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT) ) == (D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT) ) 64 | float alphaArg = arg.a; 65 | alphaArg = 1.0f - alphaArg; 66 | arg.rgba = float4(alphaArg, alphaArg, alphaArg, alphaArg); 67 | #elif ( ( (ARG) & D3DTA_ALPHAREPLICATE) != 0) 68 | arg = arg.aaaa; 69 | #elif ( ( (ARG) & D3DTA_COMPLEMENT) != 0) 70 | arg = 1.0f - arg; 71 | #endif 72 | return arg; 73 | #endif // #if (ARG & (D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT) ) == 0 74 | } 75 | 76 | #undef MAKE_ARGSELECTOR_NAME 77 | #undef ARG 78 | #undef ARGNAME 79 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DSwapChain9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DSwapChain9Hook : public IDirect3DSwapChain9 6 | { 7 | public: 8 | IDirect3DSwapChain9Hook(LPDIRECT3DSWAPCHAIN9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1), backBuffer(NULL), tempBlitSurface(NULL) 9 | { 10 | #ifdef _DEBUG 11 | memcpy(&PresentParameters, &realObject->PresentParameters, (char*)&realObject - (char*)&PresentParameters); 12 | #endif 13 | 14 | // Init the gamma ramp to its default value: 15 | InitDefaultGammaRamp(); 16 | } 17 | 18 | virtual ~IDirect3DSwapChain9Hook() 19 | { 20 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 21 | memset(this, 0x00000000, sizeof(*this) ); 22 | #endif 23 | } 24 | 25 | void InitializeSwapChain(const D3DPRESENT_PARAMETERS& _PresentParameters, IDirect3DSurface9Hook* swapChainBackBuffer); 26 | 27 | /*** IUnknown methods ***/ 28 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 29 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 30 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 31 | 32 | /*** IDirect3DSwapChain9 methods ***/ 33 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Present(THIS_ CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion,DWORD dwFlags) override; 34 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetFrontBufferData(THIS_ IDirect3DSurface9* pDestSurface) override; 35 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetBackBuffer(THIS_ UINT iBackBuffer,D3DBACKBUFFER_TYPE Type,IDirect3DSurface9** ppBackBuffer) override; 36 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetRasterStatus(THIS_ D3DRASTER_STATUS* pRasterStatus) override; 37 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDisplayMode(THIS_ D3DDISPLAYMODE* pMode) override; 38 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 39 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPresentParameters(THIS_ D3DPRESENT_PARAMETERS* pPresentationParameters) override; 40 | 41 | inline LPDIRECT3DSWAPCHAIN9 GetUnderlyingSwapChain(void) const 42 | { 43 | return realObject; 44 | } 45 | 46 | void SetGammaRamp(DWORD Flags, CONST D3DGAMMARAMP* pRamp); 47 | void GetGammaRamp(D3DGAMMARAMP* pRamp); 48 | 49 | void InitDefaultGammaRamp(void); 50 | 51 | void InitBlitSurface(void); 52 | 53 | const D3DDISPLAYMODE& GetInternalDisplayMode(void) const 54 | { 55 | return InternalDisplayMode; 56 | } 57 | 58 | IDirect3DSurface9Hook* const GetInternalBackBuffer(void) 59 | { 60 | return backBuffer; 61 | } 62 | 63 | protected: 64 | LPDIRECT3DSWAPCHAIN9 realObject; 65 | IDirect3DDevice9Hook* parentDevice; 66 | unsigned __int64 refCount; 67 | 68 | // Blit from the software backbuffer to the hardware backbuffer: 69 | void InternalBlit(void); 70 | 71 | IDirect3DSurface9Hook* backBuffer; 72 | D3DPRESENT_PARAMETERS InternalPresentParameters; 73 | D3DDISPLAYMODE InternalDisplayMode; 74 | D3DGAMMARAMP gammaRamp; 75 | LPDIRECT3DSURFACE9 tempBlitSurface; 76 | }; 77 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3D9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "d3d9include.h" 4 | 5 | #include // for offsetof 6 | 7 | #include "IDirect3DDevice9Hook.h" 8 | 9 | class IDirect3D9Hook : public IDirect3D9 10 | { 11 | public: 12 | IDirect3D9Hook(LPDIRECT3D9 _d3d9) : d3d9(_d3d9), refCount(1) 13 | { 14 | #ifdef _DEBUG 15 | memcpy(&Version, &d3d9->Version, (char*)&d3d9 - (char*)&Version); 16 | #endif 17 | } 18 | 19 | inline LPDIRECT3D9 GetUnderlyingD3D9(void) const 20 | { 21 | return d3d9; 22 | } 23 | 24 | virtual ~IDirect3D9Hook() 25 | { 26 | d3d9 = NULL; 27 | refCount = 0; 28 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 29 | memset(this, 0x00000000, sizeof(*this) ); 30 | #endif 31 | } 32 | 33 | /*** IUnknown methods ***/ 34 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 35 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 36 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 37 | 38 | /*** IDirect3D9 methods ***/ 39 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(THIS_ void* pInitializeFunction) override; 40 | virtual COM_DECLSPEC_NOTHROW UINT STDMETHODCALLTYPE GetAdapterCount(THIS) override; 41 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier) override; 42 | virtual COM_DECLSPEC_NOTHROW UINT STDMETHODCALLTYPE GetAdapterModeCount(THIS_ UINT Adapter,D3DFORMAT Format) override; 43 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE EnumAdapterModes(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode) override; 44 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode) override; 45 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CheckDeviceType(THIS_ UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed) override; 46 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CheckDeviceFormat(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat) override; 47 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels) override; 48 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat) override; 49 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CheckDeviceFormatConversion(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat) override; 50 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDeviceCaps(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps) override; 51 | virtual COM_DECLSPEC_NOTHROW HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(THIS_ UINT Adapter) override; 52 | 53 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CreateDevice(THIS_ UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, 54 | DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) override; 55 | 56 | protected: 57 | LPDIRECT3D9 d3d9; 58 | unsigned __int64 refCount; 59 | }; 60 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVolume9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DVolume9Hook.h" 4 | 5 | /*** IUnknown methods ***/ 6 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 7 | { 8 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 9 | if (ret == NOERROR) 10 | { 11 | *ppvObj = this; 12 | AddRef(); 13 | } 14 | return ret; 15 | } 16 | 17 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVolume9Hook::AddRef(THIS) 18 | { 19 | ULONG ret = realObject->AddRef(); 20 | ++refCount; 21 | return ret; 22 | } 23 | 24 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVolume9Hook::Release(THIS) 25 | { 26 | ULONG ret = realObject->Release(); 27 | if (--refCount == 0) 28 | { 29 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 30 | char printBuffer[128] = {0}; 31 | #pragma warning(push) 32 | #pragma warning(disable:4996) 33 | sprintf(printBuffer, "Fully releasing hooked Volume Surface %p\n", this); 34 | #pragma warning(pop) 35 | OutputDebugStringA(printBuffer); 36 | #endif 37 | delete this; 38 | } 39 | return ret; 40 | } 41 | 42 | /*** IDirect3DVolume9 methods ***/ 43 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 44 | { 45 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 46 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 47 | if (FAILED(ret) ) 48 | { 49 | *ppDevice = NULL; 50 | return ret; 51 | } 52 | 53 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 54 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 55 | { 56 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 57 | } 58 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 59 | 60 | *ppDevice = parentDevice; 61 | return ret; 62 | } 63 | 64 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) 65 | { 66 | HRESULT ret = realObject->SetPrivateData(refguid, pData, SizeOfData, Flags); 67 | return ret; 68 | } 69 | 70 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) 71 | { 72 | HRESULT ret = realObject->GetPrivateData(refguid, pData, pSizeOfData); 73 | return ret; 74 | } 75 | 76 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::FreePrivateData(THIS_ REFGUID refguid) 77 | { 78 | HRESULT ret = realObject->FreePrivateData(refguid); 79 | return ret; 80 | } 81 | 82 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::GetContainer(THIS_ REFIID riid,void** ppContainer) 83 | { 84 | HRESULT ret = realObject->GetContainer(riid, ppContainer); 85 | return ret; 86 | } 87 | 88 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::GetDesc(THIS_ D3DVOLUME_DESC *pDesc) 89 | { 90 | HRESULT ret = realObject->GetDesc(pDesc); 91 | return ret; 92 | } 93 | 94 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::LockBox(THIS_ D3DLOCKED_BOX * pLockedVolume,CONST D3DBOX* pBox,DWORD Flags) 95 | { 96 | HRESULT ret = realObject->LockBox(pLockedVolume, pBox, Flags); 97 | return ret; 98 | } 99 | 100 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolume9Hook::UnlockBox(THIS) 101 | { 102 | HRESULT ret = realObject->UnlockBox(); 103 | return ret; 104 | } 105 | -------------------------------------------------------------------------------- /Software_d3d9/DitherTables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Some 4x4 tables for performing color dithering before being written to rendertargets 4 | 5 | static const float uniform2bit[4][4] = 6 | { 7 | { (0.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (8.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (2.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (10.0f / 16.0f - 8.0f / 16.0f) / 4.0f }, 8 | { (12.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (4.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (14.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (6.0f / 16.0f - 8.0f / 16.0f) / 4.0f }, 9 | { (3.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (11.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (1.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (9.0f / 16.0f - 8.0f / 16.0f) / 4.0f }, 10 | { (15.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (7.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (13.0f / 16.0f - 8.0f / 16.0f) / 4.0f, (5.0f / 16.0f - 8.0f / 16.0f) / 4.0f } 11 | }; 12 | 13 | static const float uniform3bit[4][4] = 14 | { 15 | { (0.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (8.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (2.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (10.0f / 16.0f - 8.0f / 16.0f) / 8.0f }, 16 | { (12.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (4.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (14.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (6.0f / 16.0f - 8.0f / 16.0f) / 8.0f }, 17 | { (3.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (11.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (1.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (9.0f / 16.0f - 8.0f / 16.0f) / 8.0f }, 18 | { (15.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (7.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (13.0f / 16.0f - 8.0f / 16.0f) / 8.0f, (5.0f / 16.0f - 8.0f / 16.0f) / 8.0f } 19 | }; 20 | 21 | static const float uniform4bit[4][4] = 22 | { 23 | { (0.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (8.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (2.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (10.0f / 16.0f - 8.0f / 16.0f) / 16.0f }, 24 | { (12.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (4.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (14.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (6.0f / 16.0f - 8.0f / 16.0f) / 16.0f }, 25 | { (3.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (11.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (1.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (9.0f / 16.0f - 8.0f / 16.0f) / 16.0f }, 26 | { (15.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (7.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (13.0f / 16.0f - 8.0f / 16.0f) / 16.0f, (5.0f / 16.0f - 8.0f / 16.0f) / 16.0f } 27 | }; 28 | 29 | static const float uniform5bit[4][4] = 30 | { 31 | { (0.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (8.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (2.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (10.0f / 16.0f - 8.0f / 16.0f) / 32.0f }, 32 | { (12.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (4.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (14.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (6.0f / 16.0f - 8.0f / 16.0f) / 32.0f }, 33 | { (3.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (11.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (1.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (9.0f / 16.0f - 8.0f / 16.0f) / 32.0f }, 34 | { (15.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (7.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (13.0f / 16.0f - 8.0f / 16.0f) / 32.0f, (5.0f / 16.0f - 8.0f / 16.0f) / 32.0f } 35 | }; 36 | 37 | static const float uniform6bit[4][4] = 38 | { 39 | { (0.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (8.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (2.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (10.0f / 16.0f - 8.0f / 16.0f) / 64.0f }, 40 | { (12.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (4.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (14.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (6.0f / 16.0f - 8.0f / 16.0f) / 64.0f }, 41 | { (3.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (11.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (1.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (9.0f / 16.0f - 8.0f / 16.0f) / 64.0f }, 42 | { (15.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (7.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (13.0f / 16.0f - 8.0f / 16.0f) / 64.0f, (5.0f / 16.0f - 8.0f / 16.0f) / 64.0f } 43 | }; 44 | -------------------------------------------------------------------------------- /Software_d3d9/FixedFunctionToShader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | extern HINSTANCE hLThisDLL; 6 | 7 | #ifndef NO_CACHING_FIXED_FUNCTION_SHADERS 8 | typedef unsigned __int64 FixedFunctionStateHash; 9 | 10 | template 11 | static inline void HashContinue(FixedFunctionStateHash& hash, const T data) 12 | { 13 | const unsigned rotateAmount = (sizeof(T) * 8) % (sizeof(FixedFunctionStateHash) * 8); 14 | if (rotateAmount != 0) 15 | hash = _rotl64(hash, rotateAmount); 16 | hash ^= data; 17 | } 18 | 19 | // Need an explicit template specialization here because operator^= is not defined for floats: 20 | template <> 21 | static inline void HashContinue(FixedFunctionStateHash& hash, const float data) 22 | { 23 | const unsigned rotateAmount = (sizeof(float) * 8) % (sizeof(FixedFunctionStateHash) * 8); 24 | if (rotateAmount != 0) 25 | hash = _rotl64(hash, rotateAmount); 26 | const DWORD dwFlt = *(const DWORD* const)&data; 27 | hash ^= dwFlt; 28 | } 29 | 30 | template <> 31 | static inline void HashContinue(FixedFunctionStateHash& hash, const BOOL data) 32 | { 33 | const unsigned rotateAmount = 1; 34 | hash = _rotl64(hash, rotateAmount); 35 | if (data) 36 | hash ^= 0x1; 37 | } 38 | 39 | template <> 40 | static inline void HashContinue(FixedFunctionStateHash& hash, const bool data) 41 | { 42 | const unsigned rotateAmount = 1; 43 | hash = _rotl64(hash, rotateAmount); 44 | if (data) 45 | hash ^= 0x1; 46 | } 47 | 48 | template 49 | static inline void HashStruct(FixedFunctionStateHash& hash, const T& data) 50 | { 51 | const unsigned rotateAmount = (sizeof(T) * 8) % (sizeof(FixedFunctionStateHash) * 8); 52 | if (rotateAmount != 0) 53 | hash = _rotl64(hash, rotateAmount); 54 | 55 | const unsigned char* const uData = (const unsigned char* const)&data; 56 | for (unsigned x = 0; x < sizeof(T) / sizeof(unsigned char); ++x) 57 | { 58 | hash = _rotl64(hash, sizeof(unsigned char) * 8); 59 | hash ^= uData[x]; 60 | } 61 | } 62 | 63 | // Forward-declares: 64 | const FixedFunctionStateHash HashVertexState(const DeviceState& state); 65 | const FixedFunctionStateHash HashPixelState(const DeviceState& state); 66 | 67 | #endif // #ifndef NO_CACHING_FIXED_FUNCTION_SHADERS 68 | 69 | void FixedFunctionStateToVertexShader(const DeviceState& state, IDirect3DVertexShader9Hook** const outVertShader, IDirect3DDevice9Hook* const dev); 70 | void FixedFunctionStateToPixelShader(const DeviceState& state, IDirect3DPixelShader9Hook** const outPixelShader, IDirect3DDevice9Hook* const dev); 71 | void SetFixedFunctionVertexShaderState(const DeviceState& state, IDirect3DDevice9Hook* const dev); 72 | void SetFixedFunctionPixelShaderState(const DeviceState& state, IDirect3DDevice9Hook* const dev); 73 | void BuildVertexShader(const DeviceState& state, IDirect3DDevice9Hook* const dev, IDirect3DVertexShader9Hook** const outNewShader); 74 | void BuildPixelShader(const DeviceState& state, IDirect3DDevice9Hook* const dev, IDirect3DPixelShader9Hook** const outNewShader); 75 | 76 | struct D3DXIncludeHandler : public ID3DXInclude 77 | { 78 | STDMETHOD(Open)(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes); 79 | STDMETHOD(Close)(THIS_ LPCVOID pData); 80 | 81 | virtual ~D3DXIncludeHandler() 82 | { 83 | } 84 | 85 | static inline D3DXIncludeHandler* const GetGlobalIncludeHandlerSingleton() 86 | { 87 | return &globalIncludeHandlerSingleton; 88 | } 89 | 90 | private: 91 | static D3DXIncludeHandler globalIncludeHandlerSingleton; 92 | }; 93 | 94 | // The resourceName passed in may also be a string from the MAKEINTRESOURCEA() macro. 95 | // Returns NULL if the resource cannot be found! 96 | const void* const GetShaderResourceFile(const char* const resourceNameA, unsigned& outFoundResourceSize, const char* const resourceCategory = "HLSL"); 97 | -------------------------------------------------------------------------------- /Software_d3d9/SemanticMappings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GlobalToggles.h" 4 | #include "IDirect3DDevice9Hook.h" 5 | 6 | // Mapping from vertex declarations and vertex streams to vertex shader inputs (or from vertex streams to pixel shader inputs for POSITIONT vert decls): 7 | struct DeclarationSemanticMapping 8 | { 9 | DeclarationSemanticMapping() 10 | { 11 | ClearSemanticMapping(); 12 | } 13 | 14 | inline void ClearSemanticMapping() 15 | { 16 | for (unsigned x = 0; x <= MAXD3DDECLUSAGE; ++x) 17 | for (unsigned y = 0; y <= MAXD3DDECLUSAGEINDEX; ++y) 18 | vals[x][y] = NULL; 19 | } 20 | 21 | // Computes a mapping between vertex streams and vertex shader inputs 22 | void ComputeMappingVS(const IDirect3DVertexDeclaration9Hook* const vertexDecl, const IDirect3DVertexShader9Hook* const vertexShader); 23 | 24 | // Computes a mapping between vertex shader outputs and the postransformed vertex declaration 25 | void ComputeMappingVStoPS(const IDirect3DVertexDeclaration9Hook* const vertexDecl, const IDirect3DVertexShader9Hook* const vertexShader); 26 | 27 | // Computes a mapping between vertex streams and pixel shader inputs (for POSITIONT decls) 28 | void ComputeMappingPS(const IDirect3DVertexDeclaration9Hook* const vertexDecl, const IDirect3DPixelShader9Hook* const pixelShader); 29 | 30 | // Returns the address of the register within the input vertex stream given the usage and index in the map 31 | inline const D3DXVECTOR4* const GetAddress(const D3DDECLUSAGE usage, const unsigned index, const D3DXVECTOR4* const baseAddr) const 32 | { 33 | const DebuggableD3DVERTEXELEMENT9* const offsetElement = vals[usage][index]; 34 | return baseAddr + offsetElement->Offset; 35 | } 36 | 37 | const DebuggableD3DVERTEXELEMENT9* vals[MAXD3DDECLUSAGE + 1][MAXD3DDECLUSAGEINDEX + 1]; 38 | }; 39 | 40 | // Mapping from vertex shader outputs to pixel shader inputs: 41 | struct VStoPSMapping 42 | { 43 | VStoPSMapping() 44 | { 45 | ClearSemanticMapping(); 46 | } 47 | 48 | inline void ClearSemanticMapping() 49 | { 50 | memset(this, 0, sizeof(*this) ); 51 | } 52 | 53 | void ComputeMappingVSToPS(const IDirect3DVertexShader9Hook* const vs, const IDirect3DPixelShader9Hook* const ps); 54 | 55 | // VS1/VS2 to PS1: 56 | // Directly go across -> 2colors + 6texcoords 57 | void ComputeMappingVS2ToPS1(const IDirect3DVertexShader9Hook* const vs, const IDirect3DPixelShader9Hook* const ps); 58 | 59 | // VS1/VS2 to PS2: 60 | // Directly go across -> 2colors + 8texcoords 61 | void ComputeMappingVS2ToPS2(const IDirect3DVertexShader9Hook* const vs, const IDirect3DPixelShader9Hook* const ps); 62 | 63 | // VS1/VS2 to PS3: 64 | // Use semantics to map from 2colors + 8texcoords to 10 PS input registers 65 | void ComputeMappingVS2ToPS3(const IDirect3DVertexShader9Hook* const vs, const IDirect3DPixelShader9Hook* const ps); 66 | 67 | // VS3 to PS2: 68 | // Map from 12 VS output registers to 2colors + 6texcoords (anything that isn't a color goes into texcoords) 69 | void ComputeMappingVS3ToPS1(const IDirect3DVertexShader9Hook* const vs, const IDirect3DPixelShader9Hook* const ps); 70 | 71 | // VS3 to PS2: 72 | // Use semantics to map from 12 VS output registers to 2colors + 8texcoords (anything that isn't a color goes into texcoords) 73 | void ComputeMappingVS3ToPS2(const IDirect3DVertexShader9Hook* const vs, const IDirect3DPixelShader9Hook* const ps); 74 | 75 | // VS3 to PS3: 76 | // Map across non-rasterizer VS outputs (no POSITIONT, no FOG, no PSIZE, etc.) 77 | void ComputeMappingVS3ToPS3(const IDirect3DVertexShader9Hook* const vs, const IDirect3DPixelShader9Hook* const ps); 78 | 79 | union _psInputRegistersUnion 80 | { 81 | struct _ps_2_0_registers 82 | { 83 | unsigned colors[D3DMCS_COLOR2]; // 2 colors 84 | unsigned texCoords[D3DDP_MAXTEXCOORD]; // 8 texcoords 85 | } ps_2_0_registers; 86 | 87 | struct _ps_3_0_registers 88 | { 89 | unsigned inputs[10]; // 10 pixel shader inputs 90 | } ps_3_0_registers; 91 | } psInputRegistersUnion; 92 | }; 93 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DResource9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DResource9Hook.h" 4 | 5 | /*** IUnknown methods ***/ 6 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DResourceHook9::QueryInterface(THIS_ REFIID riid, void** ppvObj) 7 | { 8 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 9 | if (ret == NOERROR) 10 | { 11 | *ppvObj = this; 12 | AddRef(); 13 | } 14 | return ret; 15 | } 16 | 17 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DResourceHook9::AddRef(THIS) 18 | { 19 | ULONG ret = realObject->AddRef(); 20 | ++refCount; 21 | return ret; 22 | } 23 | 24 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DResourceHook9::Release(THIS) 25 | { 26 | ULONG ret = realObject->Release(); 27 | if (--refCount == 0) 28 | { 29 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 30 | char printBuffer[128] = {0}; 31 | #pragma warning(push) 32 | #pragma warning(disable:4996) 33 | sprintf(printBuffer, "Fully releasing hooked Base Resource %p\n", this); 34 | #pragma warning(pop) 35 | OutputDebugStringA(printBuffer); 36 | #endif 37 | delete this; 38 | } 39 | return ret; 40 | } 41 | 42 | /*** IDirect3DResource9 methods ***/ 43 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DResourceHook9::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 44 | { 45 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 46 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 47 | if (FAILED(ret) ) 48 | { 49 | *ppDevice = NULL; 50 | return ret; 51 | } 52 | 53 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 54 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 55 | { 56 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 57 | } 58 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 59 | 60 | *ppDevice = parentDevice; 61 | return ret; 62 | } 63 | 64 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DResourceHook9::SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) 65 | { 66 | HRESULT ret = realObject->SetPrivateData(refguid, pData, SizeOfData, Flags); 67 | return ret; 68 | } 69 | 70 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DResourceHook9::GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) 71 | { 72 | HRESULT ret = realObject->GetPrivateData(refguid, pData, pSizeOfData); 73 | return ret; 74 | } 75 | 76 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DResourceHook9::FreePrivateData(THIS_ REFGUID refguid) 77 | { 78 | HRESULT ret = realObject->FreePrivateData(refguid); 79 | return ret; 80 | } 81 | 82 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DResourceHook9::SetPriority(THIS_ DWORD PriorityNew) 83 | { 84 | DWORD ret = realObject->SetPriority(PriorityNew); 85 | return ret; 86 | } 87 | 88 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DResourceHook9::GetPriority(THIS) 89 | { 90 | DWORD ret = realObject->GetPriority(); 91 | return ret; 92 | } 93 | 94 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DResourceHook9::PreLoad(THIS) 95 | { 96 | realObject->PreLoad(); 97 | } 98 | 99 | COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE IDirect3DResourceHook9::GetType(THIS) 100 | { 101 | D3DRESOURCETYPE ret = realObject->GetType(); 102 | return ret; 103 | } 104 | 105 | BYTE* const PageAllocWithNoAccessPage(const unsigned lenBytes) 106 | { 107 | BYTE* voidBytes = NULL; 108 | BYTE* const pageAddress = (BYTE* const)VirtualAlloc(NULL, lenBytes + 4096, MEM_RESERVE, PAGE_NOACCESS); 109 | if (pageAddress) 110 | { 111 | if (!VirtualAlloc(pageAddress, lenBytes, MEM_COMMIT, PAGE_READWRITE) ) 112 | { 113 | __debugbreak(); // Can't alloc our new surface 114 | VirtualFree(pageAddress, 0, MEM_RELEASE); 115 | } 116 | 117 | if (lenBytes % 4096 == 0) 118 | voidBytes = pageAddress; 119 | else 120 | voidBytes = pageAddress + (4096 - (lenBytes % 4096) ); 121 | 122 | return voidBytes; 123 | } 124 | if (!voidBytes) 125 | { 126 | __debugbreak(); // Can't alloc our new surface! 127 | } 128 | 129 | return NULL; 130 | } 131 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DCubeTexture9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DCubeTexture9Hook : public IDirect3DCubeTexture9 6 | { 7 | public: 8 | IDirect3DCubeTexture9Hook(LPDIRECT3DCUBETEXTURE9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1) 9 | { 10 | #ifdef _DEBUG 11 | memcpy(&Name, &realObject->Name, (char*)&realObject - (char*)&Name); 12 | #endif 13 | } 14 | 15 | virtual ~IDirect3DCubeTexture9Hook() 16 | { 17 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 18 | memset(this, 0x00000000, sizeof(*this) ); 19 | #endif 20 | } 21 | 22 | /*** IUnknown methods ***/ 23 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 24 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 25 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 26 | 27 | /*** IDirect3DBaseTexture9 methods ***/ 28 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 29 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) override; 30 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) override; 31 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE FreePrivateData(THIS_ REFGUID refguid) override; 32 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetPriority(THIS_ DWORD PriorityNew) override; 33 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetPriority(THIS) override; 34 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE PreLoad(THIS) override; 35 | virtual COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE GetType(THIS) override; 36 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetLOD(THIS_ DWORD LODNew) override; 37 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetLOD(THIS) override; 38 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetLevelCount(THIS) override; 39 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(THIS_ D3DTEXTUREFILTERTYPE FilterType) override; 40 | virtual COM_DECLSPEC_NOTHROW D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType(THIS) override; 41 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE GenerateMipSubLevels(THIS) override; 42 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetLevelDesc(THIS_ UINT Level,D3DSURFACE_DESC *pDesc) override; 43 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetCubeMapSurface(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level,IDirect3DSurface9** ppCubeMapSurface) override; 44 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE LockRect(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags) override; 45 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE UnlockRect(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level) override; 46 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE AddDirtyRect(THIS_ D3DCUBEMAP_FACES FaceType,CONST RECT* pDirtyRect) override; 47 | 48 | inline LPDIRECT3DCUBETEXTURE9 GetUnderlyingCubeTexture(void) const 49 | { 50 | return realObject; 51 | } 52 | 53 | inline const UINT GetInternalEdgeLength() const 54 | { 55 | return InternalEdgeLength; 56 | } 57 | 58 | inline const D3DFORMAT GetInternalFormat() const 59 | { 60 | return InternalFormat; 61 | } 62 | 63 | const UINT GetInternalMipLevels() const 64 | { 65 | return InternalLevels; 66 | } 67 | 68 | const DebuggableUsage GetInternalUsage() const 69 | { 70 | return InternalUsage; 71 | } 72 | 73 | const D3DPOOL GetInternalPool() const 74 | { 75 | return InternalPool; 76 | } 77 | 78 | void CreateCubeTexture(UINT _EdgeLength, UINT _Levels, DebuggableUsage _Usage, D3DFORMAT _Format, D3DPOOL _Pool); 79 | 80 | protected: 81 | LPDIRECT3DCUBETEXTURE9 realObject; 82 | IDirect3DDevice9Hook* parentDevice; 83 | unsigned __int64 refCount; 84 | 85 | UINT InternalEdgeLength; 86 | UINT InternalLevels; 87 | DebuggableUsage InternalUsage; 88 | D3DFORMAT InternalFormat; 89 | D3DPOOL InternalPool; 90 | }; 91 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVertexShader9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | #include "ShaderAnalysis.h" 5 | 6 | class VShaderEngine; 7 | 8 | class IDirect3DVertexShader9Hook : public IDirect3DVertexShader9 9 | { 10 | public: 11 | IDirect3DVertexShader9Hook(LPDIRECT3DVERTEXSHADER9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1), outPositionRegisterIndex(0), 12 | jitShaderMain(NULL), jitShaderMain4(NULL), triedJit(false) 13 | { 14 | #ifdef _DEBUG 15 | memcpy(&Version, &realObject->Version, (char*)&realObject - (char*)&Version); 16 | #endif 17 | } 18 | 19 | inline LPDIRECT3DVERTEXSHADER9 GetUnderlyingVertexShader(void) const 20 | { 21 | return realObject; 22 | } 23 | 24 | virtual ~IDirect3DVertexShader9Hook(); 25 | 26 | /*** IUnknown methods ***/ 27 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 28 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 29 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 30 | 31 | /*** IDirect3DVertexShader9 methods ***/ 32 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 33 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetFunction(THIS_ void* pData,UINT* pSizeOfData) override; 34 | 35 | void CreateVertexShader(const DWORD* const pFunction); 36 | 37 | inline const ShaderInfo& GetShaderInfo() const 38 | { 39 | return vertexShaderInfo; 40 | } 41 | 42 | inline ShaderInfo& GetModifyShaderInfo() 43 | { 44 | return vertexShaderInfo; 45 | } 46 | 47 | inline const UINT GetOPosRegisterIndex(void) const 48 | { 49 | return outPositionRegisterIndex; 50 | } 51 | 52 | inline const UINT GetOPosOffset_Bytes(void) const 53 | { 54 | return GetOPosRegisterIndex() * sizeof(D3DXVECTOR4); 55 | } 56 | 57 | inline const D3DXVECTOR4& GetPosition(const VS_2_0_OutputRegisters& thisOutputRegisters) const 58 | { 59 | // Uhhhhhh, is this correct? Should we be checking vertex shader versions here before reaching in and grabbing a register? 60 | return ( (const D3DXVECTOR4* const)&thisOutputRegisters)[outPositionRegisterIndex]; 61 | } 62 | 63 | inline D3DXVECTOR4& GetPosition(VS_2_0_OutputRegisters& thisOutputRegisters) const 64 | { 65 | // Uhhhhhh, is this correct? Should we be checking vertex shader versions here before reaching in and grabbing a register? 66 | return ( (D3DXVECTOR4* const)&thisOutputRegisters)[outPositionRegisterIndex]; 67 | } 68 | 69 | inline void GetPosition4(const VS_2_0_OutputRegisters* (&thisOutputRegisters)[4], const D3DXVECTOR4* (&outPositionPtrs)[4]) const 70 | { 71 | // Uhhhhhh, is this correct? Should we be checking vertex shader versions here before reaching in and grabbing a register? 72 | outPositionPtrs[0] = ( (const D3DXVECTOR4* const)thisOutputRegisters[0]) + outPositionRegisterIndex; 73 | outPositionPtrs[1] = ( (const D3DXVECTOR4* const)thisOutputRegisters[1]) + outPositionRegisterIndex; 74 | outPositionPtrs[2] = ( (const D3DXVECTOR4* const)thisOutputRegisters[2]) + outPositionRegisterIndex; 75 | outPositionPtrs[3] = ( (const D3DXVECTOR4* const)thisOutputRegisters[3]) + outPositionRegisterIndex; 76 | } 77 | 78 | inline void GetPosition4(VS_2_0_OutputRegisters* (&thisOutputRegisters)[4], D3DXVECTOR4* (&outPositionPtrs)[4]) const 79 | { 80 | // Uhhhhhh, is this correct? Should we be checking vertex shader versions here before reaching in and grabbing a register? 81 | outPositionPtrs[0] = ( (D3DXVECTOR4* const)thisOutputRegisters[0]) + outPositionRegisterIndex; 82 | outPositionPtrs[1] = ( (D3DXVECTOR4* const)thisOutputRegisters[1]) + outPositionRegisterIndex; 83 | outPositionPtrs[2] = ( (D3DXVECTOR4* const)thisOutputRegisters[2]) + outPositionRegisterIndex; 84 | outPositionPtrs[3] = ( (D3DXVECTOR4* const)thisOutputRegisters[3]) + outPositionRegisterIndex; 85 | } 86 | 87 | void JitLoadShader(); 88 | 89 | protected: 90 | LPDIRECT3DVERTEXSHADER9 realObject; 91 | IDirect3DDevice9Hook* parentDevice; 92 | unsigned __int64 refCount; 93 | 94 | public: 95 | typedef void (__fastcall *VSEntry)(VShaderEngine& ps); 96 | VSEntry jitShaderMain; 97 | VSEntry jitShaderMain4; 98 | 99 | bool triedJit; 100 | protected: 101 | unsigned outPositionRegisterIndex; 102 | 103 | std::vector shaderBytecode; 104 | ShaderInfo vertexShaderInfo; 105 | }; 106 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVolumeTexture9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DVolumeTexture9Hook : public IDirect3DVolumeTexture9 6 | { 7 | public: 8 | IDirect3DVolumeTexture9Hook(LPDIRECT3DVOLUMETEXTURE9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1) 9 | { 10 | #ifdef _DEBUG 11 | memcpy(&Name, &realObject->Name, (char*)&realObject - (char*)&Name); 12 | #endif 13 | } 14 | 15 | virtual ~IDirect3DVolumeTexture9Hook() 16 | { 17 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 18 | memset(this, 0x00000000, sizeof(*this) ); 19 | #endif 20 | } 21 | 22 | /*** IUnknown methods ***/ 23 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 24 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 25 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 26 | 27 | /*** IDirect3DBaseTexture9 methods ***/ 28 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 29 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) override; 30 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) override; 31 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE FreePrivateData(THIS_ REFGUID refguid) override; 32 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetPriority(THIS_ DWORD PriorityNew) override; 33 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetPriority(THIS) override; 34 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE PreLoad(THIS) override; 35 | virtual COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE GetType(THIS) override; 36 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetLOD(THIS_ DWORD LODNew) override; 37 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetLOD(THIS) override; 38 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetLevelCount(THIS) override; 39 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(THIS_ D3DTEXTUREFILTERTYPE FilterType) override; 40 | virtual COM_DECLSPEC_NOTHROW D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType(THIS) override; 41 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE GenerateMipSubLevels(THIS) override; 42 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetLevelDesc(THIS_ UINT Level,D3DVOLUME_DESC *pDesc) override; 43 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetVolumeLevel(THIS_ UINT Level,IDirect3DVolume9** ppVolumeLevel) override; 44 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE LockBox(THIS_ UINT Level,D3DLOCKED_BOX* pLockedVolume,CONST D3DBOX* pBox,DWORD Flags) override; 45 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE UnlockBox(THIS_ UINT Level) override; 46 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE AddDirtyBox(THIS_ CONST D3DBOX* pDirtyBox) override; 47 | 48 | inline LPDIRECT3DVOLUMETEXTURE9 GetUnderlyingVolumeTexture(void) const 49 | { 50 | return realObject; 51 | } 52 | 53 | inline const UINT GetInternalWidth() const 54 | { 55 | return InternalWidth; 56 | } 57 | 58 | inline const UINT GetInternalHeight() const 59 | { 60 | return InternalHeight; 61 | } 62 | 63 | inline const UINT GetInternalDepth() const 64 | { 65 | return InternalDepth; 66 | } 67 | 68 | inline const D3DFORMAT GetInternalFormat() const 69 | { 70 | return InternalFormat; 71 | } 72 | 73 | const UINT GetInternalMipLevels() const 74 | { 75 | return InternalLevels; 76 | } 77 | 78 | const DebuggableUsage GetInternalUsage() const 79 | { 80 | return InternalUsage; 81 | } 82 | 83 | const D3DPOOL GetInternalPool() const 84 | { 85 | return InternalPool; 86 | } 87 | 88 | void CreateVolumeTexture(UINT _Width, UINT _Height, UINT _Depth, UINT _Levels, DebuggableUsage _Usage, D3DFORMAT _Format, D3DPOOL _Pool); 89 | 90 | protected: 91 | LPDIRECT3DVOLUMETEXTURE9 realObject; 92 | IDirect3DDevice9Hook* parentDevice; 93 | unsigned __int64 refCount; 94 | 95 | UINT InternalWidth; 96 | UINT InternalHeight; 97 | UINT InternalDepth; 98 | UINT InternalLevels; 99 | DebuggableUsage InternalUsage; 100 | D3DFORMAT InternalFormat; 101 | D3DPOOL InternalPool; 102 | }; 103 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DBaseTexture9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DBaseTexture9Hook.h" 4 | 5 | /*** IUnknown methods ***/ 6 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 7 | { 8 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 9 | if (ret == NOERROR) 10 | { 11 | *ppvObj = this; 12 | AddRef(); 13 | } 14 | return ret; 15 | } 16 | 17 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::AddRef(THIS) 18 | { 19 | ULONG ret = realObject->AddRef(); 20 | ++refCount; 21 | return ret; 22 | } 23 | 24 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::Release(THIS) 25 | { 26 | ULONG ret = realObject->Release(); 27 | if (--refCount == 0) 28 | { 29 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 30 | char printBuffer[128] = {0}; 31 | #pragma warning(push) 32 | #pragma warning(disable:4996) 33 | sprintf(printBuffer, "Fully releasing hooked Base Texture %p\n", this); 34 | #pragma warning(pop) 35 | OutputDebugStringA(printBuffer); 36 | #endif 37 | delete this; 38 | } 39 | return ret; 40 | } 41 | 42 | /*** IDirect3DResource9 methods ***/ 43 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 44 | { 45 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 46 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 47 | if (FAILED(ret) ) 48 | { 49 | *ppDevice = NULL; 50 | return ret; 51 | } 52 | 53 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 54 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 55 | { 56 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 57 | } 58 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 59 | 60 | *ppDevice = parentDevice; 61 | return ret; 62 | } 63 | 64 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) 65 | { 66 | HRESULT ret = realObject->SetPrivateData(refguid, pData, SizeOfData, Flags); 67 | return ret; 68 | } 69 | 70 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) 71 | { 72 | HRESULT ret = realObject->GetPrivateData(refguid, pData, pSizeOfData); 73 | return ret; 74 | } 75 | 76 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::FreePrivateData(THIS_ REFGUID refguid) 77 | { 78 | HRESULT ret = realObject->FreePrivateData(refguid); 79 | return ret; 80 | } 81 | 82 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::SetPriority(THIS_ DWORD PriorityNew) 83 | { 84 | DWORD ret = realObject->SetPriority(PriorityNew); 85 | return ret; 86 | } 87 | 88 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::GetPriority(THIS) 89 | { 90 | DWORD ret = realObject->GetPriority(); 91 | return ret; 92 | } 93 | 94 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::PreLoad(THIS) 95 | { 96 | realObject->PreLoad(); 97 | } 98 | 99 | COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::GetType(THIS) 100 | { 101 | D3DRESOURCETYPE ret = realObject->GetType(); 102 | return ret; 103 | } 104 | 105 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::SetLOD(THIS_ DWORD LODNew) 106 | { 107 | DWORD ret = realObject->SetLOD(LODNew); 108 | return ret; 109 | } 110 | 111 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::GetLOD(THIS) 112 | { 113 | DWORD ret = realObject->GetLOD(); 114 | return ret; 115 | } 116 | 117 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::GetLevelCount(THIS) 118 | { 119 | DWORD ret = realObject->GetLevelCount(); 120 | return ret; 121 | } 122 | 123 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::SetAutoGenFilterType(THIS_ D3DTEXTUREFILTERTYPE FilterType) 124 | { 125 | HRESULT ret = realObject->SetAutoGenFilterType(FilterType); 126 | return ret; 127 | } 128 | 129 | COM_DECLSPEC_NOTHROW D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::GetAutoGenFilterType(THIS) 130 | { 131 | D3DTEXTUREFILTERTYPE ret = realObject->GetAutoGenFilterType(); 132 | return ret; 133 | } 134 | 135 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DBaseTexture9Hook::GenerateMipSubLevels(THIS) 136 | { 137 | realObject->GenerateMipSubLevels(); 138 | } 139 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVertexDeclaration9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DVertexDeclaration9Hook : public IDirect3DVertexDeclaration9 6 | { 7 | public: 8 | IDirect3DVertexDeclaration9Hook(LPDIRECT3DVERTEXDECLARATION9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1), 9 | inVertexSize(0), outVertexSize(0), foundPositionT0(NULL), skipVertexProcessing(false), hasColor0(false), hasColor1(false) 10 | { 11 | vertDeclAutoCreatedFromFVF.rawFVF_DWORD = 0x00000000; 12 | #ifdef _DEBUG 13 | memcpy(&CreationCallStack, &realObject->CreationCallStack, (char*)&realObject - (char*)&CreationCallStack); 14 | #endif 15 | } 16 | 17 | inline LPDIRECT3DVERTEXDECLARATION9 GetUnderlyingVertexDeclaration(void) const 18 | { 19 | return realObject; 20 | } 21 | 22 | LPDIRECT3DVERTEXDECLARATION9 GetUnderlyingPostTransformVertexDeclaration(void) const 23 | { 24 | return vertShaderOutputDecl; 25 | } 26 | 27 | virtual ~IDirect3DVertexDeclaration9Hook() 28 | { 29 | // TODO: Remove this vertex decl from the FVFToVertDeclCache when it gets fully released 30 | 31 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 32 | memset(this, 0x00000000, sizeof(*this) - (sizeof(elements) + sizeof(vertShaderOutputElements) ) ); 33 | #endif 34 | } 35 | 36 | const std::vector& GetElementsInternal(void) const 37 | { 38 | return elements; 39 | } 40 | 41 | const std::vector& GetOutputElementsInternal(void) const 42 | { 43 | return vertShaderOutputElements; 44 | } 45 | 46 | // Returns true if this vertex decl contains pretransformed vertices 47 | inline const bool SkipVertexProcessing(void) const 48 | { 49 | return skipVertexProcessing; 50 | } 51 | 52 | // This may return NULL in the case that this is not a "pre transformed" vertex decl 53 | inline const DebuggableD3DVERTEXELEMENT9* const GetPositionT0Element(void) const 54 | { 55 | return foundPositionT0; 56 | } 57 | 58 | /*** IUnknown methods ***/ 59 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 60 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 61 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 62 | 63 | /*** IDirect3DVertexDeclaration9 methods ***/ 64 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 65 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDeclaration(THIS_ D3DVERTEXELEMENT9* pElement,UINT* pNumElements) override; 66 | 67 | void CreateVertexDeclaration(const DebuggableD3DVERTEXELEMENT9* const pVertexElements, const debuggableFVF _vertDeclAutoCreatedFromFVF); 68 | 69 | inline const UINT GetVertexSize(void) const 70 | { 71 | return inVertexSize; 72 | } 73 | 74 | inline const UINT GetPostTransformVertexSize(void) const 75 | { 76 | return outVertexSize; 77 | } 78 | 79 | static const UINT GetElementSizeFromType(const D3DDECLTYPE elementType); 80 | 81 | // Returns true if vertex offset is found, otherwise returns false and then vertOffset and streamIndex undefined 82 | const bool GetVertexOffset(unsigned& vertOffset, unsigned& streamIndex, const D3DDECLUSAGE usage, const unsigned usageIndex) const; 83 | 84 | // Returns NULL if no such element is found 85 | const DebuggableD3DVERTEXELEMENT9* const GetVertexElement(const D3DDECLUSAGE usage, const unsigned usageIndex) const; 86 | const DebuggableD3DVERTEXELEMENT9* const GetVertexElementOutput(const D3DDECLUSAGE usage, const unsigned usageIndex) const; 87 | 88 | UINT GetStream0Float4PositionTOffset(void) const; 89 | 90 | inline const bool GetHasCOLOR0(void) const 91 | { 92 | return hasColor0; 93 | } 94 | 95 | inline const bool GetHasCOLOR1(void) const 96 | { 97 | return hasColor1; 98 | } 99 | 100 | protected: 101 | LPDIRECT3DVERTEXDECLARATION9 realObject; 102 | IDirect3DDevice9Hook* parentDevice; 103 | unsigned __int64 refCount; 104 | 105 | // This may be NULL for decl's that don't specify a POSITIONT0 element 106 | const DebuggableD3DVERTEXELEMENT9* foundPositionT0; 107 | 108 | // This is the case if someone passes in an element with POSITIONT in it 109 | bool skipVertexProcessing; 110 | 111 | // These two bools determine if the COLOR0 and COLOR1 semantics are present for this vertex decl 112 | bool hasColor0; 113 | bool hasColor1; 114 | 115 | debuggableFVF vertDeclAutoCreatedFromFVF; 116 | 117 | unsigned inVertexSize; 118 | unsigned outVertexSize; 119 | 120 | LPDIRECT3DVERTEXDECLARATION9 vertShaderOutputDecl; 121 | 122 | std::vector elements; 123 | std::vector vertShaderOutputElements; 124 | 125 | void ComputeVertexSizes(); 126 | }; 127 | -------------------------------------------------------------------------------- /Software_d3d9/FixedFunctionToShader.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FixedFunctionToShader.h" 4 | #include "IDirect3DVertexShader9Hook.h" 5 | #include "IDirect3DPixelShader9Hook.h" 6 | #include "GlobalToggles.h" 7 | #include // for std::vector 8 | #include // for std::map 9 | #include "resource.h" 10 | 11 | // Note: There's some good tidbits of information on this page: https://docs.microsoft.com/en-us/windows-hardware/drivers/display/converting-the-direct3d-fixed-function-state 12 | 13 | /*static*/ D3DXIncludeHandler D3DXIncludeHandler::globalIncludeHandlerSingleton; 14 | 15 | #ifndef NO_CACHING_FIXED_FUNCTION_SHADERS 16 | // These maps map from device state hashes into shaders: 17 | static std::map vertShadersHashMap; 18 | static std::map pixelShadersHashMap; 19 | #endif // NO_CACHING_FIXED_FUNCTION_SHADERS 20 | 21 | DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE D3DXIncludeHandler::Open(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) 22 | { 23 | UNREFERENCED_PARAMETER(pParentData); 24 | UNREFERENCED_PARAMETER(IncludeType); 25 | 26 | unsigned resourceSize = 0; 27 | const void* includeFileBytes = GetShaderResourceFile(pFileName, resourceSize); 28 | if (includeFileBytes != NULL) 29 | { 30 | *ppData = includeFileBytes; 31 | *pBytes = resourceSize; 32 | return S_OK; 33 | } 34 | else 35 | return E_FAIL; 36 | } 37 | 38 | DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE D3DXIncludeHandler::Close(THIS_ LPCVOID pData) 39 | { 40 | UNREFERENCED_PARAMETER(pData); 41 | 42 | // We don't have to do anything on close, so this is okay! 43 | return S_OK; 44 | } 45 | 46 | // The resourceName passed in may also be a string from the MAKEINTRESOURCEA() macro. 47 | // Returns NULL if the resource cannot be found! 48 | const void* const GetShaderResourceFile(const char* const resourceNameA, unsigned& outFoundResourceSize, const char* const resourceCategory/* = "HLSL"*/) 49 | { 50 | HRSRC hlslResource = FindResourceA(hLThisDLL, resourceNameA, resourceCategory); 51 | if (hlslResource) 52 | { 53 | HGLOBAL loadedResource = LoadResource(hLThisDLL, hlslResource); 54 | if (loadedResource) 55 | { 56 | const unsigned resourceSize = SizeofResource(hLThisDLL, hlslResource); 57 | if (resourceSize > 0) 58 | { 59 | const void* const resourceBytes = LockResource(loadedResource); 60 | if (resourceBytes) 61 | { 62 | outFoundResourceSize = resourceSize; 63 | return resourceBytes; 64 | } 65 | } 66 | } 67 | } 68 | outFoundResourceSize = 0; 69 | return NULL; 70 | } 71 | 72 | void FixedFunctionStateToVertexShader(const DeviceState& state, IDirect3DVertexShader9Hook** const outVertShader, IDirect3DDevice9Hook* const dev) 73 | { 74 | #ifdef _DEBUG 75 | if (!outVertShader) 76 | { 77 | __debugbreak(); 78 | } 79 | #endif 80 | 81 | #ifndef NO_CACHING_FIXED_FUNCTION_SHADERS 82 | const FixedFunctionStateHash stateHash = HashVertexState(state); 83 | 84 | // If we can match the device state to a shader (should happen every time after the first) then just return that shader 85 | const std::map::const_iterator it = vertShadersHashMap.find(stateHash); 86 | if (it != vertShadersHashMap.end() ) 87 | { 88 | *outVertShader = it->second; 89 | return; 90 | } 91 | #endif // NO_CACHING_FIXED_FUNCTION_SHADERS 92 | 93 | // Construct new vertex shader from device state 94 | IDirect3DVertexShader9Hook* newVertShader = NULL; 95 | BuildVertexShader(state, dev, &newVertShader); 96 | 97 | #ifndef NO_CACHING_FIXED_FUNCTION_SHADERS 98 | // Insert new vertex shader into vert shaders hash map 99 | vertShadersHashMap.insert(std::make_pair(stateHash, newVertShader) ); 100 | #endif // NO_CACHING_FIXED_FUNCTION_SHADERS 101 | 102 | *outVertShader = newVertShader; 103 | } 104 | 105 | void FixedFunctionStateToPixelShader(const DeviceState& state, IDirect3DPixelShader9Hook** const outPixelShader, IDirect3DDevice9Hook* const dev) 106 | { 107 | #ifdef _DEBUG 108 | if (!outPixelShader) 109 | { 110 | __debugbreak(); 111 | } 112 | #endif 113 | 114 | #ifndef NO_CACHING_FIXED_FUNCTION_SHADERS 115 | const FixedFunctionStateHash stateHash = HashPixelState(state); 116 | 117 | // If we can match the device state to a shader (should happen every time after the first) then just return that shader 118 | const std::map::const_iterator it = pixelShadersHashMap.find(stateHash); 119 | if (it != pixelShadersHashMap.end() ) 120 | { 121 | *outPixelShader = it->second; 122 | return; 123 | } 124 | #endif // NO_CACHING_FIXED_FUNCTION_SHADERS 125 | 126 | // Construct new pixel shader from device state 127 | IDirect3DPixelShader9Hook* newPixelShader = NULL; 128 | BuildPixelShader(state, dev, &newPixelShader); 129 | 130 | #ifndef NO_CACHING_FIXED_FUNCTION_SHADERS 131 | // Insert new pixel shader into pixel shaders hash map 132 | pixelShadersHashMap.insert(std::make_pair(stateHash, newPixelShader) ); 133 | #endif // NO_CACHING_FIXED_FUNCTION_SHADERS 134 | 135 | *outPixelShader = newPixelShader; 136 | } 137 | -------------------------------------------------------------------------------- /Software_d3d9/FixedFuncEmu/FFVS/Include/FFVS_CalculateSingleLight.fxh: -------------------------------------------------------------------------------- 1 | #ifndef LIGHTTYPE 2 | #error Error: Do not include this file without defining LIGHTTYPE first to one of: D3DLIGHT_POINT, D3DLIGHT_SPOT, or D3DLIGHT_DIRECTIONAL 3 | #endif 4 | #ifndef LIGHTINDEX 5 | #error Error: Do not include this file without defining LIGHTINDEX first! 6 | #endif 7 | 8 | #define FuncName(x) CalculateFixedFunctionLightingForSingleLight##x 9 | 10 | const PerLightResults FuncName(LIGHTINDEX)(in const LightData lightdata, in const float3 viewspaceVertexPos, in const float3 viewspaceVertexNormal) 11 | { 12 | PerLightResults ret; 13 | 14 | // Calculating Ldir (the light direction relative to the current vertex) is different for directional vs. point/spot lights: https://docs.microsoft.com/en-us/windows/win32/direct3d9/camera-space-transformations 15 | #if LIGHTTYPE == D3DLIGHT_DIRECTIONAL 16 | const float3 vertexToLightDirNormalized = -lightdata.Direction.xyz; 17 | #else 18 | const float3 vertexToLightDirRaw = lightdata.Position.xyz - viewspaceVertexPos; 19 | const float3 vertexToLightDirNormalized = normalize(vertexToLightDirRaw); 20 | #endif 21 | 22 | // Attenuation is calculated based on the equations on this page: https://docs.microsoft.com/en-us/windows/win32/direct3d9/attenuation-and-spotlight-factor#attenuation 23 | #if LIGHTTYPE == D3DLIGHT_POINT || LIGHTTYPE == D3DLIGHT_SPOT 24 | const float distToLight = length(vertexToLightDirRaw); 25 | float attenuation; 26 | [flatten] if (distToLight > lightdata.Position.w) 27 | attenuation = 0.0f; 28 | else 29 | attenuation = 1.0f / (lightdata.Attenuation.x + lightdata.Attenuation.y * distToLight + lightdata.Attenuation.z * (distToLight * distToLight) ); 30 | #endif // #if LIGHTTYPE == D3DLIGHT_POINT || LIGHTTYPE == D3DLIGHT_SPOT 31 | 32 | // Spotlight Factor is calculated based on the equations on this page: https://docs.microsoft.com/en-us/windows/win32/direct3d9/attenuation-and-spotlight-factor#spotlight-factor 33 | #if LIGHTTYPE == D3DLIGHT_SPOT 34 | const float rho = -lightdata.Direction.xyz * vertexToLightDirNormalized; 35 | float spotlight; 36 | [flatten] if (rho > lightdata.SpotlightParams.z) 37 | spotlight = 1.0f; 38 | else if (rho <= lightdata.SpotlightParams.w) 39 | spotlight = 0.0f; 40 | else 41 | spotlight = pow( (rho - lightdata.SpotlightParams.w) * lightdata.Attenuation.w, lightdata.Direction.w); 42 | #endif // #if LIGHTTYPE == D3DLIGHT_SPOT 43 | 44 | #if (LIGHTTYPE < D3DLIGHT_POINT) || (LIGHTTYPE > D3DLIGHT_DIRECTIONAL) 45 | #error Error: Invalid light type for LIGHTTYPE 46 | #endif 47 | 48 | #if LIGHTTYPE == D3DLIGHT_POINT 49 | ret.Ambient = attenuation * lightdata.Ambient; 50 | #elif LIGHTTYPE == D3DLIGHT_SPOT 51 | ret.Ambient = attenuation * spotlight * lightdata.Ambient; 52 | #elif LIGHTTYPE == D3DLIGHT_DIRECTIONAL 53 | ret.Ambient = lightdata.Ambient; 54 | #endif 55 | 56 | #if LIGHTTYPE == D3DLIGHT_POINT 57 | const float NdotL = dot(viewspaceVertexNormal, vertexToLightDirNormalized); 58 | ret.Diffuse = (NdotL > 0.0f) ? (attenuation * NdotL * lightdata.Diffuse) : float4(0.0f, 0.0f, 0.0f, 0.0f); 59 | #elif LIGHTTYPE == D3DLIGHT_SPOT 60 | const float NdotL = dot(viewspaceVertexNormal, vertexToLightDirNormalized); 61 | ret.Diffuse = (NdotL > 0.0f) ? (attenuation * spotlight * NdotL * lightdata.Diffuse) : float4(0.0f, 0.0f, 0.0f, 0.0f); 62 | #elif LIGHTTYPE == D3DLIGHT_DIRECTIONAL 63 | const float NdotL = dot(viewspaceVertexNormal, vertexToLightDirNormalized); 64 | ret.Diffuse = (NdotL > 0.0f) ? (NdotL * lightdata.Diffuse) : float4(0.0f, 0.0f, 0.0f, 0.0f); 65 | #endif 66 | 67 | // D3DRS_LOCALVIEWER changes the computation of the halfway vector, so account for that here 68 | #ifdef D3DRS_LOCALVIEWER 69 | #if LIGHTTYPE == D3DLIGHT_POINT 70 | const float3 halfVector = normalize(normalize(-viewspaceVertexPos) + vertexToLightDirNormalized); 71 | #elif LIGHTTYPE == D3DLIGHT_SPOT 72 | const float3 halfVector = normalize(normalize(-viewspaceVertexPos) + lightdata.Direction.xyz); 73 | #elif LIGHTTYPE == D3DLIGHT_DIRECTIONAL 74 | const float3 halfVector = normalize(normalize(-viewspaceVertexPos) + lightdata.Direction.xyz); 75 | #endif 76 | #else // #ifdef D3DRS_LOCALVIEWER 77 | #if LIGHTTYPE == D3DLIGHT_POINT 78 | const float3 halfVector = normalize(float3(0.0f, 0.0f, 1.0f) + vertexToLightDirNormalized); 79 | #elif LIGHTTYPE == D3DLIGHT_SPOT 80 | const float3 halfVector = normalize(float3(0.0f, 0.0f, 1.0f) + lightdata.Direction.xyz); 81 | #elif LIGHTTYPE == D3DLIGHT_DIRECTIONAL 82 | const float3 halfVector = normalize(float3(0.0f, 0.0f, 1.0f) + lightdata.Direction.xyz); 83 | #endif 84 | #endif // #ifdef D3DRS_LOCALVIEWER 85 | 86 | #if LIGHTTYPE == D3DLIGHT_POINT 87 | const float specComponent = pow(dot(viewspaceVertexNormal, halfVector), materialData.Specular.w); 88 | ret.Specular = attenuation * specComponent * lightdata.Specular; 89 | #elif LIGHTTYPE == D3DLIGHT_SPOT 90 | const float specComponent = pow(dot(viewspaceVertexNormal, halfVector), materialData.Specular.w); 91 | ret.Specular = attenuation * spotlight * specComponent * lightdata.Specular; 92 | #elif LIGHTTYPE == D3DLIGHT_DIRECTIONAL 93 | const float specComponent = pow(dot(viewspaceVertexNormal, halfVector), materialData.Specular.w); 94 | ret.Specular = specComponent * lightdata.Specular; 95 | #endif 96 | 97 | return ret; 98 | } 99 | 100 | #undef LIGHTINDEX 101 | #undef LIGHTTYPE 102 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVertexBuffer9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | 5 | class IDirect3DVertexBuffer9Hook : public IDirect3DVertexBuffer9 6 | { 7 | public: 8 | IDirect3DVertexBuffer9Hook(LPDIRECT3DVERTEXBUFFER9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1), 9 | InternalLength(0), InternalUsage(UsageNone), InternalFVF(0x00000000), InternalPool(D3DPOOL_DEFAULT), lockCount(0), data(NULL), isSoftVertexBufferUP(false) 10 | { 11 | #ifdef _DEBUG 12 | if (realObject) 13 | memcpy(&Name, &realObject->Name, (char*)&realObject - (char*)&Name); 14 | else 15 | memset(&Name, 0x00000000, (char*)&realObject - (char*)&Name); 16 | #endif 17 | } 18 | 19 | inline LPDIRECT3DVERTEXBUFFER9 GetUnderlyingVertexBuffer(void) const 20 | { 21 | return realObject; 22 | } 23 | 24 | virtual ~IDirect3DVertexBuffer9Hook() 25 | { 26 | #ifdef VERTEX_BUFFER_ALLOC_PAGE_NOACCESS 27 | if (!isSoftVertexBufferUP) 28 | { 29 | if (data) 30 | { 31 | VirtualFree(data, 0, MEM_RELEASE); 32 | data = NULL; 33 | } 34 | } 35 | #else // #ifdef VERTEX_BUFFER_ALLOC_PAGE_NOACCESS 36 | if (!isSoftVertexBufferUP) 37 | { 38 | if (data) 39 | { 40 | free(data); 41 | data = NULL; 42 | } 43 | } 44 | #endif 45 | if (isSoftVertexBufferUP) 46 | data = NULL; 47 | 48 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 49 | memset(this, 0x00000000, sizeof(*this) ); 50 | #endif 51 | } 52 | 53 | /*** IUnknown methods ***/ 54 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 55 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 56 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 57 | 58 | /*** IDirect3DResource9 methods ***/ 59 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 60 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) override; 61 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) override; 62 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE FreePrivateData(THIS_ REFGUID refguid) override; 63 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetPriority(THIS_ DWORD PriorityNew) override; 64 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetPriority(THIS) override; 65 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE PreLoad(THIS) override; 66 | virtual COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE GetType(THIS) override; 67 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Lock(THIS_ UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags) override; 68 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Unlock(THIS) override; 69 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDesc(THIS_ D3DVERTEXBUFFER_DESC *pDesc) override; 70 | 71 | void CreateVertexBuffer(UINT _Length, const DebuggableUsage _Usage, DWORD _FVF, D3DPOOL _Pool); 72 | 73 | inline void MarkSoftBufferUP(const bool isSoftUPVertexBuffer) 74 | { 75 | isSoftVertexBufferUP = isSoftUPVertexBuffer; 76 | } 77 | 78 | inline void SoftUPSetInternalPointer(const BYTE* const stream0BytesUP, const UINT BufferLengthBytes) 79 | { 80 | #ifdef _DEBUG 81 | if (!isSoftVertexBufferUP) 82 | { 83 | __debugbreak(); // What are you doing calling this on a regular vertex buffer? 84 | } 85 | if (data != NULL) 86 | { 87 | __debugbreak(); // Probably forgot a reset somewhere! 88 | } 89 | if (stream0BytesUP == NULL) 90 | { 91 | __debugbreak(); // This should never happen, draw calls with NULL stream0UP data are invalid 92 | } 93 | #endif 94 | data = (BYTE* const)stream0BytesUP; 95 | InternalLength = BufferLengthBytes; 96 | } 97 | 98 | inline void SoftUPResetInternalPointer(void) 99 | { 100 | #ifdef _DEBUG 101 | if (!isSoftVertexBufferUP) 102 | { 103 | __debugbreak(); // What are you doing calling this on a regular vertex buffer? 104 | } 105 | if (data == NULL) 106 | { 107 | __debugbreak(); // You either did a reset twice in a row, or you forgot to set the pointer in the first place! 108 | } 109 | #endif 110 | data = NULL; 111 | InternalLength = 0; 112 | } 113 | 114 | inline const BYTE* const GetInternalDataBuffer(void) const 115 | { 116 | return data; 117 | } 118 | 119 | inline const UINT GetInternalLength_Bytes(void) const 120 | { 121 | return InternalLength; 122 | } 123 | 124 | inline const DWORD GetInternalFVF(void) const 125 | { 126 | return InternalFVF; 127 | } 128 | 129 | inline const bool IsUnlocked(void) const 130 | { 131 | return lockCount == 0; 132 | } 133 | 134 | protected: 135 | LPDIRECT3DVERTEXBUFFER9 realObject; 136 | IDirect3DDevice9Hook* parentDevice; 137 | unsigned __int64 refCount; 138 | 139 | UINT InternalLength; 140 | DebuggableUsage InternalUsage; 141 | DWORD InternalFVF; 142 | D3DPOOL InternalPool; 143 | 144 | long lockCount; 145 | bool isSoftVertexBufferUP; // If this is true, then the memory pointed to by the buffer is managed by the application and should not be modified or freed! 146 | 147 | BYTE* data; 148 | }; 149 | -------------------------------------------------------------------------------- /Software_d3d9/ShaderEngineBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ShaderBase.h" 4 | #include "ShaderIntrinsicFunctions.h" 5 | 6 | struct ShaderInfo; 7 | 8 | static const D3DXVECTOR4 ZEROVEC(0.0f, 0.0f, 0.0f, 0.0f); 9 | 10 | __declspec(align(16) ) class ShaderEngineBase 11 | { 12 | public: 13 | ShaderEngineBase() : instructionPtr(NULL), shaderInfo(NULL) 14 | { 15 | } 16 | 17 | ~ShaderEngineBase() 18 | { 19 | instructionPtr = NULL; 20 | shaderInfo = NULL; 21 | } 22 | 23 | typedef void (__fastcall * tex2DMip0Sig)(float4& outVal, const float4& texCoord, const sampler* const samplerPtr); 24 | tex2DMip0Sig tex2DMip0ptrs[15]; 25 | 26 | typedef void (__fastcall * tex2DLoDSig)(float4& outVal, const float4& texCoordAndLoD, const sampler* const samplerPtr); 27 | tex2DLoDSig tex2DLoDptrs[15]; 28 | 29 | typedef void (__fastcall * tex2DGradSig)(float4& outVal, const float4& texCoord, const float4& texDdx, const float4& texDdy, const sampler* const samplerPtr); 30 | tex2DGradSig tex2DGradPtrs[15]; 31 | 32 | typedef void (__fastcall * tex2DGradBiasSig)(float4& outVal, const float4& texCoord, const float4& texDdx, const float4& texDdy, const sampler* const samplerPtr); 33 | tex2DGradBiasSig tex2DGradBiasPtrs[15]; 34 | 35 | void GlobalInitTex2DFunctionTable() 36 | { 37 | tex2DMip0ptrs[0] = (const tex2DMip0Sig)&tex2Dmip0<1>; 38 | tex2DMip0ptrs[1] = (const tex2DMip0Sig)&tex2Dmip0<2>; 39 | tex2DMip0ptrs[2] = (const tex2DMip0Sig)&tex2Dmip0<3>; 40 | tex2DMip0ptrs[3] = (const tex2DMip0Sig)&tex2Dmip0<4>; 41 | tex2DMip0ptrs[4] = (const tex2DMip0Sig)&tex2Dmip0<5>; 42 | tex2DMip0ptrs[5] = (const tex2DMip0Sig)&tex2Dmip0<6>; 43 | tex2DMip0ptrs[6] = (const tex2DMip0Sig)&tex2Dmip0<7>; 44 | tex2DMip0ptrs[7] = (const tex2DMip0Sig)&tex2Dmip0<8>; 45 | tex2DMip0ptrs[8] = (const tex2DMip0Sig)&tex2Dmip0<9>; 46 | tex2DMip0ptrs[9] = (const tex2DMip0Sig)&tex2Dmip0<10>; 47 | tex2DMip0ptrs[10] = (const tex2DMip0Sig)&tex2Dmip0<11>; 48 | tex2DMip0ptrs[11] = (const tex2DMip0Sig)&tex2Dmip0<12>; 49 | tex2DMip0ptrs[12] = (const tex2DMip0Sig)&tex2Dmip0<13>; 50 | tex2DMip0ptrs[13] = (const tex2DMip0Sig)&tex2Dmip0<14>; 51 | tex2DMip0ptrs[14] = (const tex2DMip0Sig)&tex2Dmip0<15>; 52 | 53 | tex2DLoDptrs[0] = (const tex2DLoDSig)&tex2Dlod<1>; 54 | tex2DLoDptrs[1] = (const tex2DLoDSig)&tex2Dlod<2>; 55 | tex2DLoDptrs[2] = (const tex2DLoDSig)&tex2Dlod<3>; 56 | tex2DLoDptrs[3] = (const tex2DLoDSig)&tex2Dlod<4>; 57 | tex2DLoDptrs[4] = (const tex2DLoDSig)&tex2Dlod<5>; 58 | tex2DLoDptrs[5] = (const tex2DLoDSig)&tex2Dlod<6>; 59 | tex2DLoDptrs[6] = (const tex2DLoDSig)&tex2Dlod<7>; 60 | tex2DLoDptrs[7] = (const tex2DLoDSig)&tex2Dlod<8>; 61 | tex2DLoDptrs[8] = (const tex2DLoDSig)&tex2Dlod<9>; 62 | tex2DLoDptrs[9] = (const tex2DLoDSig)&tex2Dlod<10>; 63 | tex2DLoDptrs[10] = (const tex2DLoDSig)&tex2Dlod<11>; 64 | tex2DLoDptrs[11] = (const tex2DLoDSig)&tex2Dlod<12>; 65 | tex2DLoDptrs[12] = (const tex2DLoDSig)&tex2Dlod<13>; 66 | tex2DLoDptrs[13] = (const tex2DLoDSig)&tex2Dlod<14>; 67 | tex2DLoDptrs[14] = (const tex2DLoDSig)&tex2Dlod<15>; 68 | 69 | tex2DGradPtrs[0] = (const tex2DGradSig)&tex2Dgrad<1, false>; 70 | tex2DGradPtrs[1] = (const tex2DGradSig)&tex2Dgrad<2, false>; 71 | tex2DGradPtrs[2] = (const tex2DGradSig)&tex2Dgrad<3, false>; 72 | tex2DGradPtrs[3] = (const tex2DGradSig)&tex2Dgrad<4, false>; 73 | tex2DGradPtrs[4] = (const tex2DGradSig)&tex2Dgrad<5, false>; 74 | tex2DGradPtrs[5] = (const tex2DGradSig)&tex2Dgrad<6, false>; 75 | tex2DGradPtrs[6] = (const tex2DGradSig)&tex2Dgrad<7, false>; 76 | tex2DGradPtrs[7] = (const tex2DGradSig)&tex2Dgrad<8, false>; 77 | tex2DGradPtrs[8] = (const tex2DGradSig)&tex2Dgrad<9, false>; 78 | tex2DGradPtrs[9] = (const tex2DGradSig)&tex2Dgrad<10, false>; 79 | tex2DGradPtrs[10] = (const tex2DGradSig)&tex2Dgrad<11, false>; 80 | tex2DGradPtrs[11] = (const tex2DGradSig)&tex2Dgrad<12, false>; 81 | tex2DGradPtrs[12] = (const tex2DGradSig)&tex2Dgrad<13, false>; 82 | tex2DGradPtrs[13] = (const tex2DGradSig)&tex2Dgrad<14, false>; 83 | tex2DGradPtrs[14] = (const tex2DGradSig)&tex2Dgrad<15, false>; 84 | 85 | tex2DGradBiasPtrs[0] = (const tex2DGradBiasSig)&tex2Dgrad<1, true>; 86 | tex2DGradBiasPtrs[1] = (const tex2DGradBiasSig)&tex2Dgrad<2, true>; 87 | tex2DGradBiasPtrs[2] = (const tex2DGradBiasSig)&tex2Dgrad<3, true>; 88 | tex2DGradBiasPtrs[3] = (const tex2DGradBiasSig)&tex2Dgrad<4, true>; 89 | tex2DGradBiasPtrs[4] = (const tex2DGradBiasSig)&tex2Dgrad<5, true>; 90 | tex2DGradBiasPtrs[5] = (const tex2DGradBiasSig)&tex2Dgrad<6, true>; 91 | tex2DGradBiasPtrs[6] = (const tex2DGradBiasSig)&tex2Dgrad<7, true>; 92 | tex2DGradBiasPtrs[7] = (const tex2DGradBiasSig)&tex2Dgrad<8, true>; 93 | tex2DGradBiasPtrs[8] = (const tex2DGradBiasSig)&tex2Dgrad<9, true>; 94 | tex2DGradBiasPtrs[9] = (const tex2DGradBiasSig)&tex2Dgrad<10, true>; 95 | tex2DGradBiasPtrs[10] = (const tex2DGradBiasSig)&tex2Dgrad<11, true>; 96 | tex2DGradBiasPtrs[11] = (const tex2DGradBiasSig)&tex2Dgrad<12, true>; 97 | tex2DGradBiasPtrs[12] = (const tex2DGradBiasSig)&tex2Dgrad<13, true>; 98 | tex2DGradBiasPtrs[13] = (const tex2DGradBiasSig)&tex2Dgrad<14, true>; 99 | tex2DGradBiasPtrs[14] = (const tex2DGradBiasSig)&tex2Dgrad<15, true>; 100 | } 101 | 102 | // Public accessor for ShaderInfo 103 | inline const ShaderInfo* const GetShaderInfo() const 104 | { 105 | return shaderInfo; 106 | } 107 | 108 | protected: 109 | const DWORD* instructionPtr; 110 | 111 | const ShaderInfo* shaderInfo; 112 | }; 113 | -------------------------------------------------------------------------------- /Software_d3d9/GlobalToggles.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Uncomment to disable fixed function shader caching 4 | // #define NO_CACHING_FIXED_FUNCTION_SHADERS 1 5 | 6 | // Uncomment to disable FVF vertex decl caching 7 | // #define NO_CACHING_FVF_VERT_DECLS 1 8 | 9 | // Uncomment this line for debugging vertex shader engines: 10 | // Note that if the JIT pixel shader fails to compile, the renderer will still fall back to using the interpreter pixel shader engine regardless of this setting 11 | // #define FORCE_INTERPRETED_VERTEX_SHADER 1 12 | 13 | // Uncomment this line for debugging pixel shader engines: 14 | // Note that if the JIT pixel shader fails to compile, the renderer will still fall back to using the interpreter pixel shader engine regardless of this setting 15 | // #define FORCE_INTERPRETED_PIXEL_SHADER 1 16 | 17 | // Comment out to disable 18 | // #define DUMP_TEXTURES_ON_FIRST_SET 1 19 | 20 | // Comment out to disable 21 | // #define COMPUTE_SURFACE_HASHES_FOR_DEBUGGING 1 22 | 23 | // Commment this out to enable "fully correct" gamma correction calculations 24 | #define USE_CHEAP_GAMMA_APPROXIMATION 1 25 | 26 | // Comment out to disable 27 | #ifdef _DEBUG 28 | // #define DEBUG_VERTEX_OUT_POSITIONS 1 29 | #endif 30 | 31 | // Uncomment to enable showing the shader compilation window when compiling (does not play nicely with fullscreen windows) 32 | // #define DEBUG_SHOW_SHADERCOMPILE_WINDOW 1 33 | 34 | // These are useful for debugging: Forcing windowed mode, and forcing no VSync 35 | #ifdef _DEBUG 36 | #define OVERRIDE_FORCE_WINDOWED_MODE 1 37 | #endif 38 | #define OVERRIDE_FORCE_NO_VSYNC 1 39 | #ifdef _DEBUG 40 | #define OVERRIDE_FORCE_NO_VSYNC 1 41 | #endif 42 | #define OVERRIDE_HIDE_CURSOR 1 43 | 44 | // If this is not defined, all shaders will run in solo threads rather than warps (usually of at least 2x2 pixels or vertices) 45 | #define RUN_SHADERS_IN_WARPS 1 46 | 47 | // Defines for different kinds of parallel libraries 48 | #define PARALLELLIB_CONCRT 1 49 | #define PARALLELLIB_TBB 2 50 | 51 | // Use this define to set which parallel library to use (ConcRT or TBB are currently supported): 52 | #define PARALLEL_LIBRARY PARALLELLIB_CONCRT 53 | 54 | // Comment this line out to disable multithread shading 55 | #define MULTITHREAD_SHADING 1 56 | 57 | // Comment these out to disable shader execution profiling 58 | #ifndef MULTITHREAD_SHADING 59 | //#define PROFILE_AVERAGE_VERTEX_SHADE_TIMES 1 60 | //#define PROFILE_AVERAGE_PIXEL_SHADE_TIMES 1 61 | #endif 62 | 63 | // If defined, the software renderer will improve the system's scheduler resolution (which is useful when running many threads in the job system). 64 | // This increase only lasts as long as the process is running, and the default scheduler resolution will be applied when the process terminates. 65 | #ifdef MULTITHREAD_SHADING 66 | #define INCREASE_SYSTEM_SCHEDULER_RESOLUTION 1 67 | #endif 68 | 69 | #ifdef MULTITHREAD_SHADING 70 | #define TRIANGLEJOBS 1 71 | #define PIXELJOBS 2 72 | #define TRIANGLEJOBS_OR_PIXELJOBS PIXELJOBS 73 | #endif 74 | 75 | // Comment out to disable 76 | //#define INDEX_BUFFER_MAGIC_COOKIE 1 77 | 78 | // Comment out to disable 79 | //#define VERTEX_BUFFER_MAGIC_COOKIE 1 80 | 81 | // Comment out to disable 82 | //#define SURFACE_MAGIC_COOKIE 1 83 | 84 | // Comment out to disable printing when D3D hook objects are fully released (deleted) 85 | #define DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 1 86 | 87 | // Comment out to disable memset'ing a D3DHook object after it's destructed 88 | #define WIPE_ON_DESTRUCT_D3DHOOKOBJECT 1 89 | 90 | // Comment out to use a more efficient allocator for surface alloc. Leave uncommented for a safer way to make sure reads and writes don't go past the end of the surface 91 | #ifndef SURFACE_MAGIC_COOKIE 92 | //#define SURFACE_ALLOC_PAGE_NOACCESS 1 93 | #endif 94 | 95 | // If defined, this will wipe surfaces when D3DLOCK_DISCARD is specified during a LockRect operation 96 | #ifdef _DEBUG 97 | #define SURFACE_ENFORCE_DISCARD_ON_LOCK 1 98 | #endif 99 | 100 | // Comment out to use a more efficient allocator for vertex buffer alloc. Leave uncommented for a safer way to make sure reads and writes don't go past the end of the buffer 101 | #ifndef VERTEX_BUFFER_MAGIC_COOKIE 102 | //#define VERTEX_BUFFER_ALLOC_PAGE_NOACCESS 1 103 | #endif 104 | 105 | // If defined, this will force vertex buffer data to be made read-only after Unlock() is called 106 | #ifdef VERTEX_BUFFER_ALLOC_PAGE_NOACCESS 107 | //#define VERTEX_BUFFER_ENFORCE_READONLY_WHILE_UNLOCKED 1 108 | #endif 109 | 110 | // If defined, this will wipe vertex buffers when D3DLOCK_DISCARD is specified during a Lock operation 111 | #ifdef _DEBUG 112 | #define VERTEX_BUFFER_ENFORCE_DISCARD_ON_LOCK 1 113 | #endif 114 | 115 | // Comment out to use a more efficient allocator for index buffer alloc. Leave uncommented for a safer way to make sure reads and writes don't go past the end of the buffer 116 | #ifndef INDEX_BUFFER_MAGIC_COOKIE 117 | //#define INDEX_BUFFER_ALLOC_PAGE_NOACCESS 1 118 | #endif 119 | 120 | // If defined, this will force index buffer data to be made read-only after Unlock() is called 121 | #ifdef INDEX_BUFFER_ALLOC_PAGE_NOACCESS 122 | //#define INDEX_BUFFER_ENFORCE_READONLY_WHILE_UNLOCKED 1 123 | #endif 124 | 125 | // If defined, this will wipe index buffers when D3DLOCK_DISCARD is specified during a Lock operation 126 | #ifdef _DEBUG 127 | #define INDEX_BUFFER_ENFORCE_DISCARD_ON_LOCK 1 128 | #endif 129 | 130 | // Uncomment this to enable holding the "END" key to skip draw calls (very useful in debug mode where draw calls can take a very long time to complete) 131 | #define ENABLE_END_TO_SKIP_DRAWS 1 132 | 133 | // Comment this out to allow the early Z testing optimization 134 | //#define DISALLOW_EARLY_Z_TESTING 1 135 | -------------------------------------------------------------------------------- /Software_d3d9/PShaderEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "d3d9include.h" 4 | #include "ShaderEngineBase.h" 5 | 6 | class IDirect3DTexture9Hook; 7 | struct DeviceState; 8 | struct DeviceState_ShaderRegisters; 9 | struct ShaderInfo; 10 | 11 | #define MAX_NUM_PS_CONSTANTS 4096 12 | #define MAX_NUM_PS_INPUTS 10 13 | 14 | __declspec(align(16) ) struct PS_2_0_ConstantsBuffer 15 | { 16 | D3DXVECTOR4 c[MAX_NUM_PS_CONSTANTS]; // Constant registers 17 | BOOL b[MAX_NUM_CONST_BOOL_REGISTERS]; // Constant boolean registers 18 | int4 i[MAX_NUM_CONST_INT_REGISTERS]; // Constant int registers 19 | sampler s[16]; // Samplers 20 | }; 21 | 22 | __declspec(align(16) ) struct PS_2_0_InputRegisters 23 | { 24 | union _ps_interpolated_inputs 25 | { 26 | struct _ps_2_0_inputs 27 | { 28 | __declspec(align(16) ) D3DCOLORVALUE v[D3DMCS_COLOR2]; // Input vertex color registers (0 = diffuse, 1 = specular) 29 | __declspec(align(16) ) D3DCOLORVALUE t[D3DDP_MAXTEXCOORD]; // Texcoord registers 30 | } ps_2_0_inputs; 31 | 32 | struct _ps_3_0_inputs 33 | { 34 | __declspec(align(16) ) D3DCOLORVALUE t[MAX_NUM_PS_INPUTS]; // Input interpolator registers 35 | } ps_3_0_inputs; 36 | } ps_interpolated_inputs; 37 | }; 38 | 39 | __declspec(align(16) ) struct PS_2_0_RuntimeRegisters 40 | { 41 | D3DXVECTOR4 r[MAX_NUM_TEMP_REGISTERS]; // Temporary GPR 42 | int4 p0; // Predicate register 43 | int aL; // Loop Counter Register (only exists in ps_3_0 and up) 44 | }; 45 | 46 | enum pixelOutputStatus : unsigned // This needs to be a 32-bit enum so that we can use gather4 on it 47 | { 48 | normalWrite, 49 | discard, // TEXKILL 50 | stencilFail, 51 | ZFail 52 | }; 53 | 54 | __declspec(align(16) ) struct PS_2_0_OutputRegisters 55 | { 56 | float4 oC[4]; // Output color registers (very important) 57 | float oDepth; // Output depth register 58 | pixelOutputStatus pixelStatus; // Was this pixel discarded or did it finish (or was it Z or Stencil-culled)? 59 | }; 60 | 61 | __declspec(align(16) ) struct PS_2_0_MiscRegisters 62 | { 63 | D3DXVECTOR4 vPos; 64 | D3DXVECTOR4 vFace; 65 | }; 66 | 67 | enum shaderStatus : unsigned char 68 | { 69 | shouldContinueStatus = 0, 70 | errorStatus = 1, 71 | texkillStatus = 2, 72 | normalCompletion = 3 73 | }; 74 | 75 | __declspec(align(16) ) class PShaderEngine : public ShaderEngineBase 76 | { 77 | public: 78 | PShaderEngine() : constantRegisters(NULL) 79 | { 80 | } 81 | 82 | ~PShaderEngine() 83 | { 84 | constantRegisters = NULL; 85 | } 86 | 87 | inline PShaderEngine& operator=(const PShaderEngine& rhs) 88 | { 89 | shaderInfo = rhs.shaderInfo; 90 | constantRegisters = rhs.constantRegisters; 91 | return *this; 92 | } 93 | 94 | inline void DeepCopy(const PShaderEngine& rhs) 95 | { 96 | memcpy(this, &rhs, sizeof(*this) ); 97 | } 98 | 99 | // Called once for each shader instruction 100 | const shaderStatus InterpreterExecStep(); 101 | 102 | // Called once at device reset time 103 | void GlobalInit(const PS_2_0_ConstantsBuffer* const _constantRegisters); 104 | 105 | // Called once at the beginning of processing a draw-call: 106 | void Init(const DeviceState& deviceState, const ShaderInfo& _shaderInfo, PS_2_0_ConstantsBuffer* const mutableConstantRegisters); 107 | 108 | // Called once for every pixel to reset the state of the interpreter to its default 109 | void Reset(const unsigned x, const unsigned y); 110 | 111 | // Called once for every quad of pixels to reset the state of the interpreter to its default 112 | void Reset4(const __m128i x4, const __m128i y4); 113 | 114 | void InterpreterExecutePixel(void); 115 | 116 | const PS_2_0_ConstantsBuffer* constantRegisters; 117 | __declspec(align(16) ) PS_2_0_InputRegisters inputRegisters[4]; 118 | __declspec(align(16) ) PS_2_0_RuntimeRegisters runtimeRegisters[4]; 119 | __declspec(align(16) ) PS_2_0_OutputRegisters outputRegisters[4]; 120 | __declspec(align(16) ) PS_2_0_MiscRegisters miscRegisters[4]; 121 | 122 | const INTRINSIC_INLINE D3DXVECTOR4& ResolveSrcAddressIfValid(const void* const addressPtr) const 123 | { 124 | if (addressPtr >= &constantRegisters->c[0] && addressPtr <= &constantRegisters->c[(MAX_NUM_PS_CONSTANTS - 1)]) 125 | return *(const D3DXVECTOR4* const)addressPtr; 126 | else if (addressPtr >= &runtimeRegisters[0].r[0] && addressPtr <= &runtimeRegisters[0].r[(MAX_NUM_TEMP_REGISTERS - 1)]) 127 | return *(const D3DXVECTOR4* const)addressPtr; 128 | else if (addressPtr >= &inputRegisters[0].ps_interpolated_inputs.ps_3_0_inputs.t[0] && addressPtr <= &inputRegisters[0].ps_interpolated_inputs.ps_3_0_inputs.t[MAX_NUM_PS_INPUTS - 1]) 129 | return *(const D3DXVECTOR4* const)addressPtr; 130 | else 131 | // When reading outside of the constants buffer or the runtime registers the 132 | // constant (0,0,0,0) is always returned 133 | return ZEROVEC; 134 | } 135 | 136 | const INTRINSIC_INLINE D3DXVECTOR4& GetSrcRegisterFromAddress(const float4& baseRegister, const int addressOffset) 137 | { 138 | const float4* const targetRegister = &baseRegister + addressOffset; 139 | return ResolveSrcAddressIfValid(targetRegister); 140 | } 141 | 142 | protected: 143 | void InitGlobalConstants(const DeviceState_ShaderRegisters& globalPixelShaderConstants, PS_2_0_ConstantsBuffer* const mutableConstantRegisters); 144 | void InitLocalConstants(const ShaderInfo& pixelShaderInfo, PS_2_0_ConstantsBuffer* const mutableConstantRegisters); 145 | void InitSamplers(const DeviceState& deviceState, PS_2_0_ConstantsBuffer* const mutableConstantRegisters); 146 | 147 | void WriteDstParameter(const DWORD rawDstBytecode, const D3DXVECTOR4& value); 148 | D3DXVECTOR4& ResolveDstParameter(const DWORD rawDstBytecode); 149 | const float ResolveSrcReplicateSwizzle(const DWORD rawSrcBytecode, const D3DXVECTOR4& registerData) const; 150 | const D3DXVECTOR4& ResolveSrcParameter(const DWORD rawSrcBytecode) const; 151 | const D3DXVECTOR4 ResolveSrcRegister(const DWORD rawSrcBytecode) const; 152 | }; 153 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DPixelShader9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DPixelShader9Hook.h" 4 | #include "ShaderBase.h" 5 | #include "ShaderJIT.h" 6 | 7 | static std::vector alivePixelShaders; 8 | 9 | void IDirect3DPixelShader9Hook::CreatePixelShader(const DWORD* const pFunction) 10 | { 11 | if (!pFunction) 12 | return; 13 | 14 | ShaderInfo tempPixelShaderInfo; 15 | AnalyzeShader(pFunction, tempPixelShaderInfo 16 | #ifdef _DEBUG 17 | ,"NonePS" 18 | #endif 19 | ); 20 | 21 | if (!tempPixelShaderInfo.isPixelShader) 22 | { 23 | // This is not a pixel shader! 24 | __debugbreak(); 25 | } 26 | 27 | switch (tempPixelShaderInfo.shaderMajorVersion) 28 | { 29 | case 1: 30 | case 2: 31 | case 3: 32 | // We're good! 33 | break; 34 | default: 35 | // This is not a valid D3D9 shader! 36 | { 37 | __debugbreak(); 38 | } 39 | break; 40 | } 41 | 42 | shaderBytecode.resize(tempPixelShaderInfo.shaderLengthDWORDs); 43 | memcpy(&shaderBytecode.front(), pFunction, tempPixelShaderInfo.shaderLengthDWORDs * sizeof(DWORD) ); 44 | 45 | // Bad hack to rebase all of the pointer offsets, fix plz! 46 | AnalyzeShader(&shaderBytecode.front(), pixelShaderInfo 47 | #ifdef _DEBUG 48 | ,"NonePS" 49 | #endif 50 | ); 51 | 52 | parentDevice->LockDeviceCS(); 53 | alivePixelShaders.push_back(this); 54 | parentDevice->UnlockDeviceCS(); 55 | 56 | //JitLoadShader(); 57 | } 58 | 59 | /*virtual*/ IDirect3DPixelShader9Hook::~IDirect3DPixelShader9Hook() 60 | { 61 | parentDevice->LockDeviceCS(); 62 | const unsigned numAliveShaders = alivePixelShaders.size(); 63 | bool foundAndErased = false; 64 | for (unsigned x = 0; x < numAliveShaders; ++x) 65 | { 66 | if (alivePixelShaders[x] == this) 67 | { 68 | alivePixelShaders.erase(alivePixelShaders.begin() + x); 69 | foundAndErased = true; 70 | break; 71 | } 72 | } 73 | #ifdef _DEBUG 74 | if (!foundAndErased) 75 | { 76 | __debugbreak(); // Should never be here! 77 | } 78 | #endif 79 | parentDevice->UnlockDeviceCS(); 80 | 81 | shaderBytecode.clear(); 82 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 83 | memset(this, 0x00000000, sizeof(*this) - (sizeof(shaderBytecode) + sizeof(pixelShaderInfo) ) ); 84 | #endif 85 | } 86 | 87 | void IDirect3DPixelShader9Hook::JitLoadShader() 88 | { 89 | #ifdef FORCE_INTERPRETED_PIXEL_SHADER 90 | return; 91 | #endif 92 | 93 | const char* const jitName = ConstructShaderJITName(pixelShaderInfo); 94 | char jitFilenameBuffer[MAX_PATH] = {0}; 95 | #pragma warning(push) 96 | #pragma warning(disable:4996) 97 | sprintf(jitFilenameBuffer, "%s\\%s.dll", shaderJITTempDirectory, jitName); 98 | #pragma warning(pop) 99 | HMODULE hm = LoadLibraryA(jitFilenameBuffer); 100 | 101 | #ifdef _M_X64 102 | static const char* const shaderMainExportName = "PixelShaderMain"; 103 | #else 104 | static const char* const shaderMainExportName = "@PixelShaderMain@4"; 105 | #endif 106 | 107 | triedJit = true; 108 | 109 | if (hm) 110 | { 111 | jitShaderMain = (PSEntry)GetProcAddress(hm, shaderMainExportName); 112 | if (!jitShaderMain) 113 | { 114 | DbgBreakPrint("Error: Cannot find PixelShaderMain in existing JIT DLL"); 115 | } 116 | } 117 | else 118 | { 119 | if (!JITNewShader(pixelShaderInfo, jitName) ) 120 | { 121 | DbgBreakPrint("Error: Failed to JIT Pixel Shader"); 122 | } 123 | else 124 | { 125 | HMODULE hm2 = LoadLibraryA(jitFilenameBuffer); 126 | if (!hm2) 127 | { 128 | DbgBreakPrint("Error: Failed to load recently JIT'd Pixel Shader"); 129 | return; 130 | } 131 | jitShaderMain = (PSEntry)GetProcAddress(hm2, shaderMainExportName); 132 | if (!jitShaderMain) 133 | { 134 | DbgBreakPrint("Error: Cannot find PixelShaderMain in newly created JIT DLL"); 135 | return; 136 | } 137 | } 138 | } 139 | } 140 | 141 | /*** IUnknown methods ***/ 142 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DPixelShader9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 143 | { 144 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 145 | if (ret == NOERROR) 146 | { 147 | *ppvObj = this; 148 | AddRef(); 149 | } 150 | return ret; 151 | } 152 | 153 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DPixelShader9Hook::AddRef(THIS) 154 | { 155 | ULONG ret = realObject->AddRef(); 156 | ++refCount; 157 | return ret; 158 | } 159 | 160 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DPixelShader9Hook::Release(THIS) 161 | { 162 | ULONG ret = realObject->Release(); 163 | if (--refCount == 0) 164 | { 165 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 166 | char printBuffer[128] = {0}; 167 | #pragma warning(push) 168 | #pragma warning(disable:4996) 169 | sprintf(printBuffer, "Fully releasing hooked Pixel Shader %p\n", this); 170 | #pragma warning(pop) 171 | OutputDebugStringA(printBuffer); 172 | #endif 173 | delete this; 174 | } 175 | return ret; 176 | } 177 | 178 | /*** IDirect3DPixelShader9 methods ***/ 179 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DPixelShader9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 180 | { 181 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 182 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 183 | if (FAILED(ret) ) 184 | { 185 | *ppDevice = NULL; 186 | return ret; 187 | } 188 | 189 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 190 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 191 | { 192 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 193 | } 194 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 195 | 196 | *ppDevice = parentDevice; 197 | return ret; 198 | } 199 | 200 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DPixelShader9Hook::GetFunction(THIS_ void* pData,UINT* pSizeOfData) 201 | { 202 | HRESULT ret = realObject->GetFunction(pData, pSizeOfData); 203 | return ret; 204 | } 205 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVolumeTexture9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DVolumeTexture9Hook.h" 4 | 5 | /*** IUnknown methods ***/ 6 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 7 | { 8 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 9 | if (ret == NOERROR) 10 | { 11 | *ppvObj = this; 12 | AddRef(); 13 | } 14 | return ret; 15 | } 16 | 17 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::AddRef(THIS) 18 | { 19 | ULONG ret = realObject->AddRef(); 20 | ++refCount; 21 | return ret; 22 | } 23 | 24 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::Release(THIS) 25 | { 26 | ULONG ret = realObject->Release(); 27 | if (--refCount == 0) 28 | { 29 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 30 | char printBuffer[128] = {0}; 31 | #pragma warning(push) 32 | #pragma warning(disable:4996) 33 | sprintf(printBuffer, "Fully releasing hooked Volume Texture %p\n", this); 34 | #pragma warning(pop) 35 | OutputDebugStringA(printBuffer); 36 | #endif 37 | delete this; 38 | } 39 | return ret; 40 | } 41 | 42 | 43 | /*** IDirect3DBaseTexture9 methods ***/ 44 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 45 | { 46 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 47 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 48 | if (FAILED(ret) ) 49 | { 50 | *ppDevice = NULL; 51 | return ret; 52 | } 53 | 54 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 55 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 56 | { 57 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 58 | } 59 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 60 | 61 | *ppDevice = parentDevice; 62 | return ret; 63 | } 64 | 65 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) 66 | { 67 | HRESULT ret = realObject->SetPrivateData(refguid, pData, SizeOfData, Flags); 68 | return ret; 69 | } 70 | 71 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) 72 | { 73 | HRESULT ret = realObject->GetPrivateData(refguid, pData, pSizeOfData); 74 | return ret; 75 | } 76 | 77 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::FreePrivateData(THIS_ REFGUID refguid) 78 | { 79 | HRESULT ret = realObject->FreePrivateData(refguid); 80 | return ret; 81 | } 82 | 83 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::SetPriority(THIS_ DWORD PriorityNew) 84 | { 85 | DWORD ret = realObject->SetPriority(PriorityNew); 86 | return ret; 87 | } 88 | 89 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetPriority(THIS) 90 | { 91 | DWORD ret = realObject->GetPriority(); 92 | return ret; 93 | } 94 | 95 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::PreLoad(THIS) 96 | { 97 | realObject->PreLoad(); 98 | } 99 | 100 | COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetType(THIS) 101 | { 102 | D3DRESOURCETYPE ret = realObject->GetType(); 103 | return ret; 104 | } 105 | 106 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::SetLOD(THIS_ DWORD LODNew) 107 | { 108 | DWORD ret = realObject->SetLOD(LODNew); 109 | return ret; 110 | } 111 | 112 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetLOD(THIS) 113 | { 114 | DWORD ret = realObject->GetLOD(); 115 | return ret; 116 | } 117 | 118 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetLevelCount(THIS) 119 | { 120 | DWORD ret = realObject->GetLevelCount(); 121 | return ret; 122 | } 123 | 124 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::SetAutoGenFilterType(THIS_ D3DTEXTUREFILTERTYPE FilterType) 125 | { 126 | HRESULT ret = realObject->SetAutoGenFilterType(FilterType); 127 | return ret; 128 | } 129 | 130 | COM_DECLSPEC_NOTHROW D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetAutoGenFilterType(THIS) 131 | { 132 | D3DTEXTUREFILTERTYPE ret = realObject->GetAutoGenFilterType(); 133 | return ret; 134 | } 135 | 136 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GenerateMipSubLevels(THIS) 137 | { 138 | realObject->GenerateMipSubLevels(); 139 | 140 | if (!(InternalUsage & D3DUSAGE_AUTOGENMIPMAP) ) 141 | return; 142 | } 143 | 144 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetLevelDesc(THIS_ UINT Level,D3DVOLUME_DESC *pDesc) 145 | { 146 | HRESULT ret = realObject->GetLevelDesc(Level, pDesc); 147 | return ret; 148 | } 149 | 150 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::GetVolumeLevel(THIS_ UINT Level,IDirect3DVolume9** ppVolumeLevel) 151 | { 152 | HRESULT ret = realObject->GetVolumeLevel(Level, ppVolumeLevel); 153 | return ret; 154 | } 155 | 156 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::LockBox(THIS_ UINT Level,D3DLOCKED_BOX* pLockedVolume,CONST D3DBOX* pBox,DWORD Flags) 157 | { 158 | HRESULT ret = realObject->LockBox(Level, pLockedVolume, pBox, Flags); 159 | return ret; 160 | } 161 | 162 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::UnlockBox(THIS_ UINT Level) 163 | { 164 | HRESULT ret = realObject->UnlockBox(Level); 165 | return ret; 166 | } 167 | 168 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVolumeTexture9Hook::AddDirtyBox(THIS_ CONST D3DBOX* pDirtyBox) 169 | { 170 | HRESULT ret = realObject->AddDirtyBox(pDirtyBox); 171 | return ret; 172 | } 173 | 174 | void IDirect3DVolumeTexture9Hook::CreateVolumeTexture(UINT _Width, UINT _Height, UINT _Depth, UINT _Levels, DebuggableUsage _Usage, D3DFORMAT _Format, D3DPOOL _Pool) 175 | { 176 | InternalWidth = _Width; 177 | InternalHeight = _Height; 178 | InternalDepth = _Depth; 179 | InternalLevels = _Levels; 180 | InternalUsage = _Usage; 181 | InternalFormat = _Format; 182 | InternalPool = _Pool; 183 | } 184 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DCubeTexture9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DCubeTexture9Hook.h" 4 | 5 | /*** IUnknown methods ***/ 6 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 7 | { 8 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 9 | if (ret == NOERROR) 10 | { 11 | *ppvObj = this; 12 | AddRef(); 13 | } 14 | return ret; 15 | } 16 | 17 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::AddRef(THIS) 18 | { 19 | ULONG ret = realObject->AddRef(); 20 | ++refCount; 21 | return ret; 22 | } 23 | 24 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::Release(THIS) 25 | { 26 | ULONG ret = realObject->Release(); 27 | if (--refCount == 0) 28 | { 29 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 30 | char printBuffer[128] = {0}; 31 | #pragma warning(push) 32 | #pragma warning(disable:4996) 33 | sprintf(printBuffer, "Fully releasing hooked Cube Texture %p\n", this); 34 | #pragma warning(pop) 35 | OutputDebugStringA(printBuffer); 36 | #endif 37 | delete this; 38 | } 39 | return ret; 40 | } 41 | 42 | /*** IDirect3DBaseTexture9 methods ***/ 43 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 44 | { 45 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 46 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 47 | if (FAILED(ret) ) 48 | { 49 | *ppDevice = NULL; 50 | return ret; 51 | } 52 | 53 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 54 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 55 | { 56 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 57 | } 58 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 59 | 60 | *ppDevice = parentDevice; 61 | return ret; 62 | } 63 | 64 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) 65 | { 66 | HRESULT ret = realObject->SetPrivateData(refguid, pData, SizeOfData, Flags); 67 | return ret; 68 | } 69 | 70 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) 71 | { 72 | HRESULT ret = realObject->GetPrivateData(refguid, pData, pSizeOfData); 73 | return ret; 74 | } 75 | 76 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::FreePrivateData(THIS_ REFGUID refguid) 77 | { 78 | HRESULT ret = realObject->FreePrivateData(refguid); 79 | return ret; 80 | } 81 | 82 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::SetPriority(THIS_ DWORD PriorityNew) 83 | { 84 | DWORD ret = realObject->SetPriority(PriorityNew); 85 | return ret; 86 | } 87 | 88 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetPriority(THIS) 89 | { 90 | DWORD ret = realObject->GetPriority(); 91 | return ret; 92 | } 93 | 94 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::PreLoad(THIS) 95 | { 96 | realObject->PreLoad(); 97 | } 98 | 99 | COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetType(THIS) 100 | { 101 | D3DRESOURCETYPE ret = realObject->GetType(); 102 | return ret; 103 | } 104 | 105 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::SetLOD(THIS_ DWORD LODNew) 106 | { 107 | DWORD ret = realObject->SetLOD(LODNew); 108 | return ret; 109 | } 110 | 111 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetLOD(THIS) 112 | { 113 | DWORD ret = realObject->GetLOD(); 114 | return ret; 115 | } 116 | 117 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetLevelCount(THIS) 118 | { 119 | DWORD ret = realObject->GetLevelCount(); 120 | return ret; 121 | } 122 | 123 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::SetAutoGenFilterType(THIS_ D3DTEXTUREFILTERTYPE FilterType) 124 | { 125 | HRESULT ret = realObject->SetAutoGenFilterType(FilterType); 126 | return ret; 127 | } 128 | 129 | COM_DECLSPEC_NOTHROW D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetAutoGenFilterType(THIS) 130 | { 131 | D3DTEXTUREFILTERTYPE ret = realObject->GetAutoGenFilterType(); 132 | return ret; 133 | } 134 | 135 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GenerateMipSubLevels(THIS) 136 | { 137 | realObject->GenerateMipSubLevels(); 138 | 139 | if (!(InternalUsage & D3DUSAGE_AUTOGENMIPMAP) ) 140 | return; 141 | } 142 | 143 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetLevelDesc(THIS_ UINT Level,D3DSURFACE_DESC *pDesc) 144 | { 145 | HRESULT ret = realObject->GetLevelDesc(Level, pDesc); 146 | return ret; 147 | } 148 | 149 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::GetCubeMapSurface(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level,IDirect3DSurface9** ppCubeMapSurface) 150 | { 151 | HRESULT ret = realObject->GetCubeMapSurface(FaceType, Level, ppCubeMapSurface); 152 | return ret; 153 | } 154 | 155 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::LockRect(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags) 156 | { 157 | HRESULT ret = realObject->LockRect(FaceType, Level, pLockedRect, pRect, Flags); 158 | return ret; 159 | } 160 | 161 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::UnlockRect(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level) 162 | { 163 | HRESULT ret = realObject->UnlockRect(FaceType, Level); 164 | return ret; 165 | } 166 | 167 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DCubeTexture9Hook::AddDirtyRect(THIS_ D3DCUBEMAP_FACES FaceType,CONST RECT* pDirtyRect) 168 | { 169 | HRESULT ret = realObject->AddDirtyRect(FaceType, pDirtyRect); 170 | return ret; 171 | } 172 | 173 | void IDirect3DCubeTexture9Hook::CreateCubeTexture(UINT _EdgeLength, UINT _Levels, DebuggableUsage _Usage, D3DFORMAT _Format, D3DPOOL _Pool) 174 | { 175 | InternalEdgeLength = _EdgeLength; 176 | InternalLevels = _Levels; 177 | InternalUsage = _Usage; 178 | InternalFormat = _Format; 179 | InternalPool = _Pool; 180 | } 181 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DTexture9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | #include "GlobalToggles.h" 5 | struct SamplerState; 6 | 7 | class IDirect3DTexture9Hook : public IDirect3DTexture9 8 | { 9 | public: 10 | IDirect3DTexture9Hook(LPDIRECT3DTEXTURE9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1), AutoGenFilter(D3DTEXF_LINEAR), 11 | surfaceCountMinusOne(0), surfaceCountMinusTwo(0), surfaceCountMinusOneF(0.0f), surfaceLevel0(NULL) 12 | #ifdef DUMP_TEXTURES_ON_FIRST_SET 13 | , dumped(0) 14 | #endif 15 | { 16 | #ifdef _DEBUG 17 | memcpy(&Name, &realObject->Name, (char*)&realObject - (char*)&Name); 18 | #endif 19 | } 20 | 21 | virtual ~IDirect3DTexture9Hook() 22 | { 23 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 24 | memset(this, 0x00000000, sizeof(*this) - sizeof(surfaces) ); 25 | #endif 26 | } 27 | 28 | /*** IUnknown methods ***/ 29 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 30 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 31 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 32 | 33 | /*** IDirect3DBaseTexture9 methods ***/ 34 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 35 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) override; 36 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) override; 37 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE FreePrivateData(THIS_ REFGUID refguid) override; 38 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetPriority(THIS_ DWORD PriorityNew) override; 39 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetPriority(THIS) override; 40 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE PreLoad(THIS) override; 41 | virtual COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE GetType(THIS) override; 42 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetLOD(THIS_ DWORD LODNew) override; 43 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetLOD(THIS) override; 44 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetLevelCount(THIS) override; 45 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(THIS_ D3DTEXTUREFILTERTYPE FilterType) override; 46 | virtual COM_DECLSPEC_NOTHROW D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType(THIS) override; 47 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE GenerateMipSubLevels(THIS) override; 48 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetLevelDesc(THIS_ UINT Level,D3DSURFACE_DESC *pDesc) override; 49 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetSurfaceLevel(THIS_ UINT Level,IDirect3DSurface9** ppSurfaceLevel) override; 50 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE LockRect(THIS_ UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags) override; 51 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE UnlockRect(THIS_ UINT Level) override; 52 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE AddDirtyRect(THIS_ CONST RECT* pDirtyRect) override; 53 | 54 | inline LPDIRECT3DTEXTURE9 GetUnderlyingTexture(void) const 55 | { 56 | return realObject; 57 | } 58 | 59 | inline const UINT GetInternalWidth() const 60 | { 61 | return InternalWidth; 62 | } 63 | 64 | inline const UINT GetInternalHeight() const 65 | { 66 | return InternalHeight; 67 | } 68 | 69 | inline const D3DFORMAT GetInternalFormat() const 70 | { 71 | return InternalFormat; 72 | } 73 | 74 | const UINT GetInternalMipLevels() const 75 | { 76 | return InternalLevels; 77 | } 78 | 79 | const DebuggableUsage GetInternalUsage() const 80 | { 81 | return InternalUsage; 82 | } 83 | 84 | const D3DPOOL GetInternalPool() const 85 | { 86 | return InternalPool; 87 | } 88 | 89 | void CreateTexture(const UINT _Width, const UINT _Height, const UINT _Levels, const DebuggableUsage _Usage, const D3DFORMAT _Format, const D3DPOOL _Pool); 90 | 91 | const bool UpdateTextureInternal(const IDirect3DTexture9Hook* const sourceTexture); 92 | 93 | template 94 | void SampleTextureLoD(float x, float y, float mip, const SamplerState& samplerState, D3DXVECTOR4& outColor) const; 95 | 96 | template 97 | void SampleTextureGrad(float x, float y, const D3DXVECTOR4& texDdx, const D3DXVECTOR4& texDdy, const SamplerState& samplerState, D3DXVECTOR4& outColor) const; 98 | 99 | template 100 | void SampleTextureGradBias(float x, float y, const float mipBias, const D3DXVECTOR4& texDdx, const D3DXVECTOR4& texDdy, const SamplerState& samplerState, D3DXVECTOR4& outColor) const; 101 | 102 | template 103 | void SampleTextureLoD4(float (&x4)[4], float (&y4)[4], float (&mip4)[4], const SamplerState& samplerState, D3DXVECTOR4 (&outColor4)[4]) const; 104 | 105 | template 106 | void SampleTextureGrad4(float (&x4)[4], float (&y4)[4], const D3DXVECTOR4 (&texDdx4)[4], const D3DXVECTOR4 (&texDdy4)[4], const SamplerState& samplerState, D3DXVECTOR4 (&outColor4)[4]) const; 107 | 108 | template 109 | void SampleTextureGradBias4(float (&x4)[4], float (&y4)[4], const float (&mipBias4)[4], const D3DXVECTOR4 (&texDdx4)[4], const D3DXVECTOR4 (&texDdy4)[4], const SamplerState& samplerState, D3DXVECTOR4 (&outColor4)[4]) const; 110 | 111 | #ifdef DUMP_TEXTURES_ON_FIRST_SET 112 | unsigned dumped; 113 | #endif 114 | 115 | inline const std::vector& GetUnderlyingSurfaces(void) const 116 | { 117 | return surfaces; 118 | } 119 | 120 | protected: 121 | LPDIRECT3DTEXTURE9 realObject; 122 | IDirect3DDevice9Hook* parentDevice; 123 | unsigned __int64 refCount; 124 | 125 | UINT InternalWidth; 126 | UINT InternalHeight; 127 | UINT InternalLevels; 128 | DebuggableUsage InternalUsage; 129 | D3DFORMAT InternalFormat; 130 | D3DPOOL InternalPool; 131 | D3DTEXTUREFILTERTYPE AutoGenFilter; 132 | 133 | UINT surfaceCountMinusOne; 134 | INT surfaceCountMinusTwo; 135 | float surfaceCountMinusOneF; 136 | 137 | IDirect3DSurface9Hook* surfaceLevel0; 138 | 139 | std::vector surfaces; 140 | }; 141 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DIndexBuffer9Hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DDevice9Hook.h" 4 | #include "IDirect3DResource9Hook.h" 5 | 6 | class IDirect3DIndexBuffer9Hook : public IDirect3DIndexBuffer9 7 | { 8 | public: 9 | IDirect3DIndexBuffer9Hook(LPDIRECT3DINDEXBUFFER9 _realObject, IDirect3DDevice9Hook* _parentDevice) : realObject(_realObject), parentDevice(_parentDevice), refCount(1), 10 | InternalLength(0), InternalUsage(UsageNone), InternalFormat(D3DFMT_UNKNOWN), InternalPool(D3DPOOL_DEFAULT), lockCount(0), isSoftIndexBufferUP(false) 11 | { 12 | rawBytes.voidBytes = NULL; 13 | 14 | #ifdef _DEBUG 15 | if (realObject) 16 | memcpy(&Name, &realObject->Name, (char*)&realObject - (char*)&Name); 17 | else 18 | memset(&Name, 0x00000000, (char*)&realObject - (char*)&Name); 19 | #endif 20 | } 21 | 22 | inline LPDIRECT3DINDEXBUFFER9 GetUnderlyingIndexBuffer(void) const 23 | { 24 | return realObject; 25 | } 26 | 27 | virtual ~IDirect3DIndexBuffer9Hook() 28 | { 29 | #ifdef INDEX_BUFFER_ALLOC_PAGE_NOACCESS 30 | if (!isSoftIndexBufferUP) 31 | { 32 | if (rawBytes.voidBytes) 33 | { 34 | VirtualFree(rawBytes.voidBytes, 0, MEM_RELEASE); 35 | rawBytes.voidBytes = NULL; 36 | } 37 | } 38 | #else 39 | if (isSoftIndexBufferUP) 40 | { 41 | if (rawBytes.voidBytes) 42 | { 43 | free(rawBytes.voidBytes); 44 | rawBytes.voidBytes = NULL; 45 | } 46 | } 47 | #endif 48 | if (isSoftIndexBufferUP) 49 | { 50 | rawBytes.voidBytes = NULL; 51 | InternalFormat = D3DFMT_UNKNOWN; 52 | } 53 | 54 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 55 | memset(this, 0x00000000, sizeof(*this) ); 56 | #endif 57 | } 58 | 59 | /*** IUnknown methods ***/ 60 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE QueryInterface(THIS_ REFIID riid, void** ppvObj) override; 61 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE AddRef(THIS) override; 62 | virtual COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE Release(THIS) override; 63 | 64 | /*** IDirect3DResource9 methods ***/ 65 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDevice(THIS_ IDirect3DDevice9** ppDevice) override; 66 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) override; 67 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) override; 68 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE FreePrivateData(THIS_ REFGUID refguid) override; 69 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE SetPriority(THIS_ DWORD PriorityNew) override; 70 | virtual COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE GetPriority(THIS) override; 71 | virtual COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE PreLoad(THIS) override; 72 | virtual COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE GetType(THIS) override; 73 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Lock(THIS_ UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags) override; 74 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Unlock(THIS) override; 75 | virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE GetDesc(THIS_ D3DINDEXBUFFER_DESC *pDesc) override; 76 | 77 | inline const bool IsUnlocked(void) const 78 | { 79 | return lockCount == 0; 80 | } 81 | 82 | void CreateIndexBuffer(UINT _Length, const DebuggableUsage _Usage, D3DFORMAT _Format, D3DPOOL _Pool); 83 | 84 | inline const D3DFORMAT GetFormat(void) const 85 | { 86 | return InternalFormat; 87 | } 88 | 89 | inline const BYTE* const GetBufferBytes(void) const 90 | { 91 | return rawBytes.u8Bytes; 92 | } 93 | 94 | inline const UINT GetInternalLength(void) const 95 | { 96 | return InternalLength; 97 | } 98 | 99 | inline void MarkSoftBufferUP(const bool isSoftUPIndexBuffer) 100 | { 101 | isSoftIndexBufferUP = isSoftUPIndexBuffer; 102 | } 103 | 104 | inline void SoftUPSetInternalPointer(const void* const stream0IndicesUP, const D3DFORMAT newFormat, const D3DPRIMITIVETYPE PrimitiveType, const UINT PrimitiveCount) 105 | { 106 | #ifdef _DEBUG 107 | if (!isSoftIndexBufferUP) 108 | { 109 | __debugbreak(); // What are you doing calling this on a regular index buffer? 110 | } 111 | if (rawBytes.voidBytes != NULL) 112 | { 113 | __debugbreak(); // Probably forgot a reset somewhere! 114 | } 115 | if (stream0IndicesUP == NULL) 116 | { 117 | __debugbreak(); // This should never happen, draw calls with NULL index data are invalid 118 | } 119 | if (newFormat < D3DFMT_INDEX16 || newFormat > D3DFMT_INDEX32) 120 | { 121 | __debugbreak(); // Invalid index format 122 | } 123 | #endif 124 | rawBytes.voidBytes = (BYTE* const)stream0IndicesUP; 125 | InternalFormat = newFormat; 126 | 127 | unsigned indexCount; 128 | switch (PrimitiveType) 129 | { 130 | case D3DPT_POINTLIST: 131 | indexCount = PrimitiveCount; 132 | break; 133 | case D3DPT_LINELIST: 134 | indexCount = PrimitiveCount * 2; 135 | break; 136 | case D3DPT_LINESTRIP: 137 | indexCount = PrimitiveCount - 1; 138 | break; 139 | default: 140 | #ifdef _DEBUG 141 | __debugbreak(); // Should never be here 142 | #endif 143 | case D3DPT_TRIANGLELIST: 144 | indexCount = PrimitiveCount * 3; 145 | break; 146 | case D3DPT_TRIANGLESTRIP: 147 | case D3DPT_TRIANGLEFAN: 148 | indexCount = PrimitiveCount - 2; 149 | break; 150 | } 151 | 152 | const unsigned char singleIndexSize = (newFormat == D3DFMT_INDEX16) ? 2 : 4; 153 | InternalLength = indexCount * singleIndexSize; 154 | } 155 | 156 | inline void SoftUPResetInternalPointer(void) 157 | { 158 | #ifdef _DEBUG 159 | if (!isSoftIndexBufferUP) 160 | { 161 | __debugbreak(); // What are you doing calling this on a regular index buffer? 162 | } 163 | if (rawBytes.voidBytes == NULL) 164 | { 165 | __debugbreak(); // You either did a reset twice in a row, or you forgot to set the pointer in the first place! 166 | } 167 | #endif 168 | rawBytes.voidBytes = NULL; 169 | InternalFormat = D3DFMT_UNKNOWN; 170 | InternalLength = 0; 171 | } 172 | 173 | protected: 174 | LPDIRECT3DINDEXBUFFER9 realObject; 175 | IDirect3DDevice9Hook* parentDevice; 176 | unsigned __int64 refCount; 177 | 178 | public: 179 | UINT InternalLength; 180 | DebuggableUsage InternalUsage; 181 | D3DFORMAT InternalFormat; 182 | D3DPOOL InternalPool; 183 | 184 | long lockCount; 185 | bool isSoftIndexBufferUP; 186 | 187 | union 188 | { 189 | void* voidBytes; 190 | BYTE* u8Bytes; 191 | unsigned short* shortBytes; 192 | unsigned long* longBytes; 193 | SIZE_T pointerNumber; 194 | } rawBytes; 195 | }; 196 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | *.cso 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush 296 | .cr/ 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVertexShader9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DVertexShader9Hook.h" 4 | #include "ShaderBase.h" 5 | #include "ShaderJIT.h" 6 | 7 | static std::vector aliveVertShaders; 8 | 9 | void IDirect3DVertexShader9Hook::CreateVertexShader(const DWORD* const pFunction) 10 | { 11 | if (!pFunction) 12 | return; 13 | 14 | ShaderInfo tempVertexShaderInfo; 15 | AnalyzeShader(pFunction, tempVertexShaderInfo 16 | #ifdef _DEBUG 17 | ,"NoneVS" 18 | #endif 19 | ); 20 | 21 | if (tempVertexShaderInfo.isPixelShader) 22 | { 23 | // This is not a vertex shader! 24 | __debugbreak(); 25 | } 26 | 27 | switch (tempVertexShaderInfo.shaderMajorVersion) 28 | { 29 | case 1: 30 | case 2: 31 | case 3: 32 | // We're good! 33 | break; 34 | default: 35 | // This is not a valid D3D9 shader! 36 | { 37 | __debugbreak(); 38 | } 39 | break; 40 | } 41 | 42 | shaderBytecode.resize(tempVertexShaderInfo.shaderLengthDWORDs); 43 | memcpy(&shaderBytecode.front(), pFunction, tempVertexShaderInfo.shaderLengthDWORDs * sizeof(DWORD) ); 44 | 45 | // Bad hack to rebase all of the pointer offsets, fix plz! 46 | AnalyzeShader(&shaderBytecode.front(), vertexShaderInfo 47 | #ifdef _DEBUG 48 | ,"NoneVS" 49 | #endif 50 | ); 51 | 52 | if (tempVertexShaderInfo.shaderMajorVersion == 3) 53 | { 54 | const std::vector& declaredRegs = tempVertexShaderInfo.declaredRegisters; 55 | const unsigned numDeclaredRegs = declaredRegs.size(); 56 | #ifdef _DEBUG 57 | outPositionRegisterIndex = 0xFFFFFFFF; 58 | #endif 59 | for (unsigned x = 0; x < numDeclaredRegs; ++x) 60 | { 61 | const DeclaredRegister& thisReg = declaredRegs[x]; 62 | if (!thisReg.isOutputRegister) 63 | continue; 64 | if (thisReg.usageType == D3DDECLUSAGE_POSITION || thisReg.usageType == D3DDECLUSAGE_POSITIONT) 65 | { 66 | static const unsigned NUM_PRE_OT_REGISTERS = 3u; // This is the dedicated oPos, oFog, and oPts registers used by pre-vs_3_0 shader models 67 | outPositionRegisterIndex = NUM_PRE_OT_REGISTERS + thisReg.registerIndex; 68 | break; 69 | } 70 | } 71 | #ifdef _DEBUG 72 | if (outPositionRegisterIndex == 0xFFFFFFFF) 73 | { 74 | __debugbreak(); // Output Position register not found! 75 | } 76 | #endif 77 | } 78 | else 79 | { 80 | // For vertex shaders before version vs_3_0, this should always be the dedicated oPos output register 81 | outPositionRegisterIndex = 0; 82 | } 83 | 84 | parentDevice->LockDeviceCS(); 85 | aliveVertShaders.push_back(this); 86 | parentDevice->UnlockDeviceCS(); 87 | 88 | //JitLoadShader(); 89 | } 90 | 91 | /*virtual*/ IDirect3DVertexShader9Hook::~IDirect3DVertexShader9Hook() 92 | { 93 | parentDevice->LockDeviceCS(); 94 | const unsigned numAliveShaders = aliveVertShaders.size(); 95 | bool foundAndErased = false; 96 | for (unsigned x = 0; x < numAliveShaders; ++x) 97 | { 98 | if (aliveVertShaders[x] == this) 99 | { 100 | aliveVertShaders.erase(aliveVertShaders.begin() + x); 101 | foundAndErased = true; 102 | break; 103 | } 104 | } 105 | #ifdef _DEBUG 106 | if (!foundAndErased) 107 | { 108 | __debugbreak(); // Should never be here! 109 | } 110 | #endif 111 | parentDevice->UnlockDeviceCS(); 112 | 113 | shaderBytecode.clear(); 114 | #ifdef WIPE_ON_DESTRUCT_D3DHOOKOBJECT 115 | memset(this, 0x00000000, sizeof(*this) - (sizeof(shaderBytecode) + sizeof(vertexShaderInfo) ) ); 116 | #endif 117 | } 118 | 119 | /*** IUnknown methods ***/ 120 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexShader9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 121 | { 122 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 123 | if (ret == NOERROR) 124 | { 125 | *ppvObj = this; 126 | AddRef(); 127 | } 128 | return ret; 129 | } 130 | 131 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVertexShader9Hook::AddRef(THIS) 132 | { 133 | ULONG ret = realObject->AddRef(); 134 | ++refCount; 135 | return ret; 136 | } 137 | 138 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVertexShader9Hook::Release(THIS) 139 | { 140 | ULONG ret = realObject->Release(); 141 | if (--refCount == 0) 142 | { 143 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 144 | char printBuffer[128] = {0}; 145 | #pragma warning(push) 146 | #pragma warning(disable:4996) 147 | sprintf(printBuffer, "Fully releasing hooked Vertex Shader %p\n", this); 148 | #pragma warning(pop) 149 | OutputDebugStringA(printBuffer); 150 | #endif 151 | delete this; 152 | } 153 | return ret; 154 | } 155 | 156 | /*** IDirect3DVertexShader9 methods ***/ 157 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexShader9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 158 | { 159 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 160 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 161 | if (FAILED(ret) ) 162 | { 163 | *ppDevice = NULL; 164 | return ret; 165 | } 166 | 167 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 168 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 169 | { 170 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 171 | } 172 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 173 | 174 | *ppDevice = parentDevice; 175 | return ret; 176 | } 177 | 178 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexShader9Hook::GetFunction(THIS_ void* pData,UINT* pSizeOfData) 179 | { 180 | HRESULT ret = realObject->GetFunction(pData, pSizeOfData); 181 | return ret; 182 | } 183 | 184 | void IDirect3DVertexShader9Hook::JitLoadShader() 185 | { 186 | #ifdef FORCE_INTERPRETED_VERTEX_SHADER 187 | return; 188 | #endif 189 | 190 | const char* const jitName = ConstructShaderJITName(vertexShaderInfo); 191 | char jitFilenameBuffer[MAX_PATH] = {0}; 192 | #pragma warning(push) 193 | #pragma warning(disable:4996) 194 | sprintf(jitFilenameBuffer, "%s\\%s.dll", shaderJITTempDirectory, jitName); 195 | #pragma warning(pop) 196 | HMODULE hm = LoadLibraryA(jitFilenameBuffer); 197 | 198 | triedJit = true; 199 | 200 | static const char* const shaderMainExportName = "@VertexShaderMain@4"; 201 | static const char* const shaderMainExportName4 = "@VertexShaderMain4@4"; 202 | 203 | if (hm) 204 | { 205 | jitShaderMain = (VSEntry)GetProcAddress(hm, shaderMainExportName); 206 | jitShaderMain4 = (VSEntry)GetProcAddress(hm, shaderMainExportName4); 207 | if (!jitShaderMain) 208 | { 209 | DbgBreakPrint("Error: Cannot find VertexShaderMain in existing JIT DLL"); 210 | } 211 | else if (!jitShaderMain4) 212 | { 213 | DbgPrint("Warning: Cannot find VertexShaderMain4 in existing JIT DLL"); 214 | } 215 | } 216 | else 217 | { 218 | if (!JITNewShader(vertexShaderInfo, jitName) ) 219 | { 220 | DbgBreakPrint("Error: Failed to JIT Vertex Shader"); 221 | } 222 | else 223 | { 224 | HMODULE hm2 = LoadLibraryA(jitFilenameBuffer); 225 | if (!hm2) 226 | { 227 | DbgBreakPrint("Error: Failed to load recently JIT'd Vertex Shader"); 228 | return; 229 | } 230 | jitShaderMain = (VSEntry)GetProcAddress(hm2, shaderMainExportName); 231 | jitShaderMain4 = (VSEntry)GetProcAddress(hm2, shaderMainExportName4); 232 | if (!jitShaderMain) 233 | { 234 | DbgBreakPrint("Error: Cannot find VertexShaderMain in newly created JIT DLL"); 235 | return; 236 | } 237 | else if (!jitShaderMain4) 238 | { 239 | DbgPrint("Warning: Cannot find VertexShaderMain4 in newly created JIT DLL"); 240 | return; 241 | } 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Software D3D9 2 | 3 | Performs software emulation for all of Direct3D 9 and Direct3D 9Ex via a proxy DLL (drop-in proxy replacement for Microsoft's official **d3d9.dll**). This project is intended to be a working full software emulation of Direct3D9 for educational purposes. It is intended to work with real games and other programs, and eventually should support a high level of compatibility with a wide range of existing D3D9 games and programs. Since this is software emulating hardware, this will never be as fast as a real GPU. Hopefully people can use this to learn more about how D3D9 works under the hood and to feel inspired about how 3D graphics works as a larger whole. 4 | 5 | ## Getting Started 6 | 7 | Download the repo and open **Software_d3d9.sln** in Visual Studio 2017 or higher (or if you really want to you could hack the project and solution files to use an earlier version of Visual Studio). 8 | 9 | ### Prerequisites 10 | 11 | You will need to have Visual Studio 2017 or higher installed, both for building this project, and for runtime JIT as well. 12 | ``` 13 | Get Visual Studio 2017 from Microsoft, it's free now for noncommercial use and it's still arguably the best IDE on Windows for C++ programming! 14 | ``` 15 | 16 | You will also need to have the DirectX9 SDK installed on your computer. The latest version of this is the "June 2010" DirectX SDK available here (https://www.microsoft.com/en-us/download/details.aspx?id=6812). This is currently needed for access to D3DX9, which will eventually be removed as a requirement in the future. 17 | 18 | After installing the DirectX SDK, you need to add the Include and Lib paths to Visual Studio so that it knows where to look for these new **.h** header and **.lib** library files. 19 | ``` 20 | How this is done differs between versions of Visual Studio, but the way to do it in VS2017 is: 21 | Go to the Property Manager (note that this is different than the Property Window), and under the Debug|Win32 or Release|Win32 folders, right-click and go to Properties for the Microsoft.Cpp.Win32.user property sheet. 22 | Now go to VC++ Directories in the left hand tree view. 23 | For Include Directories, add the entry that corresponds to the Includes directory where you just installed the DirectX SDK. By default that path will be: C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include 24 | For Library Directories, add the entry that corresponds to the Lib directory where you just installed the DirectX SDK. Make sure to pick the right processor architecture that matches the current build configuration (so for a Win32 build configuration, you should select the x86 directory, and for a Win64 build configuration you should select the x64 directory). By default that path will be one of: 25 | For x86: C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86 26 | For x64: C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x64 27 | Now click OK at the bottom to save your changes, and you should be good to go! 28 | ``` 29 | 30 | ### Building 31 | 32 | Open the **Software_d3d9.sln** solution in Visual Studio 2017 (or higher). 33 | Once the project and all associated files have finished loading/initializing, select the desired Solution Configuration for your target program. 34 | ``` 35 | Currently supported targets are: 36 | Debug - Win32 37 | Release - Win32 38 | 39 | Future configuration targets will support Win64 as well. 40 | ``` 41 | 42 | If you run into any compilation errors with the C/C++ code, they're likely due to the language conformance setting in Visual Studio. This project was written without using many modern C/C++ features (basically the C++11 featureset), but also not necessarily conforming to any future strictness that may be added into the C++ standard. 43 | 44 | If you experience missing includes for **d3dx9.h**, then make sure that you have the DirectX SDK installed (see above section) and that you have properly added the DirectX SDK's Include folder to your Include Directories. 45 | ``` 46 | By default, this path should be: C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include 47 | ``` 48 | 49 | If you run into any compilation errors with the HLSL code, that's likely due to shader model or shader type being set incorrectly. Make sure that the Shader Model is set to Shader Model 2 or Shader Model 3. 50 | ``` 51 | For Pixel Shaders, this should be either "ps_2_0" or "ps_3_0". 52 | For Vertex Shaders, this should be either "vs_2_0" or "vs_3_0". 53 | It's probably a good idea to keep all of the shaders built in this project on the same version if possible. 54 | ``` 55 | 56 | If you run into any linker errors, check and make sure that all of the **.c** and **.cpp** files are properly added to the project and that they are properly marked as "C/C++ compiler" under the "Item Type" property for each file so that they properly participate in the build. 57 | 58 | If you have linker errors relating to **d3dx9.lib**, then ensure that you have properly added the DirectX SDK's Lib folder to your Include Directories. 59 | ``` 60 | By default, this path should be: 61 | For x86: C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86 62 | For x64: C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x64 63 | ``` 64 | 65 | ## Deployment 66 | 67 | After building, go to the appropriate build output files folder depending on your build configuration: 68 | ``` 69 | Debug/Win32: .\Debug\ 70 | Release/Win32: .\Release\ 71 | Debug/Win64: .\x64\Debug\ 72 | Release/Win64: .\x64\Release\ 73 | ``` 74 | Copy the newly built **d3d9.dll** file from that folder and paste it into the directory next to the program that you wish to test with it. Depending on how this program is launched and how it is configured to load DLLs, you may want to instead place the proxy DLL into the working directory of your test program rather than the immediate directory in which the executable resides. Due to how DLL loading works on Windows (unless programs specify otherwise), the proxy **d3d9.dll** should be picked up rather than the true Microsoft **d3d9.dll**. 75 | 76 | If you run into errors while trying to launch your program about a missing **d3dx9_43.dll** (or any other version of "d3dx9_XX.dll"), then be sure to install the DirectX End-User Runtimes (https://www.microsoft.com/en-us/download/details.aspx?id=8109) before trying to launch your program. This should not be a problem on Windows 8 and up as these DLLs ship with the operating system, but may be an issue on Windows XP, Windows Vista, or Windows 7. 77 | 78 | ## Built With 79 | 80 | * [Wrappit] (https://www.codeproject.com/Articles/16541/Create-your-Proxy-DLLs-automatically) - Used to generate the proxy DLL template (which has since been very heavily modified). 81 | * [D3DX9] (https://www.microsoft.com/en-us/download/details.aspx?id=6812) - Used as a vector maths library (D3DXMath) and for some debug functionality (D3DXSaveSurfaceToFile(), for example, is useful for debugging surfaces dumped from memory to disk). In the future I plan to remove this as a requirement and replace D3DXMath with XNAMath. 82 | 83 | ## Authors 84 | 85 | * **Tom Lopes** - *Initial work* - [code-tom-code](https://github.com/code-tom-code) 86 | 87 | See also the list of [contributors](https://github.com/code-tom-code/Software_D3D9/contributors) who participated in this project. 88 | 89 | ## License 90 | 91 | This project is licensed under the zLib/LibPNG License - see the [LICENSE.txt](LICENSE.txt) file for details 92 | 93 | ## Acknowledgments 94 | 95 | * Thanks to Michael Chourdakis for his Wrappit code (https://www.codeproject.com/Articles/16541/Create-your-Proxy-DLLs-automatically). It's been useful for me for years now for easily generating a starting-point for a proxy DLL. 96 | * Thanks to Microsoft and MSDN for having awesome documentation for the Direct3D9/9Ex API's and the HLSL shader bytecode format docs to go off of. They have really helped with navigating edge cases and solving tricky problems. 97 | * Thanks to rygorous (Fabian 'ryg' Giesen) for authoring his series of articles that illuminate how modern GPUs work under the hood in great detail (https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-graphics-pipeline-2011-index/). 98 | -------------------------------------------------------------------------------- /Software_d3d9/FixedFuncEmu/FFPS/Include/FFPS_ApplyColorStage.fxh: -------------------------------------------------------------------------------- 1 | #define MAKE_COLOR_STAGE_FUNCNAME(x) ApplyColorStage##x 2 | #define MAKE_ALPHA_STAGE_FUNCNAME(x) ApplyAlphaStage##x 3 | 4 | // Temp. defines for testing! 5 | /*#define COLOROP D3DTOP_SELECTARG1 6 | #define STAGE_NUM 0*/ 7 | 8 | inline float3 MAKE_COLOR_STAGE_FUNCNAME(STAGE_NUM)(in const float4 ARG1, 9 | in const float4 ARG2, 10 | in const float4 ARG0, 11 | in const float VertexAlpha, 12 | in const float CurrentTexStageTextureAlpha, 13 | in const float4 CURRENT, 14 | inout float4 NextStageTexcoordsForBump, 15 | inout float NextStageLuma) 16 | { 17 | // Reset the luma for the next stage: 18 | #if COLOROP != D3DTOP_BUMPENVMAPLUMINANCE 19 | NextStageLuma = 1.0f; 20 | #endif // #if COLOROP != D3DTOP_BUMPENVMAPLUMINANCE 21 | 22 | #if COLOROP == D3DTOP_DISABLE 23 | return CURRENT.rgb; 24 | #elif COLOROP == D3DTOP_SELECTARG1 25 | return ARG1.rgb; 26 | #elif COLOROP == D3DTOP_SELECTARG2 27 | return ARG2.rgb; 28 | #elif COLOROP == D3DTOP_MODULATE 29 | return ARG1.rgb * ARG2.rgb; 30 | #elif COLOROP == D3DTOP_MODULATE2X 31 | return ARG1.rgb * ARG2.rgb * 2.0f; 32 | #elif COLOROP == D3DTOP_MODULATE4X 33 | return ARG1.rgb * ARG2.rgb * 4.0f; 34 | #elif COLOROP == D3DTOP_ADD 35 | return ARG1.rgb + ARG2.rgb; 36 | #elif COLOROP == D3DTOP_ADDSIGNED 37 | return ARG1.rgb + ARG2.rgb - 0.5f; 38 | #elif COLOROP == D3DTOP_ADDSIGNED2X 39 | return (ARG1.rgb + ARG2.rgb - 0.5f) * 2.0f; 40 | #elif COLOROP == D3DTOP_SUBTRACT 41 | return ARG1.rgb - ARG2.rgb; 42 | #elif COLOROP == D3DTOP_ADDSMOOTH 43 | return ARG1.rgb + ARG2.rgb - ARG1.rgb * ARG2.rgb; 44 | #elif COLOROP == D3DTOP_BLENDDIFFUSEALPHA 45 | return ARG1.rgb * VertexAlpha + ARG2.rgb * (1.0f - VertexAlpha); 46 | #elif COLOROP == D3DTOP_BLENDTEXTUREALPHA 47 | return ARG1.rgb * CurrentTexStageTextureAlpha + ARG2.rgb * (1.0f - CurrentTexStageTextureAlpha); 48 | #elif COLOROP == D3DTOP_BLENDFACTORALPHA 49 | return ARG1.rgb * TFACTOR.a + ARG2.rgb * (1.0f - TFACTOR.a); 50 | #elif COLOROP == D3DTOP_BLENDTEXTUREALPHAPM 51 | return ARG1.rgb + ARG2.rgb * (1.0f - CurrentTexStageTextureAlpha); 52 | #elif COLOROP == D3DTOP_BLENDCURRENTALPHA 53 | return ARG1.rgb * CURRENT.a + ARG2.rgb * (1.0f - CURRENT.a); 54 | #elif COLOROP == D3DTOP_PREMODULATE /* The output of stage n is arg1. Additionally, if there is a texture in stage n + 1, any D3DTA_CURRENT in stage n + 1 is premultiplied by texture in stage n + 1. */ 55 | return ARG1.rgb; 56 | #elif COLOROP == D3DTOP_MODULATEALPHA_ADDCOLOR 57 | return ARG1.rgb + ARG1.aaa * ARG2.rgb; 58 | #elif COLOROP == D3DTOP_MODULATECOLOR_ADDALPHA 59 | return ARG1.rgb * ARG2.rgb + ARG1.aaa; 60 | #elif COLOROP == D3DTOP_MODULATEINVALPHA_ADDCOLOR 61 | return (1.0f - ARG1.a) * ARG2.rgb + ARG1.rgb; 62 | #elif COLOROP == D3DTOP_MODULATEINVCOLOR_ADDALPHA 63 | return (1.0f - ARG1.rgb) * ARG2.rgb + ARG1.aaa; 64 | #elif COLOROP == D3DTOP_BUMPENVMAP 65 | #if STAGE_NUM < 7 66 | const float xComp = dot(ARG1.rgb, BUMPENVMAT[STAGE_NUM]._m00_m01_m02); 67 | const float yComp = dot(ARG1.rgb, BUMPENVMAT[STAGE_NUM]._m10_m11_m12); 68 | NextStageTexcoordsForBump.xy += float2(xComp, yComp); 69 | #endif // #if STAGE_NUM < 7 70 | return CURRENT.rgb; 71 | #elif COLOROP == D3DTOP_BUMPENVMAPLUMINANCE 72 | #if STAGE_NUM < 7 73 | const float xComp = dot(ARG1.rgb, BUMPENVMAT[STAGE_NUM]._m00_m01_m02); 74 | const float yComp = dot(ARG1.rgb, BUMPENVMAT[STAGE_NUM]._m10_m11_m12); 75 | const float lumaScale = BUMPENVMAT[STAGE_NUM]._m03; 76 | const float lumaBias = BUMPENVMAT[STAGE_NUM]._m13; 77 | const float lumaValue = saturate(mad(ARG1.b, lumaScale, lumaBias) ); 78 | NextStageTexcoordsForBump.xy += float2(xComp, yComp); 79 | NextStageLuma = lumaValue; 80 | #endif // #if STAGE_NUM < 7 81 | return CURRENT.rgb; 82 | #elif COLOROP == D3DTOP_DOTPRODUCT3 83 | const float3 signedARG1 = (ARG1.rgb - 0.5f) * 4.0f; 84 | const float3 signedARG2 = (ARG2.rgb - 0.5f); 85 | const float dotResult = saturate(dot(signedARG1, signedARG2) ); 86 | return float3(dotResult, dotResult, dotResult); 87 | #elif COLOROP == D3DTOP_MULTIPLYADD 88 | return mad(ARG2.rgb, ARG1.rgb, ARG0.rgb); 89 | #elif COLOROP == D3DTOP_LERP 90 | return lerp(ARG2.rgb, ARG1.rgb, ARG0.rgb); 91 | #else 92 | #error ERROR: Unknown D3DTOP value passed to COLOROP used! 93 | //return float3(0.0f, 0.0f, 0.0f); 94 | #endif 95 | } 96 | 97 | inline float MAKE_ALPHA_STAGE_FUNCNAME(STAGE_NUM)(in const float4 ARG1, 98 | in const float4 ARG2, 99 | in const float4 ARG0, 100 | in const float VertexAlpha, 101 | in const float CurrentTexStageTextureAlpha, 102 | in const float4 CURRENT) 103 | { 104 | 105 | // This is a little bit strange, but in the case of DOT3 color-ops, they override whatever the alpha op is and broadcast 106 | // the dot3 result into the alpha channel instead: 107 | #if COLOROP == D3DTOP_DOTPRODUCT3 108 | { 109 | const float3 signedARG1 = (ARG1.rgb - 0.5f) * 4.0f; 110 | const float3 signedARG2 = (ARG2.rgb - 0.5f); 111 | const float dotResult = saturate(dot(signedARG1, signedARG2) ); 112 | return dotResult; 113 | } 114 | #endif 115 | 116 | // It looks like D3DTOP_DISABLE passed to ALPHAOP means D3DTOP_SELECTARG1 and ARG1 = D3DTA_TFACTOR 117 | #if ALPHAOP == D3DTOP_DISABLE 118 | return CURRENT.a; 119 | //return ARG1.a; 120 | #elif ALPHAOP == D3DTOP_SELECTARG1 121 | return ARG1.a; 122 | #elif ALPHAOP == D3DTOP_SELECTARG2 123 | return ARG2.a; 124 | #elif ALPHAOP == D3DTOP_MODULATE 125 | return ARG1.a * ARG2.a; 126 | #elif ALPHAOP == D3DTOP_MODULATE2X 127 | return ARG1.a * ARG2.a * 2.0f; 128 | #elif ALPHAOP == D3DTOP_MODULATE4X 129 | return ARG1.a * ARG2.a * 4.0f; 130 | #elif ALPHAOP == D3DTOP_ADD 131 | return ARG1.a + ARG2.a; 132 | #elif ALPHAOP == D3DTOP_ADDSIGNED 133 | return ARG1.a + ARG2.a - 0.5f; 134 | #elif ALPHAOP == D3DTOP_ADDSIGNED2X 135 | return (ARG1.a + ARG2.a - 0.5f) * 2.0f; 136 | #elif ALPHAOP == D3DTOP_SUBTRACT 137 | return ARG1.a - ARG2.a; 138 | #elif ALPHAOP == D3DTOP_ADDSMOOTH 139 | return ARG1.a + ARG2.a - ARG1.a * ARG2.a; 140 | #elif ALPHAOP == D3DTOP_BLENDDIFFUSEALPHA 141 | return ARG1.a * VertexAlpha + ARG2.a * (1.0f - VertexAlpha); 142 | #elif ALPHAOP == D3DTOP_BLENDTEXTUREALPHA 143 | return ARG1.a * CurrentTexStageTextureAlpha + ARG2.a * (1.0f - CurrentTexStageTextureAlpha); 144 | #elif ALPHAOP == D3DTOP_BLENDFACTORALPHA 145 | return ARG1.a * TFACTOR.a + ARG2.a * (1.0f - TFACTOR.a); 146 | #elif ALPHAOP == D3DTOP_BLENDTEXTUREALPHAPM 147 | return ARG1.a + ARG2.a * (1.0f - CurrentTexStageTextureAlpha); 148 | #elif ALPHAOP == D3DTOP_BLENDCURRENTALPHA 149 | return ARG1.a * CURRENT.a + ARG2.a * (1.0f - CURRENT.a); 150 | #elif ALPHAOP == D3DTOP_PREMODULATE /* The output of stage n is arg1. Additionally, if there is a texture in stage n + 1, any D3DTA_CURRENT in stage n + 1 is premultiplied by texture in stage n + 1. */ 151 | return ARG1.a; 152 | #elif ALPHAOP == D3DTOP_MODULATEALPHA_ADDCOLOR // Note: This is technically illegal to use as an D3DTSS_ALPHAOP 153 | return 1.0f; 154 | #elif ALPHAOP == D3DTOP_MODULATECOLOR_ADDALPHA // Note: This is technically illegal to use as an D3DTSS_ALPHAOP 155 | return 1.0f; 156 | #elif ALPHAOP == D3DTOP_MODULATEINVALPHA_ADDCOLOR // Note: This is technically illegal to use as an D3DTSS_ALPHAOP 157 | return 1.0f; 158 | #elif ALPHAOP == D3DTOP_MODULATEINVCOLOR_ADDALPHA // Note: This is technically illegal to use as an D3DTSS_ALPHAOP 159 | return 1.0f; 160 | #elif ALPHAOP == D3DTOP_BUMPENVMAP // Note: This is technically illegal to use as an D3DTSS_ALPHAOP 161 | return 1.0f; 162 | #elif ALPHAOP == D3DTOP_BUMPENVMAPLUMINANCE // Note: This is technically illegal to use as an D3DTSS_ALPHAOP 163 | return 1.0f; 164 | #elif ALPHAOP == D3DTOP_DOTPRODUCT3 165 | const float3 signedARG1 = (ARG1.rgb - 0.5f) * 4.0f; 166 | const float3 signedARG2 = (ARG2.rgb - 0.5f); 167 | const float dotResult = saturate(dot(signedARG1, signedARG2) ); 168 | return dotResult; 169 | #elif ALPHAOP == D3DTOP_MULTIPLYADD 170 | return mad(ARG2.a, ARG1.a, ARG0.a); 171 | #elif ALPHAOP == D3DTOP_LERP 172 | return lerp(ARG2.a, ARG1.a, ARG0.a); 173 | #else 174 | #error Unknown D3DTSS_ALPHAOP value used! 175 | //return float3(0.0f, 0.0f, 0.0f); 176 | #endif 177 | } 178 | 179 | #undef MAKE_ALPHA_STAGE_FUNCNAME 180 | #undef MAKE_COLOR_STAGE_FUNCNAME 181 | -------------------------------------------------------------------------------- /Software_d3d9/ShaderJIT.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ShaderJIT.h" 4 | #include "IDirect3DDevice9Hook.h" 5 | #include "resource.h" 6 | 7 | extern HINSTANCE hLThisDLL; 8 | 9 | #pragma warning(push) 10 | #pragma warning(disable:4996) 11 | 12 | void LoadPrefixFileInternal(std::vector& cppfile) 13 | { 14 | #pragma warning(push) 15 | #pragma warning(disable:4302) // warning C4302: 'type cast': truncation from 'LPSTR' to 'WORD' 16 | HRSRC cppResource = FindResourceA(hLThisDLL, MAKEINTRESOURCEA(IDR_CPP1), "CPP"); 17 | #pragma warning(pop) 18 | if (cppResource) 19 | { 20 | HGLOBAL loadedResource = LoadResource(hLThisDLL, cppResource); 21 | if (loadedResource) 22 | { 23 | const unsigned resourceSize = SizeofResource(hLThisDLL, cppResource); 24 | if (resourceSize > 0) 25 | { 26 | const void* const resourceBytes = LockResource(loadedResource); 27 | if (resourceBytes) 28 | { 29 | cppfile.resize(resourceSize); 30 | memcpy(&cppfile.front(), resourceBytes, resourceSize); 31 | return; 32 | } 33 | } 34 | } 35 | } 36 | 37 | __debugbreak(); // Should never be here! 38 | } 39 | 40 | // Not multithread-safe! 41 | const char* const ConstructShaderJITName(const ShaderInfo& shaderInfo) 42 | { 43 | static char buffer[MAX_PATH] = {0}; 44 | #pragma warning(push) 45 | #pragma warning(disable:4996) 46 | // Looks like: "ps_3_0_len114_hash0xD9FF5963d" 47 | sprintf(buffer, "%cs_%u_%u_len%u_hash0x%08X%c", shaderInfo.isPixelShader ? 'p' : 'v', shaderInfo.shaderMajorVersion, shaderInfo.shaderMinorVersion, shaderInfo.shaderLengthDWORDs, shaderInfo.shaderBytecodeHash, 48 | #ifdef _DEBUG 49 | 'd' 50 | #else 51 | 'r' 52 | #endif 53 | ); 54 | #pragma warning(pop) 55 | return buffer; 56 | } 57 | 58 | static inline const bool JITBATFile(const ShaderInfo& shaderInfo, const char* const shaderFilename) 59 | { 60 | char batfilename[MAX_PATH] = {0}; 61 | // Looks like: "shaderjit\ps_3_0_len114_hash0xD9FF5963d.bat" 62 | sprintf(batfilename, "%s\\%s.bat", shaderJITTempDirectory, shaderFilename); 63 | HANDLE hBatFile = CreateFileA(batfilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 64 | if (hBatFile == INVALID_HANDLE_VALUE) 65 | { 66 | DbgBreakPrint("Error in CreateFile"); 67 | return false; 68 | } 69 | 70 | static std::vector batfile; 71 | 72 | batfile.clear(); 73 | 74 | #ifdef _DEBUG 75 | static const char* const compileDefines = "/D \"WIN32\"" 76 | " /D \"_DEBUG\"" 77 | " /D \"_WINDOWS\"" 78 | " /D \"_USRDLL\"" 79 | " /D \"_WINDLL\""; 80 | #else // Release 81 | static const char* const compileDefines = "/D \"WIN32\"" 82 | " /D \"NDEBUG\"" 83 | " /D \"_WINDOWS\"" 84 | " /D \"_USRDLL\"" 85 | " /D \"_WINDLL\""; 86 | #endif // #ifdef _DEBUG 87 | 88 | // TODO: Don't hardcode these paths... 89 | #ifdef _DEBUG 90 | static const char* const compileString = "cl.exe /c /I \"C:\\Program Files (x86)\\Microsoft DirectX SDK (June 2010)\\Include\" /FAcs /Fa /analyze- /W3 /Zc:wchar_t /ZI /Od /fp:precise /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /EHsc /nologo /GS %s %s.cpp\r\n"; 91 | #else // Release 92 | static const char* const compileString = "cl.exe /c /I \"C:\\Program Files (x86)\\Microsoft DirectX SDK (June 2010)\\Include\" /FAcs /Fa /analyze- /W3 /Zc:wchar_t /Zi /GS- /GL /Gy /Gm- /O2 /Ob2 /fp:fast /GF /WX- /Zc:forScope /arch:AVX2 /Gd /Oy- /Oi /MT /Ot %s %s.cpp\r\n"; 93 | #endif // #ifdef _DEBUG 94 | 95 | #ifdef _M_X64 96 | #define LIBPATH "/LIBPATH:\"C:\\Program Files (x86)\\Microsoft DirectX SDK (June 2010)\\Lib\\x64\"" 97 | #else 98 | #define LIBPATH "/LIBPATH:\"C:\\Program Files (x86)\\Microsoft DirectX SDK (June 2010)\\Lib\\x86\"" 99 | #endif 100 | 101 | #ifdef _M_X64 102 | #define MACHINE_PLATFORM "/MACHINE:X64" 103 | #define SAFESEH_FLAG "" // SafeSEH is not supported on x64 104 | #else 105 | #define MACHINE_PLATFORM "/MACHINE:X86" 106 | #define SAFESEH_FLAG "/SAFESEH" 107 | #endif 108 | 109 | // TODO: Don't hardcode these paths... 110 | #ifdef _DEBUG 111 | static const char* const linkString = "link.exe " LIBPATH " /DEBUG /DLL " MACHINE_PLATFORM " /SUBSYSTEM:WINDOWS /NOLOGO /NXCOMPAT %s.obj\r\n"; 112 | #else // Release 113 | static const char* const linkString = "link.exe " LIBPATH " /DEBUG /DLL " MACHINE_PLATFORM " /SUBSYSTEM:WINDOWS /NODEFAULTLIB /ENTRY:DllMain /NOLOGO /NXCOMPAT /LTCG /DLL /DYNAMICBASE \"Kernel32.lib\" \"libucrt.lib\" /OPT:REF " SAFESEH_FLAG " /INCREMENTAL:NO /OPT:ICF %s.obj\r\n"; 114 | #endif // #ifdef _DEBUG 115 | 116 | // Set up VS command prompt 117 | { 118 | // TODO: Don't hardcode this path... 119 | #ifdef _M_X64 120 | static const char* const invokeVSDevCmd = "call \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat\"\r\n"; 121 | #else 122 | static const char* const invokeVSDevCmd = "call \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\Common7\\Tools\\VsDevCmd.bat\"\r\n"; 123 | #endif 124 | AppendString(batfile, invokeVSDevCmd); 125 | } 126 | 127 | // Compile 128 | { 129 | char batBuffer[1024] = {0}; 130 | sprintf(batBuffer, compileString, compileDefines, shaderFilename); 131 | AppendString(batfile, batBuffer); 132 | } 133 | 134 | // Link 135 | { 136 | char batBuffer[1024] = {0}; 137 | sprintf(batBuffer, linkString, shaderFilename); 138 | AppendString(batfile, batBuffer); 139 | } 140 | 141 | DWORD numBytesWritten = 0; 142 | if (!WriteFile(hBatFile, &(batfile.front() ), batfile.size(), &numBytesWritten, NULL) ) 143 | { 144 | DbgBreakPrint("Error in WriteFile"); 145 | return false; 146 | } 147 | 148 | if (batfile.size() != numBytesWritten) 149 | { 150 | DbgBreakPrint("Error: Num bytes written doesn't match for bat file"); 151 | return false; 152 | } 153 | 154 | if (!CloseHandle(hBatFile) ) 155 | { 156 | DbgBreakPrint("Error in CloseHandle"); 157 | return false; 158 | } 159 | 160 | return true; 161 | } 162 | 163 | static inline const bool CompileLinkDLL(const ShaderInfo& shaderInfo, const char* const shaderFilename) 164 | { 165 | char batfilename[MAX_PATH] = {0}; 166 | // Looks like: "ps_3_0_len114_hash0xD9FF5963d.bat" 167 | sprintf(batfilename, "%s.bat", shaderFilename); 168 | 169 | char commandLine[MAX_PATH] = {0}; 170 | sprintf(commandLine, "cmd.exe /C \"%s\"", batfilename); 171 | 172 | STARTUPINFOA si = {0}; 173 | si.cb = sizeof(STARTUPINFOA); 174 | PROCESS_INFORMATION pi = {0}; 175 | 176 | char currentDirectory[MAX_PATH] = {0}; 177 | sprintf(currentDirectory, ".\\%s\\", shaderJITTempDirectory); 178 | 179 | // Either show the shadercompile window (default), or hide it 180 | const DWORD createProcessFlags = 181 | #ifdef DEBUG_SHOW_SHADERCOMPILE_WINDOW 182 | 0x00000000 183 | #else 184 | CREATE_NO_WINDOW 185 | #endif 186 | ; 187 | 188 | if (!CreateProcessA(NULL, commandLine, NULL, NULL, FALSE, createProcessFlags, NULL, currentDirectory, &si, &pi) ) 189 | { 190 | DbgBreakPrint("Error in CreateProcess"); 191 | return false; 192 | } 193 | 194 | WaitForSingleObject(pi.hProcess, INFINITE); 195 | DWORD processExitCode = STILL_ACTIVE; 196 | if (!GetExitCodeProcess(pi.hProcess, &processExitCode) ) 197 | { 198 | DbgBreakPrint("Error in GetExitCodeProcess"); 199 | return false; 200 | } 201 | 202 | if (processExitCode == STILL_ACTIVE) 203 | { 204 | DbgBreakPrint("Error: Process did not terminate yet"); 205 | return false; 206 | } 207 | 208 | if (processExitCode == S_OK) 209 | { 210 | CloseHandle(pi.hProcess); 211 | CloseHandle(pi.hThread); 212 | return true; 213 | } 214 | 215 | CloseHandle(pi.hProcess); 216 | CloseHandle(pi.hThread); 217 | 218 | DbgBreakPrint("Error: There was an error while compiling or linking the shader JIT DLL"); 219 | OutputDebugStringA("Failure in shader JIT for shader: "); 220 | OutputDebugStringA(shaderFilename); 221 | OutputDebugStringA("\n"); 222 | 223 | return false; 224 | } 225 | 226 | const bool JITNewShader(const ShaderInfo& shaderInfo, const char* const shaderFilename) 227 | { 228 | if (!CreateDirectoryA(shaderJITTempDirectory, NULL) ) 229 | { 230 | switch (GetLastError() ) 231 | { 232 | case ERROR_ALREADY_EXISTS: 233 | // This is fine 234 | break; 235 | case ERROR_PATH_NOT_FOUND: 236 | // This is not fine! 237 | DbgBreakPrint("Error in CreateDirectory"); 238 | return false; 239 | } 240 | } 241 | 242 | if (!JITCPPFileInternal(shaderInfo, shaderFilename) ) 243 | { 244 | return false; 245 | } 246 | 247 | if (!JITBATFile(shaderInfo, shaderFilename) ) 248 | { 249 | return false; 250 | } 251 | 252 | if (!CompileLinkDLL(shaderInfo, shaderFilename) ) 253 | { 254 | return false; 255 | } 256 | 257 | return true; 258 | } 259 | 260 | #pragma warning(pop) 261 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVertexBuffer9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DVertexBuffer9Hook.h" 4 | #include "IDirect3DResource9Hook.h" 5 | #include "GlobalToggles.h" 6 | 7 | void IDirect3DVertexBuffer9Hook::CreateVertexBuffer(UINT _Length, const DebuggableUsage _Usage, DWORD _FVF, D3DPOOL _Pool) 8 | { 9 | InternalLength = _Length; 10 | InternalUsage = _Usage; 11 | InternalFVF = _FVF; 12 | InternalPool = _Pool; 13 | 14 | const unsigned magicDWORDLen = 15 | #ifdef VERTEX_BUFFER_MAGIC_COOKIE 16 | sizeof(DWORD); 17 | #else 18 | 0; 19 | #endif 20 | 21 | #ifdef VERTEX_BUFFER_ALLOC_PAGE_NOACCESS 22 | data = PageAllocWithNoAccessPage(InternalLength + magicDWORDLen); 23 | #else 24 | data = (BYTE* const)malloc(InternalLength + magicDWORDLen); 25 | #endif 26 | if (!data) 27 | { 28 | __debugbreak(); // Can't alloc our vertex buffer! 29 | } 30 | 31 | #ifdef VERTEX_BUFFER_MAGIC_COOKIE 32 | *(DWORD* const)&data[InternalLength] = 'VRTX'; 33 | #endif 34 | } 35 | 36 | #ifdef VERTEX_BUFFER_MAGIC_COOKIE 37 | static inline void ValidateMagicCookie(const std::vector& bytes, const unsigned length) 38 | { 39 | if (*(const DWORD* const)&bytes[length] != 'VRTX') 40 | { 41 | __debugbreak(); 42 | } 43 | } 44 | #endif // VERTEX_BUFFER_MAGIC_COOKIE 45 | 46 | /*** IUnknown methods ***/ 47 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 48 | { 49 | if (realObject) 50 | { 51 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 52 | if (ret == NOERROR) 53 | { 54 | *ppvObj = this; 55 | AddRef(); 56 | } 57 | return ret; 58 | } 59 | // TODO: Fix this 60 | return S_OK; 61 | } 62 | 63 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::AddRef(THIS) 64 | { 65 | ULONG ret = realObject ? realObject->AddRef() : (const ULONG)(refCount + 1); 66 | ++refCount; 67 | return ret; 68 | } 69 | 70 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::Release(THIS) 71 | { 72 | ULONG ret = realObject ? realObject->Release() : (const ULONG)(refCount - 1); 73 | if (--refCount == 0) 74 | { 75 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 76 | char printBuffer[128] = {0}; 77 | #pragma warning(push) 78 | #pragma warning(disable:4996) 79 | sprintf(printBuffer, "Fully releasing hooked Vertex Buffer %p\n", this); 80 | #pragma warning(pop) 81 | OutputDebugStringA(printBuffer); 82 | #endif 83 | delete this; 84 | } 85 | return ret; 86 | } 87 | 88 | /*** IDirect3DResource9 methods ***/ 89 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 90 | { 91 | if (!ppDevice) 92 | return D3DERR_INVALIDCALL; 93 | 94 | if (realObject) 95 | { 96 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 97 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 98 | if (FAILED(ret) ) 99 | { 100 | *ppDevice = NULL; 101 | return ret; 102 | } 103 | 104 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 105 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 106 | { 107 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 108 | } 109 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 110 | 111 | *ppDevice = parentDevice; 112 | return ret; 113 | } 114 | else 115 | { 116 | *ppDevice = parentDevice; 117 | return S_OK; 118 | } 119 | } 120 | 121 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) 122 | { 123 | if (realObject) 124 | { 125 | HRESULT ret = realObject->SetPrivateData(refguid, pData, SizeOfData, Flags); 126 | return ret; 127 | } 128 | return S_OK; 129 | } 130 | 131 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) 132 | { 133 | if (realObject) 134 | { 135 | HRESULT ret = realObject->GetPrivateData(refguid, pData, pSizeOfData); 136 | return ret; 137 | } 138 | return S_OK; 139 | } 140 | 141 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::FreePrivateData(THIS_ REFGUID refguid) 142 | { 143 | if (realObject) 144 | { 145 | HRESULT ret = realObject->FreePrivateData(refguid); 146 | return ret; 147 | } 148 | return S_OK; 149 | } 150 | 151 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::SetPriority(THIS_ DWORD PriorityNew) 152 | { 153 | if (realObject) 154 | { 155 | DWORD ret = realObject->SetPriority(PriorityNew); 156 | return ret; 157 | } 158 | return 0; 159 | } 160 | 161 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::GetPriority(THIS) 162 | { 163 | if (realObject) 164 | { 165 | DWORD ret = realObject->GetPriority(); 166 | return ret; 167 | } 168 | return S_OK; 169 | } 170 | 171 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::PreLoad(THIS) 172 | { 173 | if (realObject) 174 | realObject->PreLoad(); 175 | } 176 | 177 | COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::GetType(THIS) 178 | { 179 | if (realObject) 180 | { 181 | D3DRESOURCETYPE ret = realObject->GetType(); 182 | if (ret != D3DRTYPE_VERTEXBUFFER) 183 | { 184 | __debugbreak(); // Huh? 185 | } 186 | return ret; 187 | } 188 | return D3DRTYPE_VERTEXBUFFER; 189 | } 190 | 191 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::Lock(THIS_ UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags) 192 | { 193 | if (!ppbData) 194 | return D3DERR_INVALIDCALL; 195 | 196 | const DWORD validLockFlags = D3DLOCK_DISCARD | D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE; 197 | if (Flags & (~validLockFlags) ) 198 | return D3DERR_INVALIDCALL; // These are the only D3DLOCK flags valid for this function call 199 | 200 | if (SizeToLock == 0 && OffsetToLock > 0) 201 | return D3DERR_INVALIDCALL; 202 | 203 | if (OffsetToLock + SizeToLock > InternalLength) 204 | return D3DERR_INVALIDCALL; 205 | 206 | if (Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE) ) 207 | { 208 | // D3D9 in Release mode ignores this error without returning a failure code 209 | if (!(InternalUsage & D3DUSAGE_DYNAMIC) ) 210 | return D3DERR_INVALIDCALL; 211 | } 212 | 213 | #ifdef VERTEX_BUFFER_MAGIC_COOKIE 214 | ValidateMagicCookie(data, InternalLength); 215 | #endif 216 | 217 | #ifdef VERTEX_BUFFER_ENFORCE_READONLY_WHILE_UNLOCKED 218 | if (IsUnlocked() ) 219 | { 220 | BYTE* const pageStartAddr = (BYTE* const)( ( (SIZE_T)data) - ( (SIZE_T)data % 4096) ); 221 | VirtualAlloc(pageStartAddr, InternalLength, MEM_COMMIT, PAGE_READWRITE); 222 | } 223 | #endif 224 | 225 | #ifdef VERTEX_BUFFER_ENFORCE_DISCARD_ON_LOCK 226 | if ( (InternalUsage & D3DUSAGE_DYNAMIC) && (Flags & D3DLOCK_DISCARD) ) 227 | { 228 | memset(data, 0, InternalLength); 229 | } 230 | #endif 231 | 232 | if (OffsetToLock == 0 && SizeToLock == 0) 233 | *ppbData = data;//&(data.front() ); 234 | else 235 | *ppbData = /*&(data.front() )*/data + OffsetToLock; 236 | 237 | #ifdef _DEBUG 238 | if (realObject) 239 | { 240 | void* tempLockPtr = NULL; 241 | HRESULT ret = realObject->Lock(OffsetToLock, SizeToLock, &tempLockPtr, Flags); 242 | if (FAILED(ret) ) 243 | { 244 | // There was an error that we should've caught but didn't 245 | __debugbreak(); 246 | return ret; 247 | } 248 | } 249 | #endif 250 | 251 | ++lockCount; 252 | 253 | return S_OK; 254 | } 255 | 256 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::Unlock(THIS) 257 | { 258 | #ifdef _DEBUG 259 | if (realObject) 260 | { 261 | HRESULT ret = realObject->Unlock(); 262 | if (FAILED(ret) ) 263 | { 264 | __debugbreak(); // There was an error somewhere that we should've caught 265 | return ret; 266 | } 267 | } 268 | #endif 269 | 270 | #ifdef VERTEX_BUFFER_MAGIC_COOKIE 271 | ValidateMagicCookie(data, InternalLength); 272 | #endif 273 | 274 | --lockCount; 275 | 276 | #ifdef VERTEX_BUFFER_ENFORCE_READONLY_WHILE_UNLOCKED 277 | if (IsUnlocked() ) 278 | { 279 | BYTE* const pageStartAddr = (BYTE* const)( ( (SIZE_T)data) - ( (SIZE_T)data % 4096) ); 280 | VirtualAlloc(pageStartAddr, InternalLength, MEM_COMMIT, PAGE_READONLY); 281 | } 282 | #endif 283 | 284 | return S_OK; 285 | } 286 | 287 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexBuffer9Hook::GetDesc(THIS_ D3DVERTEXBUFFER_DESC *pDesc) 288 | { 289 | if (!pDesc) 290 | return D3DERR_INVALIDCALL; 291 | 292 | #ifdef _DEBUG 293 | if (realObject) 294 | { 295 | HRESULT ret = realObject->GetDesc(pDesc); 296 | if (FAILED(ret) ) 297 | { 298 | __debugbreak(); // Should've been an error but we didn't find one 299 | return ret; 300 | } 301 | 302 | if (pDesc->Size != InternalLength) 303 | { 304 | __debugbreak(); 305 | } 306 | if (pDesc->Usage != InternalUsage) 307 | { 308 | __debugbreak(); 309 | } 310 | if (pDesc->FVF != InternalFVF) 311 | { 312 | __debugbreak(); 313 | } 314 | if (pDesc->Pool != InternalPool) 315 | { 316 | __debugbreak(); 317 | } 318 | if (pDesc->Format != D3DFMT_VERTEXDATA) 319 | { 320 | __debugbreak(); 321 | } 322 | if (pDesc->Type != D3DRTYPE_VERTEXBUFFER) 323 | { 324 | __debugbreak(); 325 | } 326 | } 327 | #endif 328 | 329 | pDesc->Size = InternalLength; 330 | pDesc->Usage = InternalUsage; 331 | pDesc->FVF = InternalFVF; 332 | pDesc->Pool = InternalPool; 333 | pDesc->Format = D3DFMT_VERTEXDATA; 334 | pDesc->Type = D3DRTYPE_VERTEXBUFFER; 335 | 336 | return S_OK; 337 | } 338 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DQuery9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DQuery9Hook.h" 4 | 5 | /*** IUnknown methods ***/ 6 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DQuery9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 7 | { 8 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 9 | if (ret == NOERROR) 10 | { 11 | *ppvObj = this; 12 | AddRef(); 13 | } 14 | return ret; 15 | } 16 | 17 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DQuery9Hook::AddRef(THIS) 18 | { 19 | ULONG ret = realObject->AddRef(); 20 | ++refCount; 21 | return ret; 22 | } 23 | 24 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DQuery9Hook::Release(THIS) 25 | { 26 | ULONG ret = realObject->Release(); 27 | if (--refCount == 0) 28 | { 29 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 30 | char printBuffer[128] = {0}; 31 | #pragma warning(push) 32 | #pragma warning(disable:4996) 33 | sprintf(printBuffer, "Fully releasing hooked Query %p\n", this); 34 | #pragma warning(pop) 35 | OutputDebugStringA(printBuffer); 36 | #endif 37 | delete this; 38 | } 39 | return ret; 40 | } 41 | 42 | /*** IDirect3DQuery9 methods ***/ 43 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DQuery9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 44 | { 45 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 46 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 47 | if (FAILED(ret) ) 48 | { 49 | *ppDevice = NULL; 50 | return ret; 51 | } 52 | 53 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 54 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 55 | { 56 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 57 | } 58 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 59 | 60 | *ppDevice = parentDevice; 61 | return ret; 62 | } 63 | 64 | COM_DECLSPEC_NOTHROW D3DQUERYTYPE STDMETHODCALLTYPE IDirect3DQuery9Hook::GetType(THIS) 65 | { 66 | #ifdef _DEBUG 67 | if (realObject->GetType() != queryType) 68 | { 69 | DbgBreakPrint("Error: Unsynchronized query types"); 70 | } 71 | #endif 72 | return queryType; 73 | } 74 | 75 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DQuery9Hook::GetDataSize(THIS) 76 | { 77 | DWORD ret = 0; 78 | switch (queryType) 79 | { 80 | case D3DQUERYTYPE_EVENT: 81 | ret = sizeof(BOOL); 82 | break; 83 | case D3DQUERYTYPE_OCCLUSION: 84 | ret = sizeof(DWORD); 85 | break; 86 | default: 87 | #ifdef _DEBUG 88 | DbgBreakPrint("Error: Invalid query type specified"); 89 | #endif 90 | case D3DQUERYTYPE_VCACHE: 91 | ret = sizeof(D3DDEVINFO_VCACHE); 92 | break; 93 | case D3DQUERYTYPE_RESOURCEMANAGER: 94 | ret = sizeof(D3DDEVINFO_RESOURCEMANAGER); 95 | break; 96 | case D3DQUERYTYPE_VERTEXSTATS: 97 | ret = sizeof(D3DDEVINFO_D3DVERTEXSTATS); 98 | break; 99 | case D3DQUERYTYPE_TIMESTAMP: 100 | ret = sizeof(UINT64); 101 | break; 102 | case D3DQUERYTYPE_TIMESTAMPDISJOINT: 103 | ret = sizeof(BOOL); 104 | break; 105 | case D3DQUERYTYPE_TIMESTAMPFREQ: 106 | ret = sizeof(UINT64); 107 | break; 108 | case D3DQUERYTYPE_PIPELINETIMINGS: 109 | ret = sizeof(D3DDEVINFO_D3D9PIPELINETIMINGS); 110 | break; 111 | case D3DQUERYTYPE_INTERFACETIMINGS: 112 | ret = sizeof(D3DDEVINFO_D3D9INTERFACETIMINGS); 113 | break; 114 | case D3DQUERYTYPE_VERTEXTIMINGS: 115 | ret = sizeof(D3DDEVINFO_D3D9STAGETIMINGS); 116 | break; 117 | case D3DQUERYTYPE_PIXELTIMINGS: // Uhhhhhhhhhh, I guess this does the same thing as VERTEXTIMINGS? 118 | ret = sizeof(D3DDEVINFO_D3D9STAGETIMINGS); 119 | break; 120 | case D3DQUERYTYPE_BANDWIDTHTIMINGS: 121 | ret = sizeof(D3DDEVINFO_D3D9BANDWIDTHTIMINGS); 122 | break; 123 | case D3DQUERYTYPE_CACHEUTILIZATION: 124 | ret = sizeof(D3DDEVINFO_D3D9CACHEUTILIZATION); 125 | break; 126 | case D3DQUERYTYPE_MEMORYPRESSURE: 127 | ret = sizeof(D3DMEMORYPRESSURE); 128 | break; 129 | } 130 | 131 | #ifdef _DEBUG 132 | if (ret != realObject->GetDataSize() ) 133 | { 134 | DbgBreakPrint("Error: Mismatched query sizes"); 135 | } 136 | #endif 137 | return ret; 138 | } 139 | 140 | static inline const bool QueryTypeSupportsIssueBegin(const D3DQUERYTYPE TestType) 141 | { 142 | switch (TestType) 143 | { 144 | default: 145 | #ifdef _DEBUG 146 | { 147 | __debugbreak(); // Should never be here! 148 | } 149 | #endif 150 | case D3DQUERYTYPE_EVENT: 151 | case D3DQUERYTYPE_RESOURCEMANAGER: 152 | case D3DQUERYTYPE_TIMESTAMP: 153 | case D3DQUERYTYPE_TIMESTAMPFREQ: 154 | case D3DQUERYTYPE_VCACHE: 155 | case D3DQUERYTYPE_VERTEXSTATS: 156 | return false; 157 | case D3DQUERYTYPE_OCCLUSION: 158 | case D3DQUERYTYPE_TIMESTAMPDISJOINT: 159 | case D3DQUERYTYPE_PIPELINETIMINGS: 160 | case D3DQUERYTYPE_INTERFACETIMINGS: 161 | case D3DQUERYTYPE_VERTEXTIMINGS: 162 | case D3DQUERYTYPE_PIXELTIMINGS: 163 | case D3DQUERYTYPE_BANDWIDTHTIMINGS: 164 | case D3DQUERYTYPE_CACHEUTILIZATION: 165 | case D3DQUERYTYPE_MEMORYPRESSURE: 166 | return true; 167 | } 168 | } 169 | 170 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DQuery9Hook::Issue(THIS_ DWORD dwIssueFlags) 171 | { 172 | if (dwIssueFlags > D3DISSUE_BEGIN) 173 | { 174 | #ifdef _DEBUG 175 | DbgBreakPrint("Error: Invalid argument to IDirect3DQuery9::Issue()!"); 176 | #endif 177 | return D3DERR_INVALIDCALL; 178 | } 179 | 180 | if (dwIssueFlags & D3DISSUE_BEGIN) 181 | { 182 | if (!QueryTypeSupportsIssueBegin(queryType) ) 183 | { 184 | #ifdef _DEBUG 185 | DbgBreakPrint("Error: Can't call Issue(D3DISSUE_BEGIN) on this query type!"); 186 | #endif 187 | return D3DERR_INVALIDCALL; 188 | } 189 | } 190 | 191 | #ifdef _DEBUG 192 | if (FAILED(realObject->Issue(dwIssueFlags) ) ) 193 | { 194 | DbgBreakPrint("Error: Mismatched issue error code"); 195 | } 196 | #endif 197 | 198 | if (dwIssueFlags & D3DISSUE_BEGIN) 199 | { 200 | occlusionQueryStartPixelsPassed_Begin = parentDevice->OcclusionQuery_GetNumPixelsPassedZTest(); 201 | } 202 | if (dwIssueFlags & D3DISSUE_END) 203 | { 204 | occlusionQueryStartPixelsPassed_End = parentDevice->OcclusionQuery_GetNumPixelsPassedZTest(); 205 | } 206 | return S_OK; 207 | } 208 | 209 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DQuery9Hook::GetData(THIS_ void* pData, DWORD dwSize, DWORD dwGetDataFlags) 210 | { 211 | // If you set dwSize to zero, you can use this method to poll the resource for the query status. pData may be NULL only if dwSize is 0. 212 | // The method returns S_OK if the query data is available and S_FALSE if it is not. These are considered successful return values. 213 | if (!pData && dwSize == 0) 214 | { 215 | return S_OK; 216 | } 217 | 218 | if (!pData) 219 | { 220 | return D3DERR_INVALIDCALL; 221 | } 222 | 223 | const DWORD requiredMinimumDataSize = GetDataSize(); 224 | if (dwSize < requiredMinimumDataSize) 225 | { 226 | return D3DERR_INVALIDCALL; 227 | } 228 | 229 | if (dwGetDataFlags > D3DGETDATA_FLUSH) 230 | { 231 | return D3DERR_INVALIDCALL; 232 | } 233 | 234 | #ifdef _DEBUG 235 | if (FAILED(realObject->GetData(pData, dwSize, dwGetDataFlags) ) ) 236 | { 237 | DbgBreakPrint("Error: Mismatched GetData error code"); 238 | } 239 | #endif 240 | 241 | switch (queryType) 242 | { 243 | case D3DQUERYTYPE_EVENT: 244 | { 245 | BOOL* const bData = (BOOL* const)pData; 246 | *bData = TRUE; 247 | break; 248 | } 249 | case D3DQUERYTYPE_OCCLUSION: 250 | { 251 | DWORD* const dwData = (DWORD* const)pData; 252 | *dwData = (occlusionQueryStartPixelsPassed_End - occlusionQueryStartPixelsPassed_Begin); 253 | break; 254 | } 255 | case D3DQUERYTYPE_TIMESTAMP: 256 | { 257 | LARGE_INTEGER* const timestampData = (LARGE_INTEGER* const)pData; 258 | QueryPerformanceCounter(timestampData); 259 | break; 260 | } 261 | case D3DQUERYTYPE_TIMESTAMPDISJOINT: 262 | { 263 | BOOL* const timestampDisjointData = (BOOL* const)pData; 264 | *timestampDisjointData = FALSE; // Timestamp data is never disjoint for a purely CPU renderer because API's like QueryPerformanceCounter() will correct for changes in CPU frequency automatically. 265 | break; 266 | } 267 | case D3DQUERYTYPE_TIMESTAMPFREQ: 268 | { 269 | LARGE_INTEGER* const timestampFreq = (LARGE_INTEGER* const)pData; 270 | QueryPerformanceFrequency(timestampFreq); 271 | break; 272 | } 273 | case D3DQUERYTYPE_VCACHE: 274 | case D3DQUERYTYPE_RESOURCEMANAGER: 275 | case D3DQUERYTYPE_VERTEXSTATS: 276 | case D3DQUERYTYPE_PIPELINETIMINGS: 277 | case D3DQUERYTYPE_INTERFACETIMINGS: 278 | case D3DQUERYTYPE_VERTEXTIMINGS: 279 | case D3DQUERYTYPE_PIXELTIMINGS: 280 | case D3DQUERYTYPE_BANDWIDTHTIMINGS: 281 | case D3DQUERYTYPE_CACHEUTILIZATION: 282 | case D3DQUERYTYPE_MEMORYPRESSURE: 283 | break; // Not yet handled 284 | default: 285 | #ifdef _DEBUG 286 | { 287 | __debugbreak(); // Should never be here 288 | } 289 | #else 290 | __assume(0); 291 | #endif 292 | } 293 | 294 | return S_OK; 295 | } 296 | 297 | void IDirect3DQuery9Hook::CreateQuery(const D3DQUERYTYPE _queryType) 298 | { 299 | queryType = _queryType; 300 | 301 | switch (queryType) 302 | { 303 | default: 304 | #ifdef _DEBUG 305 | DbgBreakPrint("Error: Invalid query type specified"); 306 | #endif 307 | case D3DQUERYTYPE_VCACHE: 308 | case D3DQUERYTYPE_EVENT: 309 | case D3DQUERYTYPE_OCCLUSION: 310 | case D3DQUERYTYPE_RESOURCEMANAGER: 311 | case D3DQUERYTYPE_VERTEXSTATS: 312 | case D3DQUERYTYPE_TIMESTAMP: 313 | case D3DQUERYTYPE_TIMESTAMPDISJOINT: 314 | case D3DQUERYTYPE_TIMESTAMPFREQ: 315 | case D3DQUERYTYPE_PIPELINETIMINGS: 316 | case D3DQUERYTYPE_INTERFACETIMINGS: 317 | case D3DQUERYTYPE_VERTEXTIMINGS: 318 | case D3DQUERYTYPE_BANDWIDTHTIMINGS: 319 | case D3DQUERYTYPE_CACHEUTILIZATION: 320 | case D3DQUERYTYPE_MEMORYPRESSURE: 321 | case D3DQUERYTYPE_PIXELTIMINGS: 322 | break; 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DIndexBuffer9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DIndexBuffer9Hook.h" 4 | #include "GlobalToggles.h" 5 | 6 | void IDirect3DIndexBuffer9Hook::CreateIndexBuffer(UINT _Length, const DebuggableUsage _Usage, D3DFORMAT _Format, D3DPOOL _Pool) 7 | { 8 | InternalLength = _Length; 9 | InternalUsage = _Usage; 10 | InternalFormat = _Format; 11 | InternalPool = _Pool; 12 | 13 | const unsigned magicDWORDBytes = 14 | #ifdef INDEX_BUFFER_MAGIC_COOKIE 15 | sizeof(DWORD); 16 | #else 17 | 0; 18 | #endif 19 | 20 | #ifdef INDEX_BUFFER_ALLOC_PAGE_NOACCESS 21 | rawBytes.voidBytes = PageAllocWithNoAccessPage(InternalLength + magicDWORDBytes); 22 | #else 23 | rawBytes.voidBytes = malloc(InternalLength + magicDWORDBytes); 24 | #endif 25 | 26 | #ifdef INDEX_BUFFER_MAGIC_COOKIE 27 | *(DWORD* const)&rawBytes.u8Bytes[InternalLength] = 'INDX'; 28 | #endif 29 | } 30 | 31 | /*** IUnknown methods ***/ 32 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 33 | { 34 | if (realObject) 35 | { 36 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 37 | if (ret == NOERROR) 38 | { 39 | *ppvObj = this; 40 | AddRef(); 41 | } 42 | return ret; 43 | } 44 | // TODO: Implement this properly 45 | return S_OK; 46 | } 47 | 48 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::AddRef(THIS) 49 | { 50 | ULONG ret = realObject ? realObject->AddRef() : (const ULONG)(refCount + 1); 51 | ++refCount; 52 | return ret; 53 | } 54 | 55 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::Release(THIS) 56 | { 57 | ULONG ret = realObject ? realObject->Release() : (const ULONG)(refCount - 1); 58 | if (--refCount == 0) 59 | { 60 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 61 | char printBuffer[128] = {0}; 62 | #pragma warning(push) 63 | #pragma warning(disable:4996) 64 | sprintf(printBuffer, "Fully releasing hooked Index Buffer %p\n", this); 65 | #pragma warning(pop) 66 | OutputDebugStringA(printBuffer); 67 | #endif 68 | delete this; 69 | } 70 | return ret; 71 | } 72 | 73 | /*** IDirect3DResource9 methods ***/ 74 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 75 | { 76 | if (!ppDevice) 77 | return D3DERR_INVALIDCALL; 78 | 79 | if (realObject) 80 | { 81 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 82 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 83 | if (FAILED(ret) ) 84 | { 85 | *ppDevice = NULL; 86 | return ret; 87 | } 88 | 89 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 90 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 91 | { 92 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 93 | } 94 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 95 | 96 | *ppDevice = parentDevice; 97 | return ret; 98 | } 99 | else 100 | { 101 | *ppDevice = parentDevice; 102 | return S_OK; 103 | } 104 | } 105 | 106 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::SetPrivateData(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) 107 | { 108 | if (realObject) 109 | { 110 | HRESULT ret = realObject->SetPrivateData(refguid, pData, SizeOfData, Flags); 111 | return ret; 112 | } 113 | return S_OK; 114 | } 115 | 116 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::GetPrivateData(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) 117 | { 118 | if (realObject) 119 | { 120 | HRESULT ret = realObject->GetPrivateData(refguid, pData, pSizeOfData); 121 | return ret; 122 | } 123 | return S_OK; 124 | } 125 | 126 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::FreePrivateData(THIS_ REFGUID refguid) 127 | { 128 | if (realObject) 129 | { 130 | HRESULT ret = realObject->FreePrivateData(refguid); 131 | return ret; 132 | } 133 | return S_OK; 134 | } 135 | 136 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::SetPriority(THIS_ DWORD PriorityNew) 137 | { 138 | if (realObject) 139 | { 140 | DWORD ret = realObject->SetPriority(PriorityNew); 141 | return ret; 142 | } 143 | return S_OK; 144 | } 145 | 146 | COM_DECLSPEC_NOTHROW DWORD STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::GetPriority(THIS) 147 | { 148 | if (realObject) 149 | { 150 | DWORD ret = realObject->GetPriority(); 151 | return ret; 152 | } 153 | return 0; 154 | } 155 | 156 | COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::PreLoad(THIS) 157 | { 158 | if (realObject) 159 | realObject->PreLoad(); 160 | } 161 | 162 | COM_DECLSPEC_NOTHROW D3DRESOURCETYPE STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::GetType(THIS) 163 | { 164 | if (realObject) 165 | { 166 | D3DRESOURCETYPE ret = realObject->GetType(); 167 | #ifdef _DEBUG 168 | if (ret != D3DRTYPE_INDEXBUFFER) 169 | { 170 | __debugbreak(); // Uhhhhh, what's going on? 171 | } 172 | #endif 173 | return ret; 174 | } 175 | return D3DRTYPE_INDEXBUFFER; 176 | } 177 | 178 | #ifdef INDEX_BUFFER_MAGIC_COOKIE 179 | static inline void ValidateMagicCookie(const std::vector& shorts, const std::vector& longs, const unsigned length, const D3DFORMAT InternalFormat) 180 | { 181 | switch (InternalFormat) 182 | { 183 | case D3DFMT_INDEX16: 184 | if (*(const DWORD* const)&shorts[length / sizeof(unsigned short)] != 'INDX') 185 | { 186 | __debugbreak(); 187 | } 188 | break; 189 | default: 190 | #ifdef _DEBUG 191 | __debugbreak(); 192 | #else 193 | __assume(0); 194 | #endif 195 | case D3DFMT_INDEX32: 196 | if (longs[length / sizeof(unsigned long)] != 'INDX') 197 | { 198 | __debugbreak(); 199 | } 200 | break; 201 | } 202 | } 203 | #endif // INDEX_BUFFER_MAGIC_COOKIE 204 | 205 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::Lock(THIS_ UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags) 206 | { 207 | if (!ppbData) 208 | return D3DERR_INVALIDCALL; 209 | 210 | const DWORD validLockFlags = D3DLOCK_DISCARD | D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE; 211 | if (Flags & (~validLockFlags) ) 212 | return D3DERR_INVALIDCALL; // These are the only D3DLOCK flags valid for this function call 213 | 214 | if (SizeToLock == 0 && OffsetToLock > 0) 215 | return D3DERR_INVALIDCALL; 216 | 217 | if (OffsetToLock + SizeToLock > InternalLength) 218 | return D3DERR_INVALIDCALL; 219 | 220 | if (Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE) ) 221 | { 222 | // D3D9 in Release mode ignores this error without returning a failure code 223 | if (!(InternalUsage & D3DUSAGE_DYNAMIC) ) 224 | return D3DERR_INVALIDCALL; 225 | } 226 | 227 | #ifdef INDEX_BUFFER_MAGIC_COOKIE 228 | ValidateMagicCookie(shortBytes, longBytes, InternalLength, InternalFormat); 229 | #endif 230 | 231 | #ifdef _DEBUG 232 | if (realObject) 233 | { 234 | void* tempLockPtr = NULL; 235 | HRESULT ret = realObject->Lock(OffsetToLock, SizeToLock, &tempLockPtr, Flags); 236 | if (FAILED(ret) ) 237 | { 238 | __debugbreak(); // There was an error that we should have caught 239 | return ret; 240 | } 241 | } 242 | #endif 243 | 244 | #ifdef INDEX_BUFFER_ENFORCE_READONLY_WHILE_UNLOCKED 245 | if (IsUnlocked() ) 246 | { 247 | BYTE* const pageStartAddr = (BYTE* const)(rawBytes.pointerNumber - (rawBytes.pointerNumber % 4096) ); 248 | VirtualAlloc(pageStartAddr, InternalLength, MEM_COMMIT, PAGE_READWRITE); 249 | } 250 | #endif 251 | 252 | #ifdef INDEX_BUFFER_ENFORCE_DISCARD_ON_LOCK 253 | if ( (InternalUsage & D3DUSAGE_DYNAMIC) && (Flags & D3DLOCK_DISCARD) ) 254 | { 255 | memset(rawBytes.u8Bytes, 0, InternalLength); 256 | } 257 | #endif 258 | 259 | if (ppbData) 260 | { 261 | *ppbData = rawBytes.u8Bytes + OffsetToLock; 262 | } 263 | 264 | ++lockCount; 265 | 266 | return S_OK; 267 | } 268 | 269 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::Unlock(THIS) 270 | { 271 | #ifdef _DEBUG 272 | if (realObject) 273 | { 274 | HRESULT ret = realObject->Unlock(); 275 | if (FAILED(ret) ) 276 | { 277 | __debugbreak(); // There was an error and we should've caught it 278 | return ret; 279 | } 280 | } 281 | #endif 282 | 283 | #ifdef INDEX_BUFFER_MAGIC_COOKIE 284 | ValidateMagicCookie(shortBytes, longBytes, InternalLength, InternalFormat); 285 | #endif 286 | 287 | --lockCount; 288 | 289 | #ifdef INDEX_BUFFER_ENFORCE_READONLY_WHILE_UNLOCKED 290 | if (IsUnlocked() ) 291 | { 292 | BYTE* const pageStartAddr = (BYTE* const)(rawBytes.pointerNumber - (rawBytes.pointerNumber % 4096) ); 293 | VirtualAlloc(pageStartAddr, InternalLength, MEM_COMMIT, PAGE_READONLY); 294 | } 295 | #endif 296 | 297 | return S_OK; 298 | } 299 | 300 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DIndexBuffer9Hook::GetDesc(THIS_ D3DINDEXBUFFER_DESC *pDesc) 301 | { 302 | if (!pDesc) 303 | return D3DERR_INVALIDCALL; 304 | 305 | #ifdef _DEBUG 306 | if (realObject) 307 | { 308 | HRESULT ret = realObject->GetDesc(pDesc); 309 | if (FAILED(ret) ) 310 | { 311 | __debugbreak(); // There was an error that we should have caught 312 | return ret; 313 | } 314 | 315 | if (pDesc->Size != InternalLength) 316 | { 317 | __debugbreak(); 318 | } 319 | if (pDesc->Usage != InternalUsage) 320 | { 321 | __debugbreak(); 322 | } 323 | if (pDesc->Format != InternalFormat) 324 | { 325 | __debugbreak(); 326 | } 327 | if (pDesc->Pool != InternalPool) 328 | { 329 | __debugbreak(); 330 | } 331 | if (pDesc->Type != D3DRTYPE_INDEXBUFFER) 332 | { 333 | __debugbreak(); 334 | } 335 | } 336 | #endif 337 | 338 | pDesc->Size = InternalLength; 339 | pDesc->Usage = InternalUsage; 340 | pDesc->Format = InternalFormat; 341 | pDesc->Pool = InternalPool; 342 | pDesc->Type = D3DRTYPE_INDEXBUFFER; 343 | 344 | return S_OK; 345 | } 346 | -------------------------------------------------------------------------------- /Software_d3d9/IDirect3DVertexDeclaration9Hook.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IDirect3DVertexDeclaration9Hook.h" 4 | 5 | static inline const bool operator==(const DebuggableD3DVERTEXELEMENT9& lhs, const DebuggableD3DVERTEXELEMENT9& rhs) 6 | { 7 | return (lhs.Stream == rhs.Stream) && (lhs.Offset == rhs.Offset) && (lhs.Type == rhs.Type) && (lhs.Method == rhs.Method) && (lhs.Usage == rhs.Usage) && (lhs.UsageIndex == rhs.UsageIndex); 8 | } 9 | 10 | static inline const bool operator!=(const DebuggableD3DVERTEXELEMENT9& lhs, const DebuggableD3DVERTEXELEMENT9& rhs) 11 | { 12 | return !(lhs == rhs); 13 | } 14 | 15 | void IDirect3DVertexDeclaration9Hook::CreateVertexDeclaration(const DebuggableD3DVERTEXELEMENT9* const pVertexElements, const debuggableFVF _vertDeclAutoCreatedFromFVF) 16 | { 17 | if (!pVertexElements) 18 | { 19 | #ifdef _DEBUG 20 | __debugbreak(); 21 | #endif 22 | return; 23 | } 24 | 25 | unsigned numElements = 0; 26 | static const DebuggableD3DVERTEXELEMENT9 endDecl = D3DDECL_END(); 27 | while (pVertexElements[numElements++] != endDecl); 28 | 29 | elements.resize(numElements); 30 | memcpy(&elements.front(), pVertexElements, numElements * sizeof(DebuggableD3DVERTEXELEMENT9) ); 31 | 32 | vertDeclAutoCreatedFromFVF = _vertDeclAutoCreatedFromFVF; 33 | 34 | // Compute skipVertexProcessing: 35 | skipVertexProcessing = false; 36 | for (unsigned x = 0; x < numElements; ++x) 37 | { 38 | if (elements[x].Usage == D3DDECLUSAGE_POSITIONT && elements[x].UsageIndex == 0) 39 | { 40 | skipVertexProcessing = true; 41 | foundPositionT0 = &elements[x]; 42 | break; 43 | } 44 | } 45 | 46 | // Compute hasColor0 and hasColor1: 47 | for (unsigned x = 0; x < numElements; ++x) 48 | { 49 | const DebuggableD3DVERTEXELEMENT9& thisElement = elements[x]; 50 | if (thisElement.Usage == D3DDECLUSAGE_COLOR) 51 | { 52 | if (thisElement.UsageIndex == 0) 53 | hasColor0 = true; 54 | else if (thisElement.UsageIndex == 1) 55 | hasColor1 = true; 56 | } 57 | } 58 | 59 | USHORT currentOffset = 0; 60 | 61 | { 62 | DebuggableD3DVERTEXELEMENT9 newElement = elements[0]; 63 | newElement.Usage = D3DDECLUSAGE_POSITIONT; 64 | newElement.Type = D3DDECLTYPE_FLOAT4; 65 | newElement.Offset = 0; 66 | newElement.Stream = 0; 67 | vertShaderOutputElements.push_back(newElement); 68 | currentOffset += GetElementSizeFromType(newElement.Type); 69 | } 70 | 71 | for (unsigned x = 0; x < numElements; ++x) 72 | { 73 | const DebuggableD3DVERTEXELEMENT9& thisElement = elements[x]; 74 | if (thisElement.Usage == D3DDECLUSAGE_POSITION || thisElement.Usage == D3DDECLUSAGE_POSITIONT) 75 | continue; // Skip these 76 | else 77 | { 78 | DebuggableD3DVERTEXELEMENT9 newElement = thisElement; 79 | newElement.Stream = 0; 80 | newElement.Offset = currentOffset; 81 | vertShaderOutputElements.push_back(newElement); 82 | currentOffset += GetElementSizeFromType(newElement.Type); 83 | } 84 | } 85 | 86 | vertShaderOutputElements.push_back(D3DDECL_END() ); 87 | 88 | if (FAILED(parentDevice->GetUnderlyingDevice()->CreateVertexDeclaration( (const D3DVERTEXELEMENT9* const)&vertShaderOutputElements.front(), &vertShaderOutputDecl) ) ) 89 | { 90 | __debugbreak(); 91 | } 92 | 93 | ComputeVertexSizes(); 94 | } 95 | 96 | void IDirect3DVertexDeclaration9Hook::ComputeVertexSizes() 97 | { 98 | { 99 | UINT totalSize = 0; 100 | const unsigned numElements = elements.size(); 101 | for (unsigned x = 0; x < numElements; ++x) 102 | { 103 | const DebuggableD3DVERTEXELEMENT9& thisElement = elements[x]; 104 | if (thisElement.Type != MAXD3DDECLTYPE) 105 | { 106 | totalSize += GetElementSizeFromType(thisElement.Type); 107 | } 108 | } 109 | inVertexSize = totalSize; 110 | } 111 | 112 | { 113 | UINT totalSize = 0; 114 | const unsigned numElements = vertShaderOutputElements.size(); 115 | for (unsigned x = 0; x < numElements; ++x) 116 | { 117 | const DebuggableD3DVERTEXELEMENT9& thisElement = vertShaderOutputElements[x]; 118 | if (thisElement.Type != MAXD3DDECLTYPE) 119 | { 120 | totalSize += GetElementSizeFromType(thisElement.Type); 121 | } 122 | } 123 | outVertexSize = totalSize; 124 | } 125 | } 126 | 127 | const UINT IDirect3DVertexDeclaration9Hook::GetElementSizeFromType(const D3DDECLTYPE elementType) 128 | { 129 | switch (elementType) 130 | { 131 | case D3DDECLTYPE_FLOAT1 : 132 | return sizeof(float); 133 | case D3DDECLTYPE_FLOAT2 : 134 | return 2 * sizeof(float); 135 | case D3DDECLTYPE_FLOAT3 : 136 | return 3 * sizeof(float); 137 | case D3DDECLTYPE_FLOAT4 : 138 | return 4 * sizeof(float); 139 | case D3DDECLTYPE_D3DCOLOR : 140 | return sizeof(D3DCOLOR); 141 | case D3DDECLTYPE_UBYTE4 : 142 | case D3DDECLTYPE_UBYTE4N : 143 | return 4 * sizeof(BYTE); 144 | case D3DDECLTYPE_SHORT2 : 145 | case D3DDECLTYPE_SHORT2N : 146 | case D3DDECLTYPE_USHORT2N : 147 | return 2 * sizeof(SHORT); 148 | case D3DDECLTYPE_SHORT4 : 149 | case D3DDECLTYPE_SHORT4N : 150 | case D3DDECLTYPE_USHORT4N : 151 | return 4 * sizeof(SHORT); 152 | case D3DDECLTYPE_UDEC3 : 153 | case D3DDECLTYPE_DEC3N : 154 | return sizeof(DWORD); 155 | case D3DDECLTYPE_FLOAT16_2 : 156 | return 2 * sizeof(D3DXFLOAT16); 157 | case D3DDECLTYPE_FLOAT16_4 : 158 | return 4 * sizeof(D3DXFLOAT16); 159 | default: 160 | case D3DDECLTYPE_UNUSED : 161 | #ifdef _DEBUG 162 | __debugbreak(); 163 | #endif 164 | return 0; 165 | } 166 | } 167 | 168 | /*** IUnknown methods ***/ 169 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexDeclaration9Hook::QueryInterface(THIS_ REFIID riid, void** ppvObj) 170 | { 171 | HRESULT ret = realObject->QueryInterface(riid, ppvObj); 172 | if (ret == NOERROR) 173 | { 174 | *ppvObj = this; 175 | AddRef(); 176 | } 177 | return ret; 178 | } 179 | 180 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVertexDeclaration9Hook::AddRef(THIS) 181 | { 182 | ULONG ret = realObject->AddRef(); 183 | ++refCount; 184 | return ret; 185 | } 186 | 187 | COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE IDirect3DVertexDeclaration9Hook::Release(THIS) 188 | { 189 | ULONG ret = realObject->Release(); 190 | if (--refCount == 0) 191 | { 192 | #ifdef DEBUGPRINT_D3DHOOKOBJECT_FULLRELEASES 193 | char printBuffer[128] = {0}; 194 | #pragma warning(push) 195 | #pragma warning(disable:4996) 196 | sprintf(printBuffer, "Fully releasing hooked Vertex Declaration %p\n", this); 197 | #pragma warning(pop) 198 | OutputDebugStringA(printBuffer); 199 | #endif 200 | delete this; 201 | } 202 | return ret; 203 | } 204 | 205 | /*** IDirect3DVertexDeclaration9 methods ***/ 206 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexDeclaration9Hook::GetDevice(THIS_ IDirect3DDevice9** ppDevice) 207 | { 208 | LPDIRECT3DDEVICE9 realD3D9dev = NULL; 209 | HRESULT ret = realObject->GetDevice(&realD3D9dev); 210 | if (FAILED(ret) ) 211 | { 212 | *ppDevice = NULL; 213 | return ret; 214 | } 215 | 216 | // Check that the parentHook's underlying IDirect3DDevice9* matches the realD3D9dev pointer 217 | if (parentDevice->GetUnderlyingDevice() != realD3D9dev) 218 | { 219 | DbgBreakPrint("Error: Unknown d3d9 device hook detected!"); 220 | } 221 | parentDevice->AddRef(); // Super important to increment the ref-count here, otherwise our parent object will get destroyed when Release() is called on it! 222 | 223 | *ppDevice = parentDevice; 224 | return ret; 225 | } 226 | 227 | COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE IDirect3DVertexDeclaration9Hook::GetDeclaration(THIS_ D3DVERTEXELEMENT9* pElement,UINT* pNumElements) 228 | { 229 | HRESULT ret = realObject->GetDeclaration(pElement, pNumElements); 230 | return ret; 231 | } 232 | 233 | UINT IDirect3DVertexDeclaration9Hook::GetStream0Float4PositionTOffset(void) const 234 | { 235 | const unsigned numOutputElements = vertShaderOutputElements.size(); 236 | for (unsigned x = 0; x < numOutputElements; ++x) 237 | { 238 | const DebuggableD3DVERTEXELEMENT9& thisElement = vertShaderOutputElements[x]; 239 | if (thisElement.Usage == D3DDECLUSAGE_POSITIONT && thisElement.Type == D3DDECLTYPE_FLOAT4 && thisElement.Stream == 0) 240 | return thisElement.Offset; 241 | } 242 | 243 | // Should never be here! 244 | __debugbreak(); 245 | return 0; 246 | } 247 | 248 | // Returns true if vertex offset is found, otherwise returns false and then vertOffset and streamIndex are undefined 249 | const bool IDirect3DVertexDeclaration9Hook::GetVertexOffset(unsigned& vertOffset, unsigned& streamIndex, const D3DDECLUSAGE usage, const unsigned usageIndex) const 250 | { 251 | const DebuggableD3DVERTEXELEMENT9* const foundElement = GetVertexElement(usage, usageIndex); 252 | if (!foundElement) 253 | { 254 | vertOffset = 0; 255 | streamIndex = 0; 256 | return false; 257 | } 258 | else 259 | { 260 | vertOffset = foundElement->Offset; 261 | streamIndex = foundElement->Stream; 262 | return true; 263 | } 264 | } 265 | 266 | // Returns NULL if no such element is found 267 | const DebuggableD3DVERTEXELEMENT9* const IDirect3DVertexDeclaration9Hook::GetVertexElement(const D3DDECLUSAGE usage, const unsigned usageIndex) const 268 | { 269 | const unsigned numElements = elements.size(); 270 | for (unsigned x = 0; x < numElements; ++x) 271 | { 272 | const DebuggableD3DVERTEXELEMENT9& thisElement = elements[x]; 273 | if (thisElement.Usage == usage && thisElement.UsageIndex == usageIndex) 274 | { 275 | return &thisElement; 276 | } 277 | } 278 | 279 | return NULL; 280 | } 281 | 282 | // Returns NULL if no such element is found 283 | const DebuggableD3DVERTEXELEMENT9* const IDirect3DVertexDeclaration9Hook::GetVertexElementOutput(const D3DDECLUSAGE usage, const unsigned usageIndex) const 284 | { 285 | const unsigned numElements = vertShaderOutputElements.size(); 286 | for (unsigned x = 0; x < numElements; ++x) 287 | { 288 | const DebuggableD3DVERTEXELEMENT9& thisElement = vertShaderOutputElements[x]; 289 | if (thisElement.Usage == usage && thisElement.UsageIndex == usageIndex) 290 | { 291 | return &thisElement; 292 | } 293 | } 294 | 295 | return NULL; 296 | } 297 | --------------------------------------------------------------------------------