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
jp9000 2016-08-29 18:57:11 -07:00
parent abdfe23252
commit 7aebf07142
1 changed files with 92 additions and 1 deletions

View File

@ -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, &copyD3D9TextureGame)))
{
@ -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();