6

I was experimenting with ways to capture screen on windows and consequently deciding on the fastest way to do so. The most common is obviously the GDI way. And it is decent in performance as well. Depending on the system load and static/non-static screen content, the screen capture rate ranged from 27-47 fps (Windows 7, Intel i5@2.6 GHz, 8 GB RAM).

Now, with DirectX front buffer approach(using the GetFrontBufferData() API), the performance was comparable but slightly on the slower side(I couldn't reach as high as 48 fps).

I went through this post: Fastest method of screen capturing and the tried out the way suggested in the accepted answer using getRenderTarget() and getRenderTargetData(), but as suggested in the comments, all I get is a black image. Here is my complete code including initial configurations for the device:

    IDirect3DSurface9* pRenderTarget=NULL;
    IDirect3DSurface9* pDestTarget=NULL;
    // sanity checks.
    if (g_pd3dDevice == NULL){
      return;
    }
    HRESULT hr;
    // get the render target surface.
    hr = g_pd3dDevice->GetRenderTarget(0, &pRenderTarget);
    // get the current adapter display mode.
    //hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode);

    // create a destination surface.
    hr = g_pd3dDevice->CreateOffscreenPlainSurface(1600, 900, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pDestTarget, NULL);
   //copy the render target to the destination surface.
   hr = g_pd3dDevice->GetRenderTargetData(pRenderTarget, pDestTarget);

   D3DLOCKED_RECT lockedRect;
   hr =pDestTarget->LockRect(&lockedRect,NULL, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY);

    for( int i=0 ; i < 900 ; i++)
    {
        for(int j=0; j < 1600; j++){
            memcpy( (BYTE*) data + i * 1600 * 3 + j * 3, (BYTE*) lockedRect.pBits + i* lockedRect.Pitch + j * 4,  3);
        }
    }
    pDestTarget->UnlockRect();
   // clean up.
   pRenderTarget->Release();
   pDestTarget->Release();

And for the device Initialization part:

g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION); 
D3DPRESENT_PARAMETERS PresentParams; 
memset(&PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS)); 
PresentParams.Windowed = TRUE; 
PresentParams.SwapEffect =D3DSWAPEFFECT_DISCARD;
g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL ,GetDesktopWindow(),D3DCREATE_SOFTWARE_VERTEXPROCESSING, &PresentParams,&g_pd3dDevice);

Please point out the mistake in the above code. Any suggestions are welcome. I also tried the GetBackBuffer() API but I couldn't get hold of the image data.

EDIT:

My use case was to capture desktop screen which seems to be done only using GetFrontBufferData() via directX. GetBackBuffer()/GetRenderTargetData() is not the correct API to call for this case. Reference: The desktop capture with DirectX does not work and How to get the screenshot of the desktop from back buffer with DirectX.

However, any suggestions to a faster method for capturing desktop screen or optimizing the GDI way are welcome.

Community
  • 1
  • 1
Hrishikesh_Pardeshi
  • 995
  • 4
  • 19
  • 45
  • 1
    I feel like `GetRenderTarget` will return the back buffer for the device. You might want to look at the `GetFrontBufferData` function. – Drew McGowen Jul 23 '13 at 14:06
  • I have used GetFrontBufferData() as mentioned in the question, it works fine. But, there is no gain in performance over the GDI way. I was looking for a faster approach, if any. – Hrishikesh_Pardeshi Jul 23 '13 at 14:10
  • I am also writing a screencapture application. [Here](http://stackoverflow.com/q/31286503/4794952) is the link to my issue. I get a black screen when I capture any game whereas for any other application, it returns the right captured screen. Is there any way to make it work with fullscreen games? – newbie2015 Jul 08 '15 at 07:54

1 Answers1

2

Did you render anything before taking the screenshot?

  • GetFrontBufferData - this function get the data of the screen
  • GetRenderTargetData - this function get the data from render target

So if you didn't render anything, you definitely will got a blank image.

Factor Mystic
  • 26,279
  • 16
  • 79
  • 95
zdd
  • 8,258
  • 8
  • 46
  • 75
  • I am probably out of context here. My use case is to get the data of the desktop screen. So, are you suggesting GetRenderTargetData() is not the correct API to call. Can you please elaborate on the rendering part? – Hrishikesh_Pardeshi Jul 24 '13 at 06:06
  • Checked up your answer here http://stackoverflow.com/questions/12859894/the-desktop-capture-with-directx-does-not-work/12863143#12863143 .. so, GetFrontBufferData() is the only API to be used to capture desktop screen through DirectX. – Hrishikesh_Pardeshi Jul 24 '13 at 06:19
  • 1
    Yes, GetRenderTargetData() was used to get data from your application's render target, not the desktop. – zdd Jul 24 '13 at 06:35