Direct3D:从IDirect3DSurface9(默认池)获取系统内存位图的有效方法?

时间:2010-12-13 15:08:51

标签: directx direct3d direct3d9 rendertarget

我有IDirect3DSurface9,默认池,YUV格式。我怎样才能有效地从中获取位图位?目前我:

    创建渲染目标:
    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)
    将数据从视频mem复制到sysmem:
    device->GetRenderTargetData(render_target, sysmem_offscreen_surface)
    来自屏幕外表面的GetDC,创建兼容的DC和兼容位图,BitBlt从屏幕外的sufrace DC到兼容的DC并通过GetDIBits()
将位图位复制到我的缓冲区

这看起来有点开销,因为有很多复制:从原始表面到渲染目标,然后到屏幕外表面,再到兼容位图,最后到我的缓冲区。如何改进?

感谢

2 个答案:

答案 0 :(得分:4)

当interjay指出......你几乎是以“正确”的方式做事。

显而易见的改进是调用CreateRenderTarget和CreateOffscreenPlainSurface一次,然后多次重复使用它们。将比特退出的最快方法是直接锁定表面。

此外,如果您需要在像视频这样的东西上实时执行此操作,那么设置一个曲面阵列(两种类型)可能会更好。然后,您可以将多个YUV帧加载到CreateRenderTarget'd表面,然后填充数组后,将第一个复制到OffscreenPlainSurface并锁定它。

通过这种方式,您将允许更多的命令被流水线操作,并停止调用锁定和强制管道的同步(即,在继续之前锁定HAS以准备就绪,这会导致管道同步)。

答案 1 :(得分:3)

由于您以可锁定模式创建渲染目标(第6个参数为CreateRenderTarget),您可以使用LockRect锁定渲染目标并直接从那里复制数据。

MSDN建议不要使用可锁定的渲染目标,says

  

如果您需要对渲染目标的读访问权限,请使用GetRenderTargetData而不是可锁定   渲染目标。

另一种方法是将GetRenderTargetData调用到屏幕外表面,然后锁定屏幕外表面(而不是使用DC和位图)。