Эффективное масштабирование DXGISurface с использованием Direct2D - PullRequest
1 голос
/ 30 мая 2019

В настоящее время используется 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 большие, и я не могу не чувствовать, что что-то упустил ...

1 Ответ

0 голосов
/ 30 мая 2019

Чтобы уточнить, вы хотите:

  • цель на основе поверхности DXGI, к которой вы хотите получить доступ позже в качестве буфера sysmem;
  • Нарисуйте еще одно растровое изображение с некоторым масштабированием.

Вы можете использовать CreateBitmapFromDxgiSurface с D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW флажками. Затем установите его с помощью SetTarget. Затем создайте исходное растровое изображение, которое вы хотите нарисовать на этой поверхности. Чтобы применить масштабирование, просто установите transform с SetTransform. После этого выполните ничью.

Позже, чтобы получить доступ к sysmem поверхности dxgi, вы можете использовать IDXGISurface::Map.

...