RenderTargetRenderer

Introduction

The RenderTargetRenderer is a class which can be used to greatly increase the performance of FlatRedBall games which present complex scenes which never or rarely change. For static scenes a RenderTargetRenderer allows for near infinite complexity – specifically it allows for a very large number of visual elements to be drawn with almost no slowdown.

Also, the RenderTargetRenderer is an easy way to render to a RenderTarget for post-processing.

The code for RenderTargetRenderer can be found on GlueVault.

Performance Example

This example will show how to render a very large number of Entities with essentially no slowdown. To set up the project:

  1. Create a new Glue project
  2. Import the following Entity: File:GraphicWithText.entz
  3. Create a new Screen. I’ll call mine GameScreen

Before we add anything to the game we’ll want to turn off any framerate throttling so we can see actual performance differences. To do this open Game1.cs and add the following code to the Game1 constructor:

Next we’ll add code to our GameScreen. To do this, open the GameScreen.cs file and modify the CustomInitialize and CustomActivity methods as follows:

This results in the game running around 7 frames per second (on my hardware at the time of this writing):

LowFpsPart1.PNG

Notice that the entities are converted to being manually updated, which reduces the update load significantly. The low frame rate in this case comes almost purely from rendering. For more information on ConvertToManuallyUpdated, see this page.

In this case we’ll assume that once the Entities have been placed they will not need to move or change otherwise. We can therefore take a “snapshot” of the screen using the RenderTargetRenderer and improve the performance significantly.

Since the RenderTargetRender only creates a Texture2D, we will need to create an object to display it. To do this:

  1. Switch to Glue
  2. Right-click on the Objects folder under the GameScreen
  3. Select “Add Object”
  4. Verify “FlatRedBall or Custom Type” is selected
  5. Select the Sprite type
  6. Call the Sprite RenderTargetSprite

Now we can switch to code to create a Texture2D for the Sprite. To do this, replace the CustomInitialize function with the following:

The result is a much higher framerate which fluctuated into the 2000’s:

HighFps1.PNG

Further optimizations

The example above shows how to perform a single render for all visuals and then to reuse that in a regular FRB Sprite for maximum performance. Of course, if the entities were being created only for a single render then we would want to destroy the entities after the render was finished.

The CustomInitialize would be modified as follows:

The immediate destruction of the entities does not necessarily boost frame rate, but it does remove objects from the game which can reduce ram usage.

ReRender

The ReRender function allows a render target to render itself again to the texture. The ReRender function has a number of conveniences built-in:

  • The initialization code does not need to be run again – the size of the texture, content managers, and name of the texture are all preserved
  • The Texture2D reference remains valid, so it does not need to be re-assigned
  • Objects do not need to be re-added to the RenderTargetRenderer’s Layer – they are preserved.

The full code example for using ReRender is as follows:

Since all objects receive a full update after rotation, updates can be expensive. However once updates are complete the game resumes at full framerate:
RotatedHighFps.PNG

Integration with Glue

The examples above show how to create entity instances and manually place them on the RenderTargetRenderer Layer. These examples illustrate how to work with the RenderTargetRenderer, but they do not reflect real Glue scenarios where objects may be defined in Glue or in files (such as Tiled TMX files) and added to Layers also created in Glue.

Fortunately existing Layers can be added to RenderTargetRenderer instances. The following example code shows how to take a LayerInstance defined in Glue and to add it to the RenderTargetRenderer:

Now anything that is added to that Layer will be part of the RenderTargetRenderer.

For more information see the FlatRedBall.SpriteManager.RemoveLayer and FlatRedBall.Camera.AddLayer pages.