използвайки 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