Can't keep RenderTarget from being disposed after gameScreen change.

I wanna keep the last rendered frame of one screen using MG extended to put it in the background of another.
The Screen however really insists on disposing that rendertarget when the Screen is changed. How can I keep the rendertarget when changing Screens.

The GameScreen:

public class Menu : GameScreen
{
    public override void LoadContent()
    {
        Game.lastRenderTarget = new RenderTarget2D();
    }

    public override void Draw()
    {
        renderTarget.Dispose();
        Game.lastRenderTarget = new RenderTarget2D();

        Game.GraphicsDevice.SetRenderTarget(Game.lastRenderTarget);
        
        Game._spriteBatch.Begin();
        Game._spriteBatch.Draw(_texture, _position, Color.White);
        Game._spriteBatch.End();

        Game.GraphicsDevice.SetRenderTarget(null);

        Game._spriteBatch.Begin();
        Game._spriteBatch.Draw(Game.lastRenderTarget);
        Game._spriteBatch.End();

    }
}

The Main Game:

public class Client : Game
{
    public SpriteBatch _spriteBatch;

    private ScreenManager _screenManager;

    public RenderTarget2D lastRenderTarget;

    public Client()
    {
        _screenManager = new ScreenManager();
        Components.Add(_screenManager);
    }

    protected override void Initialize()
    {

        renderTarget = new RenderTarget2D();

        base.Initialize();
        LoadMenu();
    }

    private void LoadMenu()
    {
    
        _screenManager.LoadScreen(new Menu(this));
    }

    private void LoadGmae()
    {
        _screenManager.LoadScreen(new Gmae(this));
    }
}

The GameScreen I want to change to:

public class Gmae : GameScreen
{
    private new Client Game => (Client)base.Game;

    public override void Draw(GameTime gameTime)
    {

        GraphicsDevice.SetRenderTarget(null);
        Game._spriteBatch.Begin();

        Game._spriteBatch.Draw(Game.lastRenderTarget);

        Game._spriteBatch.End();
    
    }
}

Simplefied it a lot but I think everything relevant is in there.

I’m not specifically sure why this happens, but these lines of code stand out as a bit of a red flag. I don’t think you need to dispose the rendertarget and recreate it each frame. It should still work out because the last thing that happens after a draw is that it’s created and drawn to, but you don’t need to do that.

You can just clear it instead.

graphics.SetRenderTarget(someTarget);
graphics.Clear(Color.Purple); // Whatever colour you like here.
// the rest of what you have.

Past that, I’m not sure… maybe the class that owns it is getting disposed somehow? It’s tough to tell from the code you posted, unfortunately.

You’re right the dispose and recreation isn’t needed everytime. I had it this way as to accomodate for any resolution changes but I can just incoperate that into the method that changes the resolution.

I just changed that and it (as I already suspected) didn’t help. Defenitely improved my code though, so thanks for that. The screen aka the class is beeing disposed, thats why I use a renderTarget that is declared in the Main Game. Am I perhaps doing something wrong by doing that??

Hmmm, I’m not sure why it would be disposing then. Yea, if it’s attached to your main game it shouldn’t dispose automatically. To be honest, it shouldn’t anyway as long as someone else is holding the reference.

You don’t have any more calls to dispose on that rendertarget anywhere else in your code, right?

Only in a window resize method, which I’m 99% sure isn’t triggering when it’s not supposed to.

Doesn’t seem likely but maybe check with a breakpoint anyway?

The only other thing I can think of is to try to reproduce this in a minimal project. Like, you have this labeled as extended but from what I can see of your code, this is just a render target so extended doesn’t need to be involved.

When I can’t figure stuff out, I find it helps to just make a new project and try to reproduce it there. It’s usually easier to do some destructive testing without messing with your main code.

I can’t think of anything else to suggest, sorry :frowning:

Alright, I did what you suggested and the problem doesn’t occur when I’m not using Extended Gamescreen feature. It only happens if the screen “interacts” with the rendertarget. Now I’m just really confused…

Well, that’s progress! It might still not be a problem with Extended and could be how you’re using it. I don’t know anything about that feature, but is it possible to then iterate on your stand alone example to utilize Gamescreen and see if you can reproduce?

If you can, it might be a problem with the library so you could probably post the info on github for the author to fix. If you can’t, the problem is still likely in your use of it… somewhere… :smiley:

RenderTargets don’t usually preserve content unless you use RenderTargetUsage.PreserveContents in the RenderTarget’s constructor. As the API states though this will potentially be slower and have an additional memory cost.

https://docs.monogame.net/api/Microsoft.Xna.Framework.Graphics.RenderTargetUsage.html

https://docs.monogame.net/api/Microsoft.Xna.Framework.Graphics.RenderTarget2D.html#Microsoft_Xna_Framework_Graphics_RenderTarget2D__ctor_Microsoft_Xna_Framework_Graphics_GraphicsDevice_System_Int32_System_Int32_System_Boolean_Microsoft_Xna_Framework_Graphics_SurfaceFormat_Microsoft_Xna_Framework_Graphics_DepthFormat_System_Int32_Microsoft_Xna_Framework_Graphics_RenderTargetUsage_

Thanks for the comment, seems like I didn’t include all important information…
I actually didn’t remember what I had written in the constructor, so when I read your comment I thought “This may actually be it!” and I would’ve been glad if it was, but sadly I already set it this way. Here’s what I always write in the constructor of the rendertarget:

new RenderTarget2D(GraphicsDevice, Game.gameResolutionX, Game.gameResolutionY, false, GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.Depth24, GraphicsDevice.PresentationParameters.MultiSampleCount, RenderTargetUsage.PreserveContents);

Also as described in an above comment, the problem seems to only occur when the rendertarget is used within the draw method of an extended Gamescreen. I’ll have to try what Trinith suggested and work my way up from a new project until I walk into the problem or don’t , we’ll see.

I’ll maybe also comment a short how-to-reproduce in the near future if anyone wants to try and see if they can find the problem in the code or in my logic when they can see the actual code in front of them.

How about before rendering to the main screen render it all to a final rendertarget, than that final rendertarget to the main screen

Then you can use the final rendertarget for your background of another

You can hook into the window changed size event and re-create the render target when that happens.

  1. What class is GameScreen inheriting from?

  2. Would it work for you rendered the whole GUI system to the render target?

// start an off screen pass
GraphicsDevice.SetRenderTarget(renderTarget);
// clear the contents of the pass
GraphicsDevice.Clear(Color.Black);
// render the gui system offscreen
guiSystem.Draw(gameTime);
// end the off screen pass AND start the main framebuffer pass
GraphicsDevice.SetRenderTarget(null);
// clear the framebuffer 
GraphicsDevice.Clear(Color.Black);
// render the contents of the offscreen pass to the framebuffer
spriteBatch.Begin();
spriteBatch.Draw(renderTarget);
spriteBatch.End();