Copying/saving a RenderTarget to another one

Hi !
I’m copying/saving an RT to another one, but I tried with copy to Texture2D, same problem:

_RT_Final = _RT_CurrentWorkInProgress
...
//Draw stuff onto _RT_Final (or to _RT_CurrentWorkInProgress changes nothing)
...

it seems they are linked, like with pointers in C++, and doing something to either one of them affects the other.
The only way to force a “copy” is to use a Texture2D and Get/Set Data.
Is this an expected behavior when using the operator ‘=’ ?

Yes. A variable or member of an object type in C# is like a pointer. If you assign the variable to another variable, it does not create a copy of the object. Both variables reference the same object instance.

I don’t know what you are trying to do. Are you wanting to re-use _RT_Final or add to it? If you wanted _RT_CurrentWorkInProgress to be the state of render at that time, you will need to do something like

SetRenderTarget(_RT_CurrentWorkInProgress)
// Draw stuff you want in the WIP texture
SetRenderTarget(_RT_Final)
// Draw _RT_CurrentWorkInProgress
// Draw the rest of the stuff
SetRenderTarget(null)

I don’t know why I forgot this on RenderTargets.
Nonetheless, what i need is to save the current state of an rt into another one, because it will be used by another component, like a luminosity extractor effect’s result will not be used only by bloom but lensflares for ex. While the original Rt will be drawn by the current component.

While writing i’m wondering if i’ll have to decouple even more my components so this problem doesn’t arise

Your only option might be to use Get/Set Data. This might fit your use-case if you’re doing this frequently:

public static RenderTarget2D CopyRenderTarget(RenderTarget2D origRT)
{
    RenderTarget2D newRT = new RenderTarget2D(origRT.GraphicsDevice, origRT.Width, origRT.Height);

    int[] rtData = new int[newRT.Width * newRT.Height];

    origRT.GetData(rtData);
    newRT.SetData(rtData);

    return newRT;
}

The problem with Kimimaru’s implementation is that you cannot use it in real time, this action will stall the whole game, so doing it every frame, for example, is not feasable (for consistent high framerates). This is because GetData/SetData transfer the memory from GPU to RAM in order to execute these commands on the CPU. But because GPU/CPU render cycles are shifted a bit this means stalling the pipeline.
In general GetData/SetData should be avoided at all costs, unless you are willing to take the hit or deem it absolutely necessary.

So an actual option is to write to your rendertarget on the GPU.

You can do that with monogame’s spritebatch, for example, but you could also use a simple texture read write shader.

E.g.
SetRenderTarget( newRT)
Spritebatch.begin
Spritebatch.draw ( old RT)
spritebatch.end

2 Likes

I have decoupled even more my components, so luminance extraction is not part a a bigger one like before.
So now the sequences of component doing their own effects and returning a rendertarget has solved the issue. thanks to all ! :slight_smile: (and by this mean i save 25 fps :))

What’s best for luminosity extraction ? Is it better to get the full scene render ? Or the _RT_Specular which contains the specular of a PBR renderer ?