Захватите и сделайте снимок экрана с помощью DirectX

Я пытаюсь заставить DirectX (DX9) сделать снимок экрана рабочего стола и сразу же вывести его обратно (в меньших размерах) в мою форму.

У меня DirectX работает так, что устройство создается вместе с несколькими поверхностями, и я могу отображать их на экране. Я использую одну поверхность F3F3Surf9_SS для получения снимка экрана рабочего стола.

Вот мое объявление и инициализация переменных

F3D3Surf9_SS : IDirect3DSurface9; //Surface SS
F3D3Surf9_A : IDirect3DSurface9;  //Surface A
F3D3Surf9_B : IDirect3DSurface9;  //Surface B

...

FDirect3D9.CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,Form1.Handle,
                        D3DCREATE_SOFTWARE_VERTEXPROCESSING,@D3DPresentParams,
                        FDirect3DDevice9);

FDirect3DDevice9.CreateOffscreenPlainSurface(1360,768,D3DFMT_X8R8G8B8,
                                             D3DPOOL_DEFAULT,F3D3Surf9_A,nil);

D3DXLoadSurfaceFromFile(F3D3Surf9_A,nil,nil,'D:\Images\Pillar.bmp',nil,
                        D3DX_DEFAULT,0,nil);

FDirect3DDevice9.CreateOffscreenPlainSurface(1360,768,D3DFMT_X8R8G8B8,
                                             D3DPOOL_DEFAULT,F3D3Surf9_B,nil);

D3DXLoadSurfaceFromFile(F3D3Surf9_B,nil,nil,'D:\Images\Niagra.bmp',nil,
                        D3DX_DEFAULT,0,nil);

FDirect3DDevice9.CreateOffscreenPlainSurface(Screen.Width,Screen.Height,D3DFMT_A8R8G8B8,
                                         D3DPOOL_SCRATCH,F3D3Surf9_SS,nil);

Вот код, который я использую для захвата и рендеринга снимка экрана.

FDIrect3DDevice9.BeginScene;

FDirect3DDevice9.Clear(0,0,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,255),0,0);
FDirect3DDevice9.GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO, BackBuffer);

FDirect3DDevice9.GetFrontBufferData(0,F3D3Surf9_SS);  //Get the screen shot

FDirect3DDevice9.StretchRect(F3D3Surf9_SS,nil,BackBuffer,nil,D3DTEXF_NONE); //Draw it

FDIrect3DDevice9.EndScene;
FDirect3DDevice9.Present(nil,nil,0,nil);

Однако это не работает.

Изображение не прорисовывается на экране. Если я рисую поверхность A или B на экране, это работает, но не работает для Surface SS. Однако я знаю, что в Surface SS есть снимок экрана, поскольку, если я вызову D3DXSaveSurfaceToFile, результирующее растровое изображение, которое я помещу на жесткий диск, будет действительным снимком экрана.

Любые мысли о правильном способе сделать это?


person Tim    schedule 01.04.2011    source источник


Ответы (1)


Причина, по которой это не сработает, заключается в том, что F3D3Surf9_SS был объявлен в системной памяти с помощью D3DPOOL_SCRATCH и не может быть отрисован непосредственно в задний буфер, как я пытался.

Итак, мое решение состояло в том, чтобы использовать поверхность F3D3Surf9_A и использовать UpdateSurface для копирования снимка экрана из системной памяти в поверхность A в видеопамяти.

Единственное другое изменение, которое мне пришлось внести, чтобы заставить это работать, — это создать поверхность A в том же формате, что и поверхность скриншота: D3DFMT_A8R8G8B8. Также нужно было убедиться, что целевая поверхность в UpdateSurface больше, чем исходная поверхность.

ЗАМЕТКА:

  • Это медленно, так как мы читаем из видеопамяти в системную память, а затем обратно в видеопамять.
  • Мне это нужно для моего приложения, так как я хочу захватить все, что ОС и другие приложения выводят на экран, но если вы просто беспокоитесь о своем собственном приложении, то есть лучшие альтернативы.
  • Если вы знаете способ GetFrontBufferData без помещения его в системную память (это единственный способ, которым я мог видеть, как он работает), сообщите мне об этом.
person Tim    schedule 04.04.2011