Jump to content
  • Advertisement
Sign in to follow this  
andy55

Advanced DX9 screenshot advice/question

This topic is 3856 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey guys, I'm hoping a DX9 maverick here can offer some insight into a relatively quick question... I'm adding a screenshot feature to my DX9 app, but because I can't guarantee that d3dx9_26.dll will be present, I can't use any of the D3DXSaveSurfaceTo*() calls (and distributing d3dx9_26.dll isn't an option either). Problems arise when I try to use the usual IDirect3DSurface9 calls: I can't use GetRenderTargetData() since by back buffer uses multisampling, and I can't use GetFrontBufferData() since I also run in windowed mode (so the window could be obscured or off the screen). So the question is: what is D3DXSaveSurfaceToFileInMemory() doing in order to always get that back buffer in a 32 bit D3DPOOL_SYSTEMMEM buffer?? So, in short, I'm trying to figure out the magic of D3DXSaveSurfaceToFileInMemory() -- it somehow is able to generate a D3DFMT_A8R8G8B8 buffer despite the fact that surface its given (via GetRenderTarget()) uses multisampling. If I could figure out what it's doing, then I could simply do the same and be on my way! So, it'd be great if any DX9 aces here can offer some snippets or insight into this... Thanks in advance! Andy

Share this post


Link to post
Share on other sites
Advertisement
You could make your back buffer lockable when you create the swap chain with D3DPRESENTFLAG_LOCKABLE_BACKBUFFER. That can be a performance hit though.

Alternatively when the screenshot button is pressed render the scene again to a new off screen render target which you can use GetRenderTargetData() on. You can make it really big and then rescale it to get antialiasing.

A quick search also turned up PrintWindow(). No idea if it'll work though.

You could also simulate a print screen keypress (VK_SNAPSHOT) and pull the data from the clipboard, but that'll trash anything that was on the clipboard before so I wouldn't recommend it.

Share this post


Link to post
Share on other sites
You could indeed GetRenderTargetData() but for it to be a meaningful file save you would have to write a file in a specific format. You could use FreeImage to write an image file to disk, though this involves dragging in an entire library for the purpose of a small operation.

Share this post


Link to post
Share on other sites
Quote:
Original post by Adam_42
You could make your back buffer lockable when you create the swap chain with D3DPRESENTFLAG_LOCKABLE_BACKBUFFER. That can be a performance hit though.


This is a performance app, so unfortunately that's not an option...

Quote:

Alternatively when the screenshot button is pressed render the scene again to a new off screen render target which you can use GetRenderTargetData() on. You can make it really big and then rescale it to get antialiasing.


As far as I know, many drivers produce different output to offscreen surfaces, so this is unfortunately out (plus, an advantage of an actual back buffer capture is that you're guaranteed to get any artifacts that the 3D hardware produced, etc--very useful for remote support).

The big issue is that D3DXSaveSurfaceTo*() seems to be able to do the job with the surface alone (i.e. no re-rendering) and presumably is only using public DX9 calls, so the question is what the heck is it doing.

Quote:

You could also simulate a print screen keypress (VK_SNAPSHOT) and pull the data from the clipboard, but that'll trash anything that was on the clipboard before so I wouldn't recommend it.


Like the problem with using GetFrontBufferData() that I mentioned, this approach falls short if the output window is obscured, minimized, or off the screen rect. Hmmm....

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave
You could indeed GetRenderTargetData() but for it to be a meaningful file save you would have to write a file in a specific format. You could use FreeImage to write an image file to disk, though this involves dragging in an entire library for the purpose of a small operation.


Well, the call to GetRenderTargetData() fails so it's not a format issue (the GetRenderTargetData() docs say that it will fail if the source surface uses multisampling, so it's behaving as expected). I can see how this makes sense since converting a multisample back surface to screen pixels is inherently a destructive process.

The question remains, then, what could D3DXSaveSurfaceToFileInMemory() be doing to convert that back buffer while keeping everything intact? My only theory is that it makes a change to the swap chain, triggers a non destructive copy to an offscreen surface, and then restores the old swap chain.

Thoughts/comments?

Share this post


Link to post
Share on other sites
Hmm, you could try using a PIX capture to see what D3D functions the D3DX function calls. Maybe that will give you some more ideas.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!