2010-12-13 5 views
4

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

    создать визуализации цель:
    device->CreateRenderTarget(surf_desc.Width, surf_desc.Height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &render_target, NULL)
    преобразования YUV в RGB32:
    device->StretchRect(videomem_surf, NULL, render_target_, NULL, D3DTEXF_NONE)
    (полный прямоугольник, не растягивая)
    создать равнине закадровый поверхности в системной памяти
    device->CreateOffscreenPlainSurface(surf_desc.Width, surf_desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &sysmem_offscreen_surf, NULL)
    копировать данные за м видео АЕТ sysmem:
    device->GetRenderTargetData(render_target, sysmem_offscreen_surface)
    GetDC от закадровых поверхностей, создать совместимый DC и совместимый точечный рисунок, BitBlt из закадрового sufrace DC в совместимый DC и скопировать растровые биты в мой буфер GetDIBits()

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

благодаря

ответ

2

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

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

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

Так альтернатива является вызов GetRenderTargetData в внеэкранную поверхность, а затем зафиксировать внеэкранную поверхность (вместо того, чтобы использовать контроллеры домен и растровые изображения).

+0

какой формат данных LockRect предоставляет? не нашли никакого описания. то же, что и GetDIBits()? –

+0

@robin: Каждая строка пикселей имеет упакованные байты в соответствии с цветовым форматом.Итак, для D3DFMT_A8R8G8B8 у вас будет 4 байта на пиксель. Байты для каждого пикселя находятся в обратном порядке (little-endian), поэтому в этом случае они будут в порядке: B, G, R, A. И значение «Pitch», которое вам дано, указывает вам, сколько байтов занимает каждая строка. Это нужно, потому что в конце каждой строки могут быть неиспользуемые байты. – interjay

3

Ну, как указывает interjay ... вы почти делаете «правильный» способ.

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

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

Таким образом вы разрешите больше команд быть конвейерными и прекратить вызывать блокировку, а FORCING - синхронизацию конвейера (то есть поверхность, которую вы блокируете, должна быть готова, прежде чем продолжить, что приведет к синхронизации конвейера).