The Render Loop

If you’ve seen the SDK samples for C# or VB.NET, and have looked much at the graphics samples you may have noticed the render loop, which looks something like this:

while(Created)
{
FullRender();
Application.DoEvents();
}

Obviously the point of this method is to loop so long as the window is created (which normally implies the application is still running). It looks harmless enough, and is relatively easy to understand, which is why we left it in the SDK, but in reality, this isn’t the best way you would want to drive your render loop.

Aside from the ‘ugliness’ factor of the loop, the real problem here is the Application.DoEvents method. It’s surprising that many people don’t actually realize what’s going on in this method, and i’d bet you would find even more people that were shocked that there’s actually an allocation happening in this method.

Let’s look at this simple application:

public class Form1 : System.Windows.Forms.Form
{
public Form1()
{
this.Show();
for (int i = 0; i < 50000; i++)
{
Application.DoEvents();
//System.Threading.Thread.Sleep(0);
}

this.Close();
}
static void Main()
{
try{Application.Run(new Form1());}
catch { }
}
}

All this does is show a form, call DoEvents 50,000 times, and exit. Nothing fancy at all. Running this through the CLR Profiler on my machine shows that during the lifetime of this application 6,207,082 bytes of data were allocated. Comment out the DoEvents and uncomment the Sleep call, and the application only allocates 406,822 bytes on my machine. Doing the math, that averages out to ~116 bytes allocated per call to DoEvents.

If you’re running a high frequency render loop, running at say, 1000 frames per second, that’s 100k of data you’re allocating per second. This will cause quicker gen0 collections, which can needlessly promote your own short lived objects to gen1, or worse.

Morale of the story. Just because it looks easy, doesn’t mean it’s the right idea.

Leave a Reply

Your email address will not be published. Required fields are marked *