используя GetFrontBufferData(), и поместите снимок экрана в отдельный резервный буфер устройства

Итак, для тех, кто много пользовался - это должен быть СУПЕР простой вопрос.

Я просто искал в Интернете способ использовать 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);
    }
}

Редактировать2:

Ой! Таким образом, очевидно, вы не можете использовать StretchRect() на поверхностях, которые находятся в D3DPOOL_SYSTEMMEM, но вы должны использовать GetFronBufferData() на D3DPOOL_SYSTEMMEM.


person user980058    schedule 25.09.2014    source источник


Ответы (1)


да. вы можете захватить рабочий стол Windows, используя GetFrontBufferData. В качестве доказательства могу предложить этот недавний вопрос где плакат работал, за исключением случаев, когда на рабочем столе использовался 16-битный цвет. Это может дать вам некоторое представление о том, как правильно его использовать.

Но нет, это не "истинная цель" GetFrontBufferData. Настоящая цель состоит в том, чтобы разрешить Direct3D-играм захватывать скриншоты самой игры, независимо от того, является ли игра оконной или полноэкранной, и, что наиболее важно, использует ли игра мультисэмплинг или нет.

GetFrontBufferData не предназначен для создания скриншотов рабочего стола Windows. Может случиться так, что он будет быстрее, чем другие методы, но он существует не поэтому.

person Ross Ridge    schedule 26.09.2014
comment
Эй, спасибо! Я понял, что моя основная проблема заключается в том, что я не могу поместить скриншот в другой резервный буфер. Заставляет меня задаться вопросом, сколько успешных попыток сделать снимок экрана у меня было раньше, даже не осознавая этого. - person user980058; 27.09.2014