Skip to content

Commit

Permalink
GraphicsCapture: Add D3D9 offset workaround
Browse files Browse the repository at this point in the history
This adds a technique so we don't have to update the program every time
microsoft changes the D3D9 dlls (finally).
  • Loading branch information
jp9000 committed Aug 30, 2016
1 parent abdfe23 commit 7aebf07
Showing 1 changed file with 92 additions and 1 deletion.
93 changes: 92 additions & 1 deletion GraphicsCapture/GraphicsCaptureHook/D3D9Capture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down Expand Up @@ -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))
Expand All @@ -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)))
Expand All @@ -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)))
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 7aebf07

Please sign in to comment.