Sign in to follow this  
feal87

Copy texture to texture.

Recommended Posts

Hi,here I am for a "i hope" simple question. I have an engine that works on both DX9 and DX10 and was tinkering on the texture support. The function i'm working to is the "Copy" between 2 textures. As far as DX10 is concerned is pretty easy, CopyResource or CopySubresourceRegion and gogogo, you can do it with 5-6 lines of code. Well, the problem is DX9. What is the most efficient way to copy a texture to another texture in DX9? Please note that in my Engine (my specification) the source texture can be of any type, while the destination texture cannot be RenderTarget or Depth Stencil and obviously both texture must be of the same format. I hope to maintain the same contract in both DX9 and DX10. I was thinking about using many paths: 1) For the render target to use GetRenderTargetData(), copy it to a system memory texture and then resending it to the destination texture with UpdateSurface... 2) For the other texture lock them (as they are Managed) and copy the data. What do you think? And for the depth stencil as source? o.O

Share this post


Link to post
Share on other sites
It's probably worth doing a quick performance test against a "normal" lock / copy / unlock - it should be fast enough, but there's a chance it'll be slower if the code doesn't have a dedicated path for copying to the same size, same format surface.

Share this post


Link to post
Share on other sites
I have a strange problem with that function, it does copy something but its strangely damaged...

Here is an example :

Original Image
Extracted Image

I use the function as follow.

D3DXLoadSurfaceFromSurface(
pDestSurface,
NULL,
NULL,
pSrcSurface,
NULL,
NULL,
D3DX_FILTER_NONE,
0
);

The source surface is the toplevel (level 0) of a DEFAULT pooled texture, the destination surface is the toplevel (level 0) of a SYSMEM pooled texture.
Both texture have the same size and format.

Any clues?

P.S. I tried on other images with the same result, it makes some strange lines on the whole image o.O

Share this post


Link to post
Share on other sites
Interesting... Are you using the Debug runtimes? Any relevant debug output? If not, what does Pix say that call is doing internally? To me, it looks like it's got the width of the image wrong...

What if you use D3DX_FILTER_POINT instead (Although that's not really a good solution...)?

Share this post


Link to post
Share on other sites
No change with the change of Filter.

I mean it works, probably the problem is with my code with saving the image. (in Pix i see clearly the image correctly modified)

As far as what Pix says...well, the really crazy thing is what it does to copy DEFAULT pooled texture to a SYSMEM pooled texture (obviously with the POINT filter you said me, i'll change back and probably things will be more easy).

I'll explain for the fun of it :

1) StretchRect (probably think the size isn't different)
2) Create Render Target + SYSMEM (2 surfaces) of that size.
3) 5/6 lockrect/unlockrect.
4) A final UpdateSurface.

Anyway i'll work on understand why the save of the image isn't working. :P

Share this post


Link to post
Share on other sites
Quote:
Original post by feal87
I mean it works, probably the problem is with my code with saving the image. (in Pix i see clearly the image correctly modified)
Ah, sounds like a bug in your code then. What if you use D3DXSaveTextureToFile()?

Quote:
Original post by feal87
As far as what Pix says...well, the really crazy thing is what it does to copy DEFAULT pooled texture to a SYSMEM pooled texture (obviously with the POINT filter you said me, i'll change back and probably things will be more easy).
It sounds like it does that for the texture filtering

Quote:
Original post by feal87
Anyway i'll work on understand why the save of the image isn't working. :P
Or use D3DXSaveTextureToFile() :P

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
Quote:
Original post by feal87
I mean it works, probably the problem is with my code with saving the image. (in Pix i see clearly the image correctly modified)
Ah, sounds like a bug in your code then. What if you use D3DXSaveTextureToFile()?

Quote:
Original post by feal87
As far as what Pix says...well, the really crazy thing is what it does to copy DEFAULT pooled texture to a SYSMEM pooled texture (obviously with the POINT filter you said me, i'll change back and probably things will be more easy).
It sounds like it does that for the texture filtering

Quote:
Original post by feal87
Anyway i'll work on understand why the save of the image isn't working. :P
Or use D3DXSaveTextureToFile() :P


It works perfectly with SaveTextureToFile, but well I have to understand it anyway cause I have an internal library for managing images in memory, and it has to work regardless of DirectX. XD
Anyway THANKS, the problem is resolved. :)

Share this post


Link to post
Share on other sites
Another quick question :

When I lock a SYSMEM top-level surface (on a texture 450x338 ARGB32)
I expect a pitch of size 450*4 = 1800 bytes, but I get a pitch of 1920 bytes.
Any clues about the reason of this? XD
I lock the surface/texture using a simple LockRect without any flags or rect.

(this is the reason of the bad image, I was expecting a different size image and then making the whole image wrong :P)

Share this post


Link to post
Share on other sites
Quote:
Original post by feal87
Another quick question :

When I lock a SYSMEM top-level surface (on a texture 450x338 ARGB32)
I expect a pitch of size 450*4 = 1800 bytes, but I get a pitch of 1920 bytes.
Any clues about the reason of this? XD
I lock the surface/texture using a simple LockRect without any flags or rect.

(this is the reason of the bad image, I was expecting a different size image and then making the whole image wrong :P)
The driver is free to add padding at the end of each scanline, and this is frequently done with non-power-of-2 textures. In this case, the driver seems to be padding each scanline to a multiple of 32 pixels.

You should be handling this as follows:

byte* dest = destrect.pBits;
const byte* src = srcrect.pBits;
for(int y=0; y<height; ++y)
{
memcpy(dest_ptr, src_ptr, width*bytes_per_pixel);
dest_ptr += destrect.Pitch;
src_ptr += srcrect.Pitch;
}

I.e. only copy the pixel information, don't overwrite the padding (The driver can store information there [although usually they don't]), and advance by Pitch bytes each row.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this