GraphicsCapture: Add D3D9 offset workaround
This adds a technique so we don't have to update the program every time microsoft changes the D3D9 dlls (finally).master
parent
abdfe23252
commit
7aebf07142
|
@ -234,6 +234,76 @@ LPBYTE GetD3D9PatchAddress()
|
|||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// new workaround for GPU copy stuff
|
||||
|
||||
static bool offsetWorkaround = false;
|
||||
static UINT32 offset_D3D9 = 0;
|
||||
static UINT32 offset_isD3D9Ex = 0;
|
||||
|
||||
#ifdef _WIN64
|
||||
#define CMP_SIZE 21
|
||||
static const BYTE mask[CMP_SIZE] = {0xF8, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00};
|
||||
static const BYTE mask_cmp[CMP_SIZE] = {0x48, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x40, 0xB8, 0x00, 0x00, 0x00, 0x00};
|
||||
#else
|
||||
|
||||
#define CMP_SIZE 19
|
||||
static const BYTE mask[CMP_SIZE] = {0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00};
|
||||
static const BYTE mask_cmp[CMP_SIZE] = {0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00};
|
||||
#endif
|
||||
|
||||
#define MAX_FUNC_SCAN_BYTES 200
|
||||
|
||||
static inline bool PatternMatches(BYTE *byte)
|
||||
{
|
||||
for (size_t i = 0; i < CMP_SIZE; i++) {
|
||||
if ((byte[i] & mask[i]) != mask_cmp[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void FindD3D9ExOffsets(IDirect3D9Ex *d3d9ex, IDirect3DDevice9Ex *dev)
|
||||
{
|
||||
BYTE **vt = *(BYTE***)dev;
|
||||
BYTE *crr = vt[125];
|
||||
|
||||
for (size_t i = 0; i < MAX_FUNC_SCAN_BYTES; i++) {
|
||||
if (PatternMatches(&crr[i])) {
|
||||
#define GetOffset(x) *(UINT32*)(&crr[i + x])
|
||||
#ifdef _WIN64
|
||||
UINT32 off1 = GetOffset(3);
|
||||
UINT32 off2 = GetOffset(9);
|
||||
#else
|
||||
UINT32 off1 = GetOffset(2);
|
||||
UINT32 off2 = GetOffset(8);
|
||||
#endif
|
||||
|
||||
if (off1 > 0xFFFF || off2 > 0xFFFF)
|
||||
break;
|
||||
|
||||
__try {
|
||||
BYTE *ptr = (BYTE*)(dev);
|
||||
BYTE *d3d9_ptr = *(BYTE**)(ptr + off1);
|
||||
|
||||
BOOL &is_d3d9ex = *(BOOL*)(d3d9_ptr + off2);
|
||||
if (is_d3d9ex != TRUE)
|
||||
continue;
|
||||
|
||||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset_D3D9 = off1;
|
||||
offset_isD3D9Ex = off2;
|
||||
offsetWorkaround = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
void ClearD3D9Data()
|
||||
{
|
||||
|
@ -452,9 +522,13 @@ void DoD3D9GPUHook(IDirect3DDevice9 *device)
|
|||
LPBYTE patchAddress = (patchType != 0) ? GetD3D9PatchAddress() : NULL;
|
||||
DWORD dwOldProtect;
|
||||
size_t patch_size;
|
||||
BOOL *pIsD3D9Ex = nullptr;
|
||||
BOOL wasD3D9Ex = false;
|
||||
|
||||
if(patchAddress)
|
||||
{
|
||||
RUNEVERYRESET logOutput << CurrentTimeString() << "DoD3D9GPUHook: offset workaround appears unavailable" << endl;
|
||||
|
||||
patch_size = patch[patchType-1].patchSize;
|
||||
savedData = (BYTE*)malloc(patch_size);
|
||||
if(VirtualProtect(patchAddress, patch_size, PAGE_EXECUTE_READWRITE, &dwOldProtect))
|
||||
|
@ -468,6 +542,17 @@ void DoD3D9GPUHook(IDirect3DDevice9 *device)
|
|||
goto finishGPUHook;
|
||||
}
|
||||
}
|
||||
else if (offsetWorkaround)
|
||||
{
|
||||
RUNEVERYRESET logOutput << CurrentTimeString() << "DoD3D9GPUHook: using offset workaround" << endl;
|
||||
|
||||
BYTE *devicePtr = (BYTE*)device;
|
||||
BYTE *d3d9Ptr = *(BYTE**)(devicePtr + offset_D3D9);
|
||||
pIsD3D9Ex = (BOOL*)(d3d9Ptr + offset_isD3D9Ex);
|
||||
|
||||
wasD3D9Ex = *pIsD3D9Ex;
|
||||
*pIsD3D9Ex = true;
|
||||
}
|
||||
|
||||
IDirect3DTexture9 *d3d9Tex;
|
||||
if(FAILED(hErr = device->CreateTexture(d3d9CaptureInfo.cx, d3d9CaptureInfo.cy, 1, D3DUSAGE_RENDERTARGET, (D3DFORMAT)d3d9Format, D3DPOOL_DEFAULT, &d3d9Tex, &sharedHandle)))
|
||||
|
@ -481,6 +566,10 @@ void DoD3D9GPUHook(IDirect3DDevice9 *device)
|
|||
memcpy(patchAddress, savedData, patch_size);
|
||||
VirtualProtect(patchAddress, patch_size, dwOldProtect, &dwOldProtect);
|
||||
}
|
||||
else if (offsetWorkaround)
|
||||
{
|
||||
*pIsD3D9Ex = wasD3D9Ex;
|
||||
}
|
||||
|
||||
if(FAILED(hErr = d3d9Tex->GetSurfaceLevel(0, ©D3D9TextureGame)))
|
||||
{
|
||||
|
@ -730,7 +819,7 @@ void DoD3D9DrawStuff(IDirect3DDevice9 *device)
|
|||
if(bD3D9Ex)
|
||||
bUseSharedTextures = true;
|
||||
else
|
||||
bUseSharedTextures = (patchType = GetD3D9PatchType()) != 0;
|
||||
bUseSharedTextures = offsetWorkaround || (patchType = GetD3D9PatchType()) != 0;
|
||||
|
||||
//fix for when backbuffers aren't actually being properly used, instead get the
|
||||
//size/format of the actual current render target at time of present
|
||||
|
@ -1296,6 +1385,8 @@ bool InitD3D9Capture()
|
|||
/*d3d9ResetEx.Hook((FARPROC)*(vtable+(528/4)), (FARPROC)D3D9ResetEx);
|
||||
d3d9Reset.Hook((FARPROC)*(vtable+(64/4)), (FARPROC)D3D9Reset);*/
|
||||
|
||||
FindD3D9ExOffsets(d3d9ex, deviceEx);
|
||||
|
||||
deviceEx->Release();
|
||||
|
||||
d3d9EndScene.Rehook();
|
||||
|
|
Loading…
Reference in New Issue