Purple screen of death

Anybody deal with viewports in XNA? Anybody ever try, for let's say split screen play, to render half the backbuffer in one rendering pass, and the other half in a second pass? Ever get a half screen of purple and a half screen of actual render?

This is actually something that XNA does on its own, and you'll probably see it if you deal with post-processing effects and viewports on the main back buffer (in other words, you're split screening). I looked this up on the XNA forums, and there people said that whenever you call SetRenderTarget and change the current render target to anything, the back buffer gets cleared to purple. I think the reasons went something along the lines of making XNA play nice with the XBox360 without killing it in terms of processor load.

There are ways around this, and they involve telling XNA to preserve the contents of the back buffer... or any graphics buffer (i.e. render targets). There's the property you can set when you initialize the render target, RenderTargetUsage.PreserveContents.


RenderTarget = new RenderTarget2D( ... , RenderTargetUsage.PreserveContents);

Then, you can add a listener to the GraphicsDeviceManager object to set this value manually so that it applies to the back buffer.


public Game() {
    this.Graphics = new GraphicsDeviceManager(this);
    this.Graphics.PreparingDeviceSettings += CustomDeviceSettings;
    ...
}

public void CustomDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e) {
    e.GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage = RenderTargetUsage.PreserveContents;
}

... Which is code that I've heard works and I experimented a bit with it, but I eventually opted for something else. I've also heard that using PreserveContents is not as efficient as it could be, and my computer is nearing double digits in age.

It's quite a bit simpler, and suits my needs - each viewport I render goes into its own render target. When I finish rendering all the viewports I need, I clear the back buffer and use SpriteBatch to draw onto the back buffer directly. I haven't lost anything out of it because I haven't actually used it yet.


protected override void Draw(GameTime Time) {
    m_Renderer.Draw(Time, m_RenderTarget1, m_Camera1);
    m_Renderer.Draw(Time, m_RenderTarget2, m_Camera2);

    GraphicsDevice.SetRenderTarget(null);
    GraphicsDevice.Clear(Color.Black);

    m_SpriteBatch.Begin();
    m_SpriteBatch.Draw(m_RenderTarget1, m_Viewport1.Bounds, Color.White);
    m_SpriteBatch.Draw(m_RenderTarget2, m_Viewport2.Bounds, Color.White);
    m_SpriteBatch.End();

    base.Draw(Time);
}

The renderer's draw function actually swaps between a bunch of render targets, because there's quite a bit of post-processing going on. When I wasn't split screening, I'd just use SpriteBatch to draw an entire render target onto the back buffer. Now, I just pass in an output parameter (the second argument), and render it when I'm ready.

... And dang, it's a pain to format code.