Rendering to intermediate textures is really slow, causes big stutter

Hi,

I have a function in my program that renders a whole bunch of text to the screen as once. In order to cut down on the performance hit from calling a bunch of spritebatch.drawStrings each frame, I created a workaround by rendering all my text onto a RenderTarget2D in a patchwork fashion, which is then copied into a 2D array of Texture2D. Then instead of drawing several hundred strings to the screen, I only need to draw, say, four sprites, using new textures from the array, pieced together into the full “screen” of text.

This works pretty great when the textures have already been generated (no persistent performance hit). However, it’s a pretty significant performance hit whenever the contents of the textures need to be updated, causing a big ugly stutter where everything will freeze while it’s rendering to my patchwork textures. This is partially from the spritebatch.drawString calls, partially from then copying the texture data from the RenderTarget2D over into my Texture2D array elements. Either way it’s not great.

My first attempt to fix this was to try to move some of the operation to asynchronous execution, so the rest of the game wouldn’t lock up while it rendered. But that was essentially a nonstarter, because the texture operations can only run on the UI thread (so synchronously with the rest of my update/draw calls). I have also tried shifting around the (internal) render operation variously within the update and draw methods, with little difference.

Not sure if I’m missing something obvious that is causing this to be such a pain to fix, or that would bypass the performance hit entirely. Does anyone have any good ideas of workarounds or alternative approaches?

Edit: Here is the current operation in question

I am copying the texture data out of the RenderTarget2D because previously, trying to create a new RenderTarget each iteration was causing more performance issues, but I am open to alternative approaches to this.

instead of creating a texture for every single string, create 1 texture for the specific font settings.
you can create them on runtime or use an allready created bitmapfont that you load in.
(i use AngelCodes Bitmapfont generator to create bitmap fonts.)

after that you just render a small frame from the texture to the scene (for each letter). can be batched to 1 single call for all the strings you want to display on screen.

So… You’re saying to essentially disregard DrawString/spriteFonts entirely, and render individual sprites for each letter? I’m not sure I see how that’d improve performance, unless spritebatch.drawstring is far more CPU intensive than I’d realized. Regardless, I’m not sure it’s feasible for me because I already have a complicated set of systems built around drawing spritefonts. It works fine in most cases (just slightly laggy when drawing hundreds of them at once).

I’m currently considering going back on the pre-rendered texture sheet thing entirely, and adding some new culling so that the original, stringwise render per-frame is less of an issue. That said this feels like something that there should be a solution for (how to perform one set of render operations without holding up the game’s execution cycle or leaving the UI thread), and a solution to that would be useful in a lot of other situations as well, so advice in that regard would still be appreciated.

To avoid hickups dont

  • create new textures or other resources
  • call GetData, because that’s download data from the GPU to the CPU
  • call SetData, because that’s uploading data from the CPU to the GPU

There’s no need to copy data from render targets to textures constantly. You can just use the rendertargets directly, just like you would use a texture. So instead of an array of textures, just have an array of rendertargets.
Don’t create new render targets constantly, create as many as you need in the beginning, and then reuse them.

2 Likes

That’s very sensible. I’ll need to do some dynamic shuffling of how many rendertargets are used to support objects of arbitrary size, but I’m sure I can come up with some good ways to address that. Thanks for the advice

If the text is static and unchanging in other words you aren’t printing out variables what ive done in the past was to simply duplicate draw string get the vertice array and draw it with DrawUserPrimitives as a buffer.

Can you elaborate on that? How do you get the vertex array for a string? Wasn’t aware that was a functionality.

Okay! Problem essentially solved. I removed all the redundancies with texture creation, and also realized that I was creating a new text object in my entity system every time I updated this text as well, which wasn’t helping things. Works a lot better now, only slight, almost unnoticeable hitch when the text is first opened and plain sailing from there. Am probably still going to add those culling systems for other circumstances, though.

Thanks all!