В настоящее время используется DXGI Desktop Duplication API для захвата моего экрана. У меня есть необходимость масштабировать вывод, а затем получить доступ к битам напрямую. В идеале я хотел бы сделать это на видеокарте для лучшей производительности.
У меня это работает с использованием Direct2D следующим образом:
// Create an ID2DBitmap with data shared from my DXGISurface
ID2D1Bitmap* backBmp;
D2D1_BITMAP_PROPERTIES const p = D2D1::BitmapProperties( /* Setup PixelFormat, Dpi */);
m_d2dDeviceContext->CreateSharedBitmap(__uuidof(IDXGISurface), (void*) m_dxgiSurface, &p, &backBmp);
Мой backBmp
имеет опцию D2D1_BITMAP_OPTIONS_CANNOT_DRAW
. Поэтому я не могу использовать его для рисования. Я не могу найти способ создания нарисованного ID2DBitmap непосредственно из моего DXGISurface. Поэтому вместо этого я создаю промежуточное растровое изображение:
// Create a drawable ID2DBitmap, and copy the data from backBmp
ID2D1Bitmap1* frontBmp;
D2D1_SIZE_U size = // Set the proper size...
D2D1_BITMAP_PROPERTIES1 const props = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET,
/* Setup PixelFormat, Dpi */
);
m_d2dDeviceContext->CreateBitmap(size, nullptr, 0, &props, &frontBmp);
frontBmp->CopyFromBitmap(nullptr, backBmp, nullptr);
Теперь у меня есть растровое растровое изображение, я создаю другое растровое изображение соответствующего размера, устанавливаю его в качестве цели рендеринга и рисую в нем frontBmp
. Вот где происходит масштабирование.
ID2D1Bitmap1* scaledBmp;
D2D1_SIZE_U scaledSize = // Set the scaled size
m_d2dDeviceContext->CreateBitmap(scaledSize, nullptr, 0, &props, &scaledBmp);
m_d2dDeviceContext->SetTarget(scaledBmp);
m_d2dDeviceContext->BeginDraw();
m_d2dDeviceContext->DrawBitmap(frontBmp, /* Other options for drawing here */);
m_d2dDeviceContext->EndDraw();
Наконец, я хочу отобразить это в системной памяти и получить доступ к битам. Однако я не могу установить D2D1_BITMAP_OPTIONS_CPU_READ
на своем scaledBmp
- из документации :
D2D1_BITMAP_OPTIONS_CPU_READ означает, что растровое изображение может быть отображено с помощью ID2D1Bitmap1 :: Map. Этот флаг требует D2D1_BITMAP_OPTIONS_CANNOT_DRAW и не может быть объединен с любыми другими флагами. Растровое изображение необходимо обновить с помощью методов CopyFromBitmap или CopyFromRenderTarget.
Итак ... Теперь я создаю 4-е растровое изображение с параметром D2D1_BITMAP_OPTIONS_CPU_READ
и копирую в него масштабированные данные
ID2D1Bitmap1* stageBmp;
D2D1_BITMAP_PROPERTIES1 const props1 = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_CPU_READ | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
/* Setup PixelFormat, Dpi */
);
m_d2dDeviceContext->CreateBitmap(scaledSize, nullptr, 0, &props1, stageBmp);
И, наконец, теперь я могу Map
мой stageBmp
и получить доступ к битам.
Подведем итог:
Растровое изображение 1 - создано из моей поверхности DXGI с использованием CreateSharedBitmap
. Не может использоваться для рисования.
Растровое изображение 2 - промежуточное растровое изображение, используемое для рисования моего растрового растрового изображения. Создано с использованием CopyFromBitmap
из растрового изображения 1
Растровое изображение 3 - Масштабированное растровое изображение, используемое в качестве цели рендеринга. Создано и извлечено из Bitmap 2. Не может использоваться для доступа к процессору
Битовая карта 4 - промежуточная битовая карта, используемая для отображения. Создано с использованием CopyFromBitmap
из Bitmap 3.
Все это кажется слишком сложным - мне нужно создать всего 4 растровых изображения, каждое с соответствующими установленными флагами, и перемешивать данные между ними. Это рекомендуемый / действительный подход? Есть ли способ лучше? Direct2D и 3D API большие, и я не могу не чувствовать, что что-то упустил ...