0
\$\begingroup\$

I have hooked Present method of the IDirect3DDevice9 interface, and I want to be able to start video capturing.

Taking a screenshoot like this work

if (GetAsyncKeyState('O') & 1) {
pDevice->CreateOffscreenPlainSurface((rect.right - rect.left),(rect.bottom - rect.top),D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&back_buffer, NULL);
pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer);
D3DXSaveSurfaceToFile(L"C:\\screenshot.bmp", D3DXIFF_BMP, back_buffer, 0, NULL );

IDirect3DSurface9_Release(back_buffer);

}

I seem to fail to lock the surface with 0x8876086C(D3DERR_INVALIDCALL)

HRESULT APIENTRY hook_Present(IDirect3DDevice9* pDevice, const RECT* pSourceRect,const RECT* pDestRect, HWND hDestWindowOverride,const RGNDATA* pDirtyRegion) {
IDirect3DSurface9*back_buffer;
D3DDEVICE_CREATION_PARAMETERS cparams;
RECT rect;
pDevice->GetCreationParameters(&cparams);
GetClientRect(cparams.hFocusWindow, &rect);
if (GetAsyncKeyState('R') & 1) {
    if(dx9Capturing == 0) {
        //Create the AVI file
        // etc code
        dx9Capturing = 1
    }
    else if(dx9Capturing == 1) dx9Capturing = 2; // stop capturing
}

if(dx9Capturing == 1) {
    // Capture the current frame
    pDevice->CreateOffscreenPlainSurface((rect.right - rect.left),(rect.bottom - rect.top),D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&back_buffer, NULL);
    pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer);
    D3DLOCKED_RECT  lockedRect;
    if(FAILED(back_buffer->LockRect(&lockedRect,&rect,D3DLOCK_READONLY))) {
        MessageBoxA(NULL, "Failed locking the back buffer!", "Error", MB_OK);
        return orig_Present(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
    }
    for(int i=0;i<rect.bottom;i++)
        {
            memcpy((BYTE*)pBits+(rect.bottom-i-1)*rect.right*BITSPERPIXEL/8,(BYTE*)lockedRect.pBits+i*lockedRect.Pitch,rect.right*BITSPERPIXEL/8);
        }
    back_buffer->UnlockRect();
    pAviFile->AddNewFrame(rect.right,rect.bottom,pBits);
}

return orig_Present(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);

}

Hooking Reset and I still have the same problem

HRESULT APIENTRY hook_Reset (IDirect3DDevice9* pDevice,D3DPRESENT_PARAMETERS* pPresentationParameters) {
HRESULT hr;
if(pFont) {
    pFont->Release();
}

D3DPRESENT_PARAMETERS d3dpp; 
D3DDISPLAYMODE d3ddm;
direct->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm );
ZeroMemory( &d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = true;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = d3ddm.Format;
    d3dpp.Flags =  D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
hr =  orig_Reset(pDevice, &d3dpp);
return hr;

}

\$\endgroup\$
  • 1
    \$\begingroup\$ Please visit this page to have your accounts merged. This will allow you to edit the post and post comments under the question and the answers. \$\endgroup\$ – Vaillancourt Dec 26 '17 at 2:27
0
\$\begingroup\$

The device needs to be created with D3DPRESENTFLAG_LOCKABLE_BACKBUFFER:

Set this flag if the application requires the ability to lock the back buffer directly. Note that back buffers are not lockable unless the application specifies D3DPRESENTFLAG_LOCKABLE_BACKBUFFER when calling CreateDevice or Reset. Lockable back buffers incur a performance cost on some graphics hardware configurations.

What you should note from this is that you need to add D3DPRESENTFLAG_LOCKABLE_BACKBUFFER to your Present Parameters in two places:

  1. The initial CreateDevice call, and,
  2. Any Reset calls that may happen.

It is not sufficient to just add it to CreateDevice because the original program may make a Reset call which may then overwrite your modified Present Parameters.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.