0
\$\begingroup\$

I encountered this strange problem where my UI drawing to RenderTarget2D works for a couple seconds and then suddenly goes black.

This is the RenderTarget2D function:

public RenderTarget2D RenderUi(SpriteBatch spriteBatch) {
    RenderTarget2D renderTarget = new RenderTarget2D(Graphics, 1920, 1080);
    Graphics.SetRenderTarget(renderTarget);

    Graphics.Clear(Color.Transparent);

    spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default);

    /* Goes black even if commented out
     - My draw calls
    */

    spriteBatch.End();

    Graphics.SetRenderTarget(null);

    return renderTarget;
}

And this is the Draw function:

public virtual void Draw(GameTime gameTime) {
    RenderTarget2D uiRenderTarget = UserInterface.RenderUi(SpriteBatch);

    /* Main SpriteBatch */
    SpriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp,
        null, null, null, Camera.TransformMatrix());

    World.Draw(gameTime, SpriteBatch);
    Entities.Draw(gameTime, SpriteBatch);

    SpriteBatch.End();

    /* Ui SpriteBatch */
    SpriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.AnisotropicClamp, DepthStencilState.Default);
    if (Input.IsAction(Actions.DrawUI))
        SpriteBatch.Draw(uiRenderTarget, new Rectangle(0, 0, Graphics.GraphicsDevice.Viewport.Width, Graphics.GraphicsDevice.Viewport.Height), Color.White);

    SpriteBatch.End();
}

So if I hold down the DrawUI button the UI draws correctly and everything below but then it suddenly goes black, releasing the button shows that everything but that RenderTarget still draws fine.

Why does this happen and what can I do to avoid that?

\$\endgroup\$
4
  • \$\begingroup\$ Why are you creating a new render target each frame? You should probably instead just create one once and reuse it. What happens if you change the code so that you only create one once? Does the problem still persist? \$\endgroup\$
    – user35344
    Sep 18 '16 at 12:13
  • \$\begingroup\$ If I create it once it does not go black. But I need a new render target each frame because I draw the complete UI in 1920x1080 on it and then scale it to match the given window resolution \$\endgroup\$
    – Spky
    Sep 18 '16 at 12:26
  • \$\begingroup\$ That doesn't justify creating a new render target to me. Couldn't you simply always reuse the texture and scale on render? \$\endgroup\$
    – user35344
    Sep 18 '16 at 12:27
  • \$\begingroup\$ If you meant that I reuse and clear RenderTarget2D renderTarget = new RenderTarget2D(Graphics, 1920, 1080); instead of creating a new one each frame. Then thanks that helped. \$\endgroup\$
    – Spky
    Sep 18 '16 at 12:36
2
\$\begingroup\$

The issue to me seems to be that you're creating a new RenderTarget2D on every frame, which is not a good practice. You're asking the GPU to allocate new memory for a texture constantly, which is unnecessary. I'm assuming that the GPU runs out of memory or something similar, and this is why your texture appears black after a while.

Instead, you should be able to simply reuse the same render texture. Create one in your constructor or some otherplace that gets called only once. Then, render to that texture (you probably want to clear it first) in your RenderUi method, and finally render the texture to the screen, properly scaled. XNA should allow you to simply specify the destination size of the texture, and that shouldn't affect that actual texture in any way.

If you decide to change your approach of resolution independent scaling, you could also simply create a new render texture when the window is resized. I'm not familiar with XNA's APIs, but I'm sure it offers callbacks on window resize.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .