Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I want my XNA game to do its thing and at the end of the Draw() call read the the frame that is sent to the screen into memory (which in XNA would presumably be a Microsoft.Xna.Framework.Color[]).

Is is possible to this from XNA? If so how and when should I do it? Immediately before or after my:

base.Draw(gameTime); 

call?

share|improve this question
    
maybe you can do what you want in a pixel shader ? –  Zonko Jul 23 '12 at 19:49
add comment

2 Answers 2

(This was going to be a comment but it got too long, so...)

Not an XNA-specific answer, but in general terms this is something that you don't want to do.

The reason why is because of the way your GPU and your CPU work together. Draw calls and other commands that you send to the GPU don't happen immediately; instead they go into a buffer and your GPU will get round to processing them sometime later; it can normally be up to 3 frames later. This is one of the reasons why GPUs get to be so fast; the CPU can continue doing work at the same time as the GPU is processing draw calls and other commands.

Reading back from the GPU will break all of that. In order to read back from the GPU, the CPU has to pause, the GPU has to immediately execute everything that's been buffered up to the time of the readback, then the readback happens. No more asynchronous processing, instead you get a massive stall. Because of the "up to 3 frames" buffering, you can lose up to two-thirds of your performance. That's not trivial.

So, like I said, you really don't want to do this if at all possible. If there is something specific you're trying to achieve then letting us know what that something specific is can be helpful, as there are often solutions that don't involve a readback but will give you the result you want without the huge performance cost.

share|improve this answer
add comment

You generally don't want to do it, and mh01 explains why very well in his answer. You don't want to make it part of gameplay. You might want to add it for taking screenshots or video. But I recommend an external tool like Fraps for that anyway.

But, that being said, you can do it in XNA. There are two methods.

Method number one is to call GetBackBufferData (MSDN). You need to set your game project to the HiDef profile (the method is not compatible with the Reach profile).

(I also think you may need to play with the RenderTargetUsage of the backbuffer, if you also want to render that frame to the screen. I haven't played with it enough to be sure. But this answer gives you a starting point.)

The place to do this is right before the end of your Draw method. You could even put it in EndDraw. It basically needs to happen after everything is drawn, but before the backbuffer gets sent to the screen (and becomes unavailable to you).

The second method works in the Reach profile. The theory is similar, but instead of drawing to the backbuffer, you draw to a RenderTarget2D. You need to set that as the render target (with GraphicsDevice.SetRenderTarget) either at the begninng of your Draw method, or where you would otherwise call SetRenderTarget(null) (which would set the back buffer as the render target).

At the end of your Draw method, you've got an empty backbuffer and a render target with your scene in it. So simply call SetRenderTarget(null) and then use SpriteBatch (or similar) to draw the render target to the backbuffer to make it display.

When you want to extract the content of the render target, call RenderTarget2D.GetData. You can also use methods like SaveAsPng - which is convenient if you are trying to implement a screenshot feature.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.