Direct3D: efficient way to get system memory bitmap from IDirect3DSurface9 (default pool)?
Asked Answered
S

2

5

I have IDirect3DSurface9, default pool, YUV format. How can I efficiently get bitmap bits from it? At the moment I:

    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()

this looks a bit of overhead, because of so many copying: from original surface to render target, then to offscreen surface, then to compatible bitmap, and then finally to my buffer. How can this be improved?

thanks

Schexnayder answered 13/12, 2010 at 15:8 Comment(0)
T
3

Since you create you render target in lockable mode (6th parameter to CreateRenderTarget), you can lock the render target with LockRect and copy the data directly from there.

MSDN does not recommend using lockable render targets, and says:

If you need read access to render targets, use GetRenderTargetData instead of lockable render targets.

So an alternative is to call GetRenderTargetData into the offscreen surface, and then lock the offscreen surface (instead of using DCs and bitmaps).

Tourbillion answered 13/12, 2010 at 18:30 Comment(2)
which data format LockRect provides? haven't found any description. the same as GetDIBits()?Schexnayder
@robin: Each row of pixels has packed bytes according to the color format. So for D3DFMT_A8R8G8B8 you would have 4 bytes per pixel. The bytes for each pixel are in reversed order (little-endian), so in this case they would be in the order: B,G,R,A. And the Pitch value that is given to you tells you how many bytes each row takes. You need this because there may be unused bytes at the end of each row.Tourbillion
E
4

Well as interjay points out ... you are nearly doing things the "correct" way.

The obvious improvements are to call CreateRenderTarget and CreateOffscreenPlainSurface once and then re-use them multiple times. The fastest way of getting the bits back out would be to directly LockRect the surface.

Furthermore if you are needing to do this in real-time on something like video it would probably be better to set up an array of surfaces (both types). You can then load multiple YUV frames on to the CreateRenderTarget'd surface and then once you have filled the array then copy the first to the OffscreenPlainSurface and lock it.

This way you will allow more of the commands to be pipelined and stop you calling lock and FORCING a synchronisation of the pipeline (ie the surface you are locking HAS to be ready before proceeding which causes a pipeline sync).

Encroachment answered 14/12, 2010 at 7:38 Comment(0)
T
3

Since you create you render target in lockable mode (6th parameter to CreateRenderTarget), you can lock the render target with LockRect and copy the data directly from there.

MSDN does not recommend using lockable render targets, and says:

If you need read access to render targets, use GetRenderTargetData instead of lockable render targets.

So an alternative is to call GetRenderTargetData into the offscreen surface, and then lock the offscreen surface (instead of using DCs and bitmaps).

Tourbillion answered 13/12, 2010 at 18:30 Comment(2)
which data format LockRect provides? haven't found any description. the same as GetDIBits()?Schexnayder
@robin: Each row of pixels has packed bytes according to the color format. So for D3DFMT_A8R8G8B8 you would have 4 bytes per pixel. The bytes for each pixel are in reversed order (little-endian), so in this case they would be in the order: B,G,R,A. And the Pitch value that is given to you tells you how many bytes each row takes. You need this because there may be unused bytes at the end of each row.Tourbillion

© 2022 - 2024 — McMap. All rights reserved.