Скриншот части экрана через DirectX
От: xteam777  
Дата: 10.07.22 11:19
Оценка:
Доброго времени.
Имеется рабочая процедура, которая делает скриншот всего экрана целиком. Необходимо ее переделать, чтобы она брала именно нужную часть. При замене везде Width и Height к примеру на 100х100, в итоге получается черный экран.
Код взят отсюда
Что я пропустил?

Рабочий код
procedure TImageCatcher.GetDirectXData();
var
  BitsPerPixel: Byte;
  pD3D: IDirect3D9;
  pSurface: IDirect3DSurface9;
  g_pD3DDevice: IDirect3DDevice9;
  D3DPP: TD3DPresentParameters;
  ARect: TRect;
  LockedRect: TD3DLockedRect;
  BMP: VCL.Graphics.TBitmap;
  i, p: Integer;
  x, y: integer;
  w, h: integer;
  res: BOOL;
begin
  GetTargetDimensions(w, h); //Возвращает ширину и высоту экрана

  GetTargetPosition(x, y);
  BitsPerPixel := 32;
  FillChar(d3dpp, SizeOf(d3dpp), 0);
  with D3DPP do
  begin
    Windowed := True;
    Flags := D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    SwapEffect := D3DSWAPEFFECT_DISCARD;
    BackBufferWidth := Screen.Width;
    BackBufferHeight := Screen.Height;
    BackBufferFormat := D3DFMT_X8R8G8B8;
  end;
  pD3D := Direct3DCreate9(D3D_SDK_VERSION);
  pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, @ D3DPP, g_pD3DDevice);
  g_pD3DDevice.CreateOffscreenPlainSurface(Screen.Width, Screen.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, pSurface, nil);
  g_pD3DDevice.GetFrontBufferData(0, pSurface);
  ARect := Screen.DesktopRect;
  pSurface.LockRect(LockedRect, @ ARect, D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_NOSYSLOCK or D3DLOCK_READONLY);
  BMP := VCL.Graphics.TBitmap.Create;
  BMP.Width := Screen.Width;
  BMP.Height := Screen.Height;
  case BitsPerPixel of
    8: BMP.PixelFormat := pf8bit;
    16: BMP.PixelFormat := pf16bit;
    24: BMP.PixelFormat := pf24bit;
    32: BMP.PixelFormat := pf32bit;
  end;
  p := Cardinal(LockedRect.pBits);
  for i := 0 to Screen.Height - 1 do
  begin
    CopyMemory(BMP.ScanLine[i], Ptr(p), Screen.Width * BitsPerPixel div 8);
    p := p + LockedRect.Pitch;
  end;
  Bitmap.SetSize(w, h);
  res := BitBlt(Bitmap.Canvas.Handle, 0, 0, w, h, BMP.Canvas.Handle, x, y, SRCCOPY);
  BMP.Free;
  pSurface.UnlockRect;
end;


Измененный нерабочий код
procedure TImageCatcher.GetDirectXData();
var
  BitsPerPixel: Byte;
  pD3D: IDirect3D9;
  pSurface: IDirect3DSurface9;
  g_pD3DDevice: IDirect3DDevice9;
  D3DPP: TD3DPresentParameters;
  ARect: TRect;
  LockedRect: TD3DLockedRect;
  BMP: VCL.Graphics.TBitmap;
  i, p: Integer;
  x, y: integer;
  w, h: integer;
  res: BOOL;
begin
  GetTargetDimensions(w, h);

//  w := 50;
//  h := 50;

  GetTargetPosition(x, y);
  BitsPerPixel := 32;
  FillChar(d3dpp, SizeOf(d3dpp), 0);
  with D3DPP do
  begin
    Windowed := True;
    Flags := D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    SwapEffect := D3DSWAPEFFECT_DISCARD;
    BackBufferWidth := 100; //Screen.Width;
    BackBufferHeight := 100; //Screen.Height;
    BackBufferFormat := D3DFMT_X8R8G8B8;
  end;
  pD3D := Direct3DCreate9(D3D_SDK_VERSION);
  pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, @ D3DPP, g_pD3DDevice);
  g_pD3DDevice.CreateOffscreenPlainSurface(100 {Screen.Width}, 100 {Screen.Height}, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, pSurface, nil);
  g_pD3DDevice.GetFrontBufferData(0, pSurface);
  ARect := Rect(0, 0, 100, 100);  //Screen.DesktopRect;
  pSurface.LockRect(LockedRect, @ ARect, D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_NOSYSLOCK or D3DLOCK_READONLY);
  BMP := VCL.Graphics.TBitmap.Create;
  BMP.Width := 100; //Screen.Width;
  BMP.Height := 100; //Screen.Height;
  case BitsPerPixel of
    8: BMP.PixelFormat := pf8bit;
    16: BMP.PixelFormat := pf16bit;
    24: BMP.PixelFormat := pf24bit;
    32: BMP.PixelFormat := pf32bit;
  end;
  p := Cardinal(LockedRect.pBits);
  for i := 0 to 100 {Screen.Height} - 1 do
  begin
    CopyMemory(BMP.ScanLine[i], Ptr(p), 100 {Screen.Width} * BitsPerPixel div 8);
    p := p + LockedRect.Pitch;
  end;
  Bitmap.SetSize(w, h);
  res := BitBlt(Bitmap.Canvas.Handle, 0, 0, w, h, BMP.Canvas.Handle, x, y, SRCCOPY);
  BMP.Free;
  pSurface.UnlockRect;
end;
Отредактировано 10.07.2022 11:20 xteam777 . Предыдущая версия .
Re: Скриншот части экрана через DirectX
От: DiPaolo Россия  
Дата: 10.07.22 11:38
Оценка:
Можно брать весь экран, а потом кропать его. Вот пример для плюсов, для делфи должно быть аналогично.

https://docs.microsoft.com/en-us/windows/win32/direct2d/crop
Патриот здравого смысла
Re[2]: Скриншот части экрана через DirectX
От: xteam777  
Дата: 10.07.22 11:42
Оценка:
Здравствуйте, DiPaolo, Вы писали:

DP>Можно брать весь экран, а потом кропать его. Вот пример для плюсов, для делфи должно быть аналогично.


DP>https://docs.microsoft.com/en-us/windows/win32/direct2d/crop


Я хочу попробовать ускорить процедуру GetFrontBufferData, за счет уменьшения копируемой части. Взять все и потом обрезать тут не поможет
Re: Скриншот части экрана через DirectX
От: BlackEric http://black-eric.lj.ru
Дата: 10.07.22 14:29
Оценка:
Здравствуйте, xteam777, Вы писали:

X>Доброго времени.

X>Имеется рабочая процедура, которая делает скриншот всего экрана целиком. Необходимо ее переделать, чтобы она брала именно нужную часть. При замене везде Width и Height к примеру на 100х100, в итоге получается черный экран.
X>Код взят отсюда
X>Что я пропустил?

Various methods for capturing the screen. Я когда-то делал по описанию из этой статьи.
Но сделать скрин отдельно именно игры выводимой через DirectX у меня не получилось. Только скрин всего экрана и потом обрезка по координатам.

Вот есть описание как скриншотить игры, но сам не пробовал: Скриншотим игры — the hard way
https://github.com/BlackEric001
Отредактировано 10.07.2022 14:32 BlackEric . Предыдущая версия .
Re[3]: Скриншот части экрана через DirectX
От: alexander_r  
Дата: 11.07.22 12:58
Оценка: -1 :)
Здравствуйте, xteam777, Вы писали:

X>Я хочу попробовать ускорить процедуру GetFrontBufferData, за счет уменьшения копируемой части. Взять все и потом обрезать тут не поможет


Ускорить GetFrontBufferData таким образом не получиться т.к текстура должна быть такого же размера как и экран

https://docs.microsoft.com/en-us/windows/win32/api/d3d9/nf-d3d9-idirect3ddevice9-getfrontbufferdata
 ...the size of the destination surface should be the size of the desktop. For full-screen mode, the size of the destination surface should be the screen size.


Если нужно что бы работало быстро то https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/desktop-dup-api или
https://docs.microsoft.com/en-us/uwp/api/windows.graphics.capture?view=winrt-22621
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.