5

我有 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)
    将数据从视频内存复制到系统内存:
    device->GetRenderTargetData(render_target, sysmem_offscreen_surface)
    GetDC 从屏幕外表面,创建兼容 DC 和兼容位图,BitBlt 从屏幕外表面 DC 到兼容 DC,并通过 GetDIBits() 将位图位复制到我的缓冲区

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

谢谢

4

2 回答 2

4

好吧,正如 interjay 指出的那样……您几乎是以“正确”的方式做事。

明显的改进是调用 CreateRenderTarget 和 CreateOffscreenPlainSurface 一次,然后多次重复使用它们。将这些位取出的最快方法是直接 LockRect 表面。

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

这样,您将允许将更多命令流水线化,并停止调用 lock 并强制执行流水线同步(即,您要锁定的表面必须在继续之前准备好,这会导致流水线同步)。

于 2010-12-14T07:38:00.237 回答
3

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

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

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

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

于 2010-12-13T18:30:51.097 回答