使用GetFrontBufferData(),&将屏幕截图放在单独的设备后备箱中

时间:2014-09-25 08:54:31

标签: buffer desktop capture direct3d

好吧,对于那些使用它的人来说 - 这应该是一个超级简单的问题。

我只是在网上搜索使用DirectX / Direct3D获取更快截图的方法,每个人都在谈论GetFrontBufferData()以及它有多棒。

我已经捣了一会儿,但我开始认为他们错误地使用了“截图”一词......我的电话成功了,但我从来没有得到过“截图”。

所以问题是,您是否可以实际使用GetFrontBufferData()来制作整个桌面的真实屏幕截图,或者它只是一种在前端缓冲区内读取像素的方法您的d3d设备的绘图区域?

(一旦成功,我预计会看到我窗户内的绘图区域做电视 - 电视 - 电视 - 电视 - 电视 - 有点效果。我什么也没有,只有黑色。)

编辑:

所以,我能够获得截图,但似乎无法将我的图像放入我的应用程序窗口的缓冲区。

起初,我认为这是因为它们是独立的设备,但我尝试在正确的设备上创建第二个表面,然后手动复制内容。 (虽然我可能会错误地复制它((现在不重要))对于正确的设备,对stretchrect的调用仍然失败。

知道为什么它不允许我将这个表面应用到我的后台?

D3DDISPLAYMODE          d3dDisplayMode;
D3DPRESENT_PARAMETERS   d3dPresentationParameters;

if( (d3d=Direct3DCreate9(D3D_SDK_VERSION))==NULL )
    exit(1);
D3DCAPS9 d3dcps;
d3d->GetDeviceCaps(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,&d3dcps);
DWORD targets = d3dcps.NumSimultaneousRTs;
// TODO: ^ make a way for user to select one from this and put it into i
DWORD i=D3DADAPTER_DEFAULT;

if( d3d->GetAdapterDisplayMode(i,&d3dDisplayMode)==D3DERR_INVALIDCALL )
    exit(1);

ZeroMemory(&d3dPresentationParameters,sizeof(D3DPRESENT_PARAMETERS));//Fills a block of memory with zeros.
d3dPresentationParameters.Windowed = TRUE;
d3dPresentationParameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dPresentationParameters.BackBufferFormat = d3dDisplayMode.Format;//d3dDisplayMode.Format;//D3DFMT_A8R8G8B8;
d3dPresentationParameters.BackBufferCount = 1;
d3dPresentationParameters.BackBufferHeight = d3dDisplayMode.Height;
d3dPresentationParameters.BackBufferWidth = d3dDisplayMode.Width;
d3dPresentationParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dPresentationParameters.MultiSampleQuality = 0;
d3dPresentationParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dPresentationParameters.hDeviceWindow = hwDesktop;
d3dPresentationParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
d3dPresentationParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

if( d3d->CreateDevice(i,D3DDEVTYPE_HAL,hwDesktop,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dPresentationParameters,&d3dcdev) != D3D_OK )
    exit(1);

if( d3dcdev->CreateOffscreenPlainSurface(d3dDisplayMode.Width,d3dDisplayMode.Height,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&sfScrn, NULL) != D3D_OK )
    exit(1);

if( d3dcdev->GetFrontBufferData(0,sfScrn) != D3D_OK)
    exit(1);   

// we now have a screenshot in sfScrn. 
// let's render it to a separate device in our app window!
d3dPresentationParameters.hDeviceWindow = hwDrawArea;
if( d3d->CreateDevice(i,D3DDEVTYPE_HAL,hwDrawArea,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dPresentationParameters,&d3drdev) != D3D_OK )
    exit(1);
d3drdev->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&sfBackBuffer);
if( d3drdev->CreateOffscreenPlainSurface(d3dDisplayMode.Width,d3dDisplayMode.Height,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&sfTransfer, NULL) != D3D_OK )
    exit(1);

D3DLOCKED_RECT lockedRectScrn, lockedRectTransfer;
ZeroMemory(&lockedRectScrn, sizeof(D3DLOCKED_RECT));
ZeroMemory(&lockedRectTransfer, sizeof(D3DLOCKED_RECT));
if(sfScrn->LockRect(&lockedRectScrn,NULL,D3DLOCK_READONLY) != D3D_OK 
    || sfTransfer->LockRect(&lockedRectTransfer,NULL,0) != D3D_OK )
    exit(1);
memcpy((BYTE*)lockedRectTransfer.pBits,(BYTE*)lockedRectScrn.pBits,lockedRectScrn.Pitch*d3dDisplayMode.Height);
sfScrn->UnlockRect();
sfTransfer->UnlockRect();

while(true)
{
    if(d3drdev != NULL)
    {
        d3drdev->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(75,0,0),1.0f,0);
        if(D3D_OK!=d3drdev->StretchRect(sfTransfer,NULL,sfBackBuffer,NULL,D3DTEXF_NONE))
        {
            MessageBox(NULL,"failed to use stretchrect","",0);
            exit(1);
        }
        if(d3drdev->BeginScene())
        {
            d3drdev->EndScene();
        }
        d3drdev->Present(NULL,NULL,NULL,NULL);
    }
}

EDIT2:

哦!显然你不能在D3DPOOL_SYSTEMMEM中的表面上使用StretchRect(),但是你必须在D3DPOOL_SYSTEMMEM上使用GetFronBufferData()。

1 个答案:

答案 0 :(得分:2)

是。您可以使用GetFrontBufferData捕获Windows桌面。作为证据我可以提供这个recent question海报有效的地方,除非桌面使用的是16位颜色。它可能会让您对如何正确使用它有所了解。

但不,这不是GetFrontBufferData的“真正目的”。它的真正目的是允许Direct3D游戏捕捉游戏本身的截图,无论游戏是窗口还是全屏,最重要的是,游戏是否使用多重采样。

GetFrontBufferData并非旨在成为获取Windows桌面屏幕截图的更好方法。它可能比其他方法更快,但这不是它存在的原因。