Rendertarget changes in XNA Game Studio 2.0
The bad news:
If you had a program using rendertargets that worked with the XNA Framework 1.0, it might not still work with 2.0.
The good news:
Things are actually much more consistent now, honest!
Let me explain...
How rendertargets used to work (1.0)
On Windows:
- Each rendertarget lives in a separate piece of video memory
- After you select the rendertarget, you can draw onto that video memory
- When you are done drawing, you call GetTexture to reuse that same area of video memory as a texture
- You can draw onto the same rendertarget as many times as you like, and its contents will always remain valid
On Xbox:
- All rendertargets share a single special piece of EDRAM memory
- This means only one of them can physically exist at a time
- When you finish drawing to a rendertarget, the GraphicsDevice.ResolveRenderTarget method copies from EDRAM to a separate area of texture memory
- You can then use this texture in any way you like
- But EDRAM is now being reused by some other rendertarget!
- This won't work like you expect:
- Draw to backbuffer (EDRAM contains what you just drew)
- Switch to rendertarget
- Draw to rendertarget (EDRAM contains what you just drew)
- Resolve rendertarget (RenderTarget.GetTexture() contains a copy of what you drew)
- Switch back to backbuffer (problem! the act of selecting a different rendertarget has overwritten what you previously drew to the backbuffer, so the EDRAM no longer contains that backbuffer image)
- The rules in summary:
- Any time you change rendertarget, the contents of EDRAM are overwritten, so all previous rendertargets (including the backbuffer) are clobbered
- Rendertarget data which was resolved into the associated texture remains valid, however
- This is ok:
- Draw to rendertarget A
- Draw to rendertarget B
- Draw textures from rendertargets A and B onto rendertarget C
- But this is not:
- Draw to rendertarget A
- Draw to rendertarget B
- Switch back to A and continue drawing over the top of it
Problem with the 1.0 behavior:
It was far too easy to write a program that worked fine on one platform, but then rendered incorrectly when you run it on the other!
How rendertargets work now (2.0)
By default:
- You get what used to be the Xbox behavior
- On Xbox, it works exactly the same as before
- On Windows, we automatically clear your rendertargets at the right times to emulate the Xbox behavior
- This is fast on both platforms (Clear is very cheap)
If you don't like that default:
- You can specify a different RenderTargetUsage
- RenderTarget2D constructor parameter
- To change it for the backbuffer, use the GraphicsDeviceManager.PreparingDeviceSettings event to alter GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage
- Specify RenderTargetUsage.PreserveContents to get what used to be the Windows behavior
- Works exactly the same as before on Windows
- On Xbox, we automatically copy data back from the resolved texture into EDRAM to restore its contents when you change rendertarget
- This is not cheap! Use it if you must, but be aware of the performance penalty
- Specify RenderTargetUsage.PlatformContents to get the exact same behavior as 1.0, which is different on Xbox versus Windows
Shawn recommends:
- If at all possible, use the default RenderTargetUsage.DiscardContents mode. This gives good performance and consistent behavior on both platforms.
Other good stuff:
- In 2.0, you no longer need to call the GraphicsDevice.ResolveRenderTarget method. In fact you can't, because we removed it. We now do this automatically when you switch away from the rendertarget.
- In 2.0, we now support multiple simultaneous rendertargets (MRT) on Xbox.