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.
Comments
Anonymous
November 23, 2003
Hi, I just wanted to know what if the best pratice for the main render loop ? Is it better to call the peekmessage win32 function directly into the main render loop ?Anonymous
February 05, 2004
The comment has been removedAnonymous
February 13, 2004
Maybe use the paint events to render, or setup a timer?Anonymous
March 23, 2004
Hi Tom,
This is very true in a background thread, but what if you have a single-threaded application that you want to keep responsive while you're inside your loop... with Sleep() calls, the app will just appear frozen.
I'm not clear why DoEvents would allocate memory... is it really DoEvents allocating the memory, or is it the code that gets an opportunity to run due to the call to DoEvents (ie: the message pump gets processed) that is doing this?
-- MikeAnonymous
March 30, 2004
Hey Tom, it would have been helpful if you mentioned this in your book "Managed DirectX 9 Graphics and Game Programming" as it sent up major red flags in my C++/MFC trained mind! Invalidating in an OnPaint runs counter to everything I've learned! :-)
I have heard people comment on using the OnIdle for rendering as opposed to DoEvents or OnPaint. Any opinion on that?Anonymous
July 13, 2004
I just noticed that the Aplication.DoEvents method was alocating memory. It seems strange that this would happen because in the Microsoft DirectX tutorials, this is what they use. I read somewhere that this may evetually get cleaned up automatically by .NET when resources get low, but I haven't tested it as I have 1gig ram.
I've tried running a render loop with the Application.Idle event, but that's no good because it is only fired once just before the app is about to go into the idle state, then it just sits there while idle.
I may try using a timer to call the loop or see if I can work out how to do a custom event that fires continuously whenever the application is in the idle state, otherwise I'll just stick with Application.DoEvents and blame Microsoft for the extraneous memory use.Anonymous
January 18, 2009
PingBack from http://www.keyongtech.com/2312059-peekmessage-and-filtered-nested-messageAnonymous
January 21, 2009
PingBack from http://www.keyongtech.com/720329-label-changes-not-being-reflectedAnonymous
May 07, 2009
PingBack from http://code.dawnofthegeeks.com/2009/05/07/c-lesson-1-the-main-loop/Anonymous
June 08, 2009
PingBack from http://insomniacuresite.info/story.php?id=10280Anonymous
June 11, 2009
PingBack from http://bobobobo.wordpress.com/2009/06/11/taking-advantage-of-controlstyles-allpaintinginwmpaint-controlstyles-userpaint-controlstyles-optimizeddoublebuffer-controlstyles-opaque/Anonymous
June 11, 2009
PingBack from http://bobobobo.wordpress.com/2009/06/12/game-loop-in-c/