Direct3D: эффективный способ получить растровое изображение системной памяти из IDirect3DSurface9 (пул по умолчанию)?

У меня IDirect3DSurface9, пул по умолчанию, формат YUV. Как я могу эффективно получить биты растрового изображения из него? На данный момент я:

    create render target:
    device->CreateRenderTarget(surf_desc.Width, surf_desc.Height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &render_target, NULL)
    convert YUV to RGB32:
    device->StretchRect(videomem_surf, NULL, render_target_, NULL, D3DTEXF_NONE)
    (complete rectangle, no stretching)
    create plain offscreen surface in system memory
    device->CreateOffscreenPlainSurface(surf_desc.Width, surf_desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &sysmem_offscreen_surf, NULL)
    copy data from video mem to sysmem:
    device->GetRenderTargetData(render_target, sysmem_offscreen_surface)
    GetDC from offscreen surface, create compatible DC and compatible bitmap, BitBlt from offscreen sufrace DC to compatible DC and copy bitmap bits to my buffer by GetDIBits()

это выглядит немного накладно из-за большого количества копий: с исходной поверхности на цель рендеринга, затем на закадровую поверхность, затем на совместимое растровое изображение и, наконец, в мой буфер. Как это можно улучшить?

Спасибо


person Andriy Tylychko    schedule 13.12.2010    source источник


Ответы (2)


Поскольку вы создаете цель рендеринга в блокируемом режиме (6-й параметр для CreateRenderTarget), вы можете заблокировать цель рендеринга с помощью LockRect и копировать данные прямо оттуда.

MSDN не рекомендует использовать блокируемые цели рендеринга и говорит :

Если вам нужен доступ для чтения к целям рендеринга, используйте GetRenderTargetData вместо блокируемых целей рендеринга.

Таким образом, альтернативой является вызов GetRenderTargetData на внеэкранной поверхности, а затем блокировка внеэкранной поверхности (вместо использования DC и растровых изображений).

person interjay    schedule 13.12.2010
comment
какой формат данных предоставляет LockRect? описания не нашел. так же, как GetDIBits()? - person Andriy Tylychko; 15.12.2010
comment
@robin: каждая строка пикселей имеет упакованные байты в соответствии с цветовым форматом. Таким образом, для D3DFMT_A8R8G8B8 у вас будет 4 байта на пиксель. Байты для каждого пикселя находятся в обратном порядке (с прямым порядком байтов), поэтому в этом случае они будут в порядке: B, G, R, A. И значение Pitch, которое вам дается, говорит вам, сколько байтов занимает каждая строка. Это необходимо, поскольку в конце каждой строки могут быть неиспользуемые байты. - person interjay; 15.12.2010

Что ж, как указывает Interjay ... вы делаете все почти «правильным» образом.

Очевидные улучшения заключаются в том, чтобы вызывать CreateRenderTarget и CreateOffscreenPlainSurface один раз, а затем повторно использовать их несколько раз. Самый быстрый способ вернуть биты обратно — это напрямую заблокировать поверхность.

Кроме того, если вам нужно сделать это в режиме реального времени на чем-то вроде видео, вероятно, было бы лучше настроить массив поверхностей (оба типа). Затем вы можете загрузить несколько кадров YUV на поверхность CreateRenderTarget, а затем, когда вы заполните массив, скопируйте первый в OffscreenPlainSurface и заблокируйте его.

Таким образом, вы разрешите конвейерную обработку большего количества команд и остановите вызов блокировки и ПРИНУДИТЕЛЬНУЮ синхронизацию конвейера (т. е. поверхность, которую вы блокируете, ДОЛЖНА быть готова перед продолжением, что вызывает синхронизацию конвейера).

person Goz    schedule 14.12.2010