I'm using an engine which utilizes DirectX9.
It creates it's render targets using:
D3DXCreateTexture(
pD3DDevice, width, height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT, &pRT
)
And all other textures are created like so:
D3DXCreateTexture(
pD3DDevice, width, height,
1, 0, D3DFMT_A8R8G8B8,
D3DPOOL_MANAGED, &pTex
)
It is worth noting that the backbuffer is also D3DFMT_X8R8G8B8
so I am unsure why textures are created differently... but I suppose "if it ain't broke, don't fix it," right? All textures appear to load/render just fine.
For more details on how this engine operates, here is it's main graphics module's code.
(mostly note the Target_Create
and Texture_Create
methods)...
HOWEVER, I've had a ton of trouble trying to stick with these rules while trying to convert a render target texture into a regular texture. The engine has no built-in functionality for this, and render targets are treated as separate objects from textures... And in turn, this limits my ability to actually USE anything which requires a render target (ie, pixel shaders, etc). The end result is that I need to find a way to copy this render target data into a texture created as above, which the engine could use without any conflict.
I have tried something like the following:
inline PVOID LockedBits(LPDIRECT3DSURFACE9 surface, UINT w, UINT h, INT* size)
{
D3DLOCKED_RECT lr;
RECT rc = {0, 0, w, h};
surface->LockRect(&lr, &rc, 0);
if(size) *size = (w*h) * 4;
return lr.pBits;
}
inline PVOID LockedBits(LPDIRECT3DTEXTURE9 texture, UINT w, UINT h, INT* size)
{
D3DLOCKED_RECT lr;
RECT rc = {0, 0, w, h};
texture->LockRect(0, &lr, &rc, 0);
if(size) *size = (w*h) * 4;
return lr.pBits;
}
LPDIRECT3DTEXTURE9 CloneTextureFromTarget(LPDIRECT3DDEVICE9 device, LPDIRECT3DTEXTURE9 target, UINT w, UINT h)
{
D3DDISPLAYMODE dm;
device->GetDisplayMode(0, &dm);
// Create source and destination surfaces and copy rendertarget
LPDIRECT3DSURFACE9 dstSurf = NULL, srcSurf = NULL;
device->CreateOffscreenPlainSurface(w, h, dm.Format, D3DPOOL_SYSTEMMEM, &dstSurf, NULL);
target->GetSurfaceLevel(0, &srcSurf);
device->GetRenderTargetData(srcSurf, dstSurf);
SafeRelease(&srcSurf);
// Create destination texture
LPDIRECT3DTEXTURE9 dstTexture = NULL;
D3DXCreateTexture(device, w, h, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &dstTexture);
// Get bits for destination surface and texture
INT dwSrc, dwDst;
PVOID pBitsSrc = LockedBits(dstSurf, w, h, &dwSrc);
PVOID pBitsDst = LockedBits(dstTexture, w, h, &dwDst);
// Copy bits from surface to texture
RtlCopyMemory(pBitsSrc, pBitsDst, dwSrc);
dstTexture->UnlockRect(0);
dstSurf->UnlockRect();
SafeRelease(&dstSurf);
/* Just to double-check if it worked... */
D3DXSaveTextureToFileA("C:\\outSrc.png", D3DXIFF_PNG, target, NULL);
D3DXSaveTextureToFileA("C:\\outDst.png", D3DXIFF_PNG, dstTexture, NULL);
// Return the result
return dstTexture;
}
The result of this code is that both textures are properly saved to disk and come out as expected, but refuse to properly render...
Am I doing something wrong?
What's the best way to achieve a perfect copy of this data into a new texture created with D3DFMT_A8R8G8B8
and D3DPOOL_MANAGED
?
D3DFMT_A8R8G8B8
, only the backbuffer of the device should be created withD3DFMT_X8R8G8B8
. Moreover this rendertarget normally can be used for rendering, but not for locking-operations. Do you need a lock or do you only want to render the rendertarget onto the backbuffer? – GnietschowD3DFMT_A8R8G8B8
then I would still require a means of stripping it away into a newD3DPOOL_MANAGED
texture, since I will no longer have any use for the rendertarget object and would like to free up any resources it uses. The engine treats textures and rendertargets as separate objects, where rendertargets store/consume more resources... And for rendering, my application utilizes an array of texture objects, so the rendertarget is merely used during initialization to create new textures (in a pixel shader) to add to this array ofD3DPOOL_MANAGED
textures. – RectangleEqualsD3DPOOL_MANAGED
texture, then no it does not require locking support... Otherwise, yes it does. Any idea how I could safely clone this data into a new texture? Also, does the code above work for you? For me, it appears to correctly save the image to disk, but somehow fails to render in my application. – RectangleEqualsStretchRect
to copy your rendertarget? In one of my applications I used it to get the data of a rendertarget and it worked well. – GnietschowStretchRect
to go from a RT texture to a normal texture. Only off-screen plain textures can go into a regular texture, and it doesn't even allow copying from RT to off-screen plain. – RectangleEquals