Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the screenshot of the desktop from back buffer with DirectX

I asked how to take the screen shot in DirectX and "Use GetFrontBufferData()" was answered. However, "This function is very slow, by design, and should not be used in any performance-critical path" was described at MSDN.

When I asked other persons the measure, "Transfer the data of a back buffer to the system memory" was answered. But, I was not able to find a concrete method.

This is an example of failure. Please let me know the right code.

#include <stdio.h>
#include <Windows.h>
#include <d3d9.h>
#include <d3dx9tex.h>

void main()
{
    CoInitialize(NULL);

    HWND hwnd = GetDesktopWindow();

    LPDIRECT3D9 d3d9;
    D3DDISPLAYMODE ddm;

    d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
    d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm);

    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferWidth = ddm.Width;
    d3dpp.BackBufferHeight = ddm.Height;
    d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    d3dpp.MultiSampleQuality = 0;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    d3dpp.hDeviceWindow = hwnd;
    d3dpp.Flags = D3DPRESENTFLAG_VIDEO;
    d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

    LPDIRECT3DDEVICE9 dev;
    d3d9->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dpp, &dev);

    /* Deprecation
    IDirect3DSurface9* surface = NULL;
    dev->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, NULL);
    dev->GetFrontBufferData(0, surface);
    D3DXSaveSurfaceToFile(L"D:\\test.bmp", D3DXIFF_BMP, surface, NULL, NULL);
    */

    // Transfer the data of a back buffer to the system memory
    IDirect3DSurface9* surface = NULL;
    dev->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL);
    LPDIRECT3DSURFACE9 back = NULL;
    dev->SetRenderTarget(0, surface);
    dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back);
    dev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,127), 1.0, 0 );
    dev->BeginScene();
    dev->StretchRect(surface, NULL, back, NULL, D3DTEXF_NONE);
    dev->EndScene();
    dev->Present(0,0,0,0);
    D3DXSaveSurfaceToFile(L"D:\\test.bmp", D3DXIFF_BMP, back, NULL, NULL);


    if(back) back->Release();

    dev->Release();
    d3d9->Release();

    CoUninitialize();
}
like image 385
Tank2005 Avatar asked Oct 23 '22 06:10

Tank2005


1 Answers

You can not get the data from back-buffer, the function GetBackBuffer only retrieve a pointer of the back buffer, not the data in it.

  • Front Buffer. A rectangle of memory that is translated by the graphics adapter and displayed on the monitor. In Direct3D an application never writes directly to the front buffer.
  • Back Buffer. A rectangle of memory that an application can directly write to. The back buffer is never directly displayed on the monitor.

that means what you saw on the desktop exists in front buffer.

like image 115
zdd Avatar answered Oct 27 '22 10:10

zdd