Click here to Skip to main content
15,499,046 members
Articles / Desktop Programming / Windows Forms
Posted 14 Jul 2005


47 bookmarked

Simple Managed DirectX Render Loop

Rate me:
Please Sign up or sign in to vote.
4.79/5 (23 votes)
14 Jul 20055 min read
A simple framework for implementing the best possible Managed DirectX render loop for games or simulations written in Microsoft .NET.


This is the framework of a Managed DirectX render loop. These loops are used to cause a game or simulation to render graphics and update state with the highest possible performance while still being responsive to user input and system events, without bogging down the entire system. This article does not explain how to use DirectX or Direct3D, only how to best arrange the main engine loop of your game or simulation for the best performance and responsiveness.


This implementation comes directly from Tom Miller's blog entry on May 05, 2005. Tom Miller is a well known author and the lead developer on the Managed DirectX team at Microsoft. After many iterations, he has discovered that this pattern will provide the best possible performance that a .NET managed application can attain without resorting to WinAPI tricks. A more complete framework is included in the June '05 version of the DirectX SDK, but I'm going to show you the simplest possible implementation and explain why/how it works and why it is the best. Using C++ and avoiding the .NET WinForms base classes can be even faster, but there are many published techniques already available. The purpose here is to create a 100% managed solution using only .NET code.

Using the code

I'm going to analyze the whole class by looking at snippets at a time. The downloadable source includes a complete MainForm class.

When the application starts up, while still in the Main method, we go ahead and bind to an odd event: Application.Idle.

public static void Main(){
    MainForm myForm = new MainForm();
    Application.Idle += new EventHandler(myForm.Application_Idle);

If you are unfamiliar with Windows messages, they are simple notifications of events like key-presses and mouse movements, but can also cover things like system shutdown, minimizing your application, etc. Almost everything that happens within your computer ends up as a Windows message.

The Application.Idle event is fired whenever our application is done processing all incoming Windows-generated messages. Our goal here is to allow our application to process as much as possible as quickly as possible, but we don't want to stop the flow of incoming Windows messages.

Here is our Application_Idle event handler:

protected void Application_Idle(object sender, EventArgs e){
        // TODO: Main game loop goes here.

public bool AppStillIdle{
      PeekMsg msg;
      return !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);

The AppStillIdle property makes use of a simple Win32 API function (PeekMessage) which checks to see if there are any pending Windows messages that our application needs to process. The reason we go into the while loop is that Application.Idle only gets fired once when the application is finishing up processing all possible Windows message and the queue of pending messages is empty. So we want to continue looping until Windows happens to give us another message to process (when PeekMessage returns true). Then we'll drop out of the loop and leave Application_Idle. The normal .NET WinForms Windows message handler will pick up the pending messages that we saw when PeekMessage returned true.

According to the Win32 API documentation, PeekMessage passes out a structure different from the one that .NET defines in System.Windows.Forms.Message. We have to redefine our own version of the Message class called PeekMsg:

public struct PeekMsg {
   public IntPtr hWnd;
   public Message msg;
   public IntPtr wParam;
   public IntPtr lParam;
   public uint time;
   public System.Drawing.Point p;

The StructLayout attribute is required when using .NET structs to pass into Win32 or COM.

Here's the native method definition for PeekMessage:

[DllImport("User32.dll", CharSet=CharSet.Auto)]
private static extern bool PeekMessage(out PeekMsg msg, IntPtr hWnd, 
        uint messageFilterMin, uint messageFilterMax, uint flags);

Making it Faster

There are a few enhancements we can make to this application. Some of them aren't hard to do, but the reasons for them aren't very clear. The first, is setting the ControlStyle of our form. This has to be done in the form constructor:

this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

These lines cause the form to not use the standard .NET and Windows form-drawing code, as well as bypass extra drawing-related messages and events. Obviously if we are going to be using DirectX to draw our game or simulation, we don't need Windows and GDI+ to be doing a whole bunch for us that will never be visible. This is the case for Full-Screen as well as Windowed games and simulations.

Another thing we can do is to modify our native method definition for PeekMessage:

[DllImport("User32.dll", CharSet=CharSet.Auto)]
private static extern bool PeekMessage(out PeekMsg msg, IntPtr hWnd, 
         uint messageFilterMin, uint messageFilterMax, uint flags);

By adding the SuppressUnmanagedCodeSecurity attribute to the call, .NET will skip the security-related checks that it would make before allowing your application to make a call out to a native Windows method. This is extremely dangerous and should not be done without carefully considering the security ramifications of making the call. In this case, making the method declaration private is good enough, especially since the call we are making is merely going to tell us if there is a message waiting for us or not. Unfortunately, the method in question passes back the next Windows message if there is one. Malicious code could use this to intercept keystrokes, watch network traffic, or interpret and redirect mouse clicks. Be sure not to leave this method call somewhere where malicious code can access it by keeping it private.

Points of Interest

Did you notice that we did nothing at all with the Control.Paint event? Well, the reason is that the event is not needed. Since the UserPaint style is set, .NET's control painting code gets disabled. Windows will still send the WM_PAINT message, but as soon as your application gets done doing ... nothing, then Application_Idle will fire and you'll be refreshing your DirectX surface anyways. If you really wanted do, you could make an additional call to render your scene from within the Control.Paint event handler, but I do not know what this will do to performance or responsiveness.


  • Released on July 14, 2005.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

GeneralMy vote of 5 Pin
Ivaylo Slavov16-Oct-12 9:14
MemberIvaylo Slavov16-Oct-12 9:14 
GeneralThis example in c++ Pin
aerocount8-Mar-10 13:15
Memberaerocount8-Mar-10 13:15 
GeneralApplication.Run Pin
Dmitri Nеstеruk15-Nov-07 2:58
MemberDmitri Nеstеruk15-Nov-07 2:58 
Questionhoe to create a parser filter. Pin
amiya das27-Sep-07 1:42
Memberamiya das27-Sep-07 1:42 
can any one tell how to create a parser filter in direct show

what r the steps needed to create a parser filter which can read a pcm file.

amiya kumar das
QuestionNo longer works properly after WindowsXP update? Pin
seefer25-Nov-06 13:02
Memberseefer25-Nov-06 13:02 
AnswerRe: No longer works properly after WindowsXP update? Pin
seefer26-Nov-06 8:33
Memberseefer26-Nov-06 8:33 
GeneralNot sure why this worked Pin
CAyuso21-Jul-06 9:10
MemberCAyuso21-Jul-06 9:10 
GeneralJune '05 SDK update comment Pin
Proudest19-Mar-06 15:42
MemberProudest19-Mar-06 15:42 
GeneralRe: June '05 SDK update comment Pin
Eric Falsken28-Mar-06 12:00
MemberEric Falsken28-Mar-06 12:00 
QuestionVB.NET conversion? Pin
Kal_Torak2-Feb-06 5:15
MemberKal_Torak2-Feb-06 5:15 
Generalbut watch out for those darn menu controls... Pin
Ruud van Eeghem6-Jan-06 4:58
MemberRuud van Eeghem6-Jan-06 4:58 
Question100% managed??? Pin
Pop Catalin12-Aug-05 3:24
MemberPop Catalin12-Aug-05 3:24 
AnswerRe: 100% managed??? Pin
Eric Falsken12-Aug-05 9:47
MemberEric Falsken12-Aug-05 9:47 
AnswerRe: 100% managed??? Pin
The_Mega_ZZTer22-Mar-09 9:10
MemberThe_Mega_ZZTer22-Mar-09 9:10 
GeneralExcellent Pin
Ryan Beesley2-Aug-05 3:14
MemberRyan Beesley2-Aug-05 3:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.