XBox Live

Given my job in the DirectX team, it’s probably a safe bet that people already realize i would be what is called a ‘Gamer’.  I spend entirely too much money on video games, and depending on the games that are out there, entirely too much time playing them.  However, right now my ‘gaming’ time is being spent almost exclusively on two games.

Obviously, i’ve had XBox Live since it was first launched in November of 2002, but honestly for the almost the entire first year it was out, there was never anything i really wanted to play on it.  Sure, i played some Mech Assault, and was into Unreal Championship for a while, but nothing i would consider ‘great’.  That’s been changing recently though.

For example, Project Gotham Racing 2.  This is probably the best XBox Live game available today.  Not only does it have a great multiplayer experience online, even the single player missions are all ‘live-enabled’.  Your best scores are stored on xbox live, and you can compare yourself to other players in all of the single player missions.  Better yet, you can actually download the ‘ghost’ of other players who have played the missions to see how they’ve acheived these outrageous high scores.  And since you’re always signed into live while you’re playing (even in single player mode), any of your friends who are also online can invite you to play a multiplayer game.  Even playing in the multiplayer modes lets you get kudos tokens you can use to help yourself during the single player mode.  This game should be the model for all future live games.  It is the entire package.  The only downside (if you could call it that), is that it doesn’t support XSN, which i can understand considering it isn’t a ‘sport’.

Speaking of XSN though, the other game i’m really into nowadays is Links 2004.  Joining tournaments online, and competing, and watching my stats is addictive.  Personally, i’ve tried Tiger Woods game, and it just doesn’t match up.  Sure, you have a wider array of choices when creating your character, but the golf isn’t as realistic, you can’t play with teams, and you can’t play with more than two players.  Playing in tournaments is the absolute best.

This doesn’t even consider the other great XBox Live games out nowadays..  Rainbow Six 3, Counterstrike, Crimson Skies, Midnight Club 2, etc.. After being out a year, i’m now really starting to be impressed..

The joy of house buying..

We bought our first house almost five years ago, so i’ve had the pleasure of completely ignoring the work required to make that purchase for so long, i had essentially forgot about it.

Don’t get me wrong, buying a new house is an exciting time, but boy can it be a difficult time as well. We’re actually having a new house built and you wouldn’t believe the sheer number of options and features we have to pick. It really is somewhat overwhelming, stressful, fun, and exciting all at the same time. I don’t actually remember if we had to sign this much paperwork before, but it feels like we didn’t.

Then, after all that, we’ll still have to wait six months before we can move in. However, we will be able to go ‘visit’ the house on weekends during construction. I’m looking forward to standing in the middle of a partially built house, taking pictures in a few months. Given the reputation for rain here, it’s weird to consider the house will be rained in during construction.

On top of that, it isn’t even considering the fun we’ll be having when we get to sell our current house.

The Render Loop Revisited

Wow. I wouldn’t have thought that my blog on the render loop and doevents would spark as much discussion as it did. Invariably everyone wanted to know what i thought the ‘best’ way to do this was.

Actually, the answer is (naturally) ‘It Depends’. It wasn’t actually an oversight on my part to leave out a recommendation at the end of the post, it was done intentionally. I had hoped to spark peoples interest in learning the cost of the methods they were calling, and pointing out a common scenario where the method had side effects that many people weren’t aware of.

However, since I’ve been asked quite a few times on alternatives, I feel obligated to provide some. =)

Here are some alternatives, in no particular order.

  • Set your form to have all drawing occur in WmPaint, and do your rendering there. Before the end of the OnPaint method, make sure you do a this.Invalidate(); This will cause the OnPaint method to be fired again immediately.
  • P/Invoke into the Win32 API and call PeekMessage/TranslateMessage/DispatchMessage. (Doevents actually does something similar, but you can do this without the extra allocations).
  • Write your own forms class that is a small wrapper around CreateWindowEx, and give yourself complete control over the message loop.
  • Decide that the DoEvents method works fine for you and stick with it.

Each of these obviously have benefits and disadvantages over the others. Pick the one that best suits your needs.

The downside of using the events

Managed DirectX has plenty of events that it captures, and fires in a normal application. Every single managed graphics object will hook certain events on the device to ensure it can behave correctly.

For example, when a device is reset (due to a window resize, or a switch to or from full screen), any object stored in the default memory pool will need to be disposed. Many objects will also have something to do after the device has been reset. In the default case, each object that will need to be disposed before a reset will hook the DeviceLost event, while the items who also have post reset work will hook the DeviceReset event.

This doesn’t even consider the fact that each object hooks the device’s dispose event. In short, if events are being hooked, every d3d object will have a hook on the device. So why is this a problem?

Take this seemingly ‘safe’ code an example (assume swapChain is a valid Swap Chain, and device is a valid Direct3D device):

device.SetRenderTarget(0, swapChain.GetBackBuffer(0, BackBufferType.Mono));
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 500);

Looks simple enough, just using the back buffer of the swap chain as the render target. However, if the events are being hooked, there are a lot more things going on here. The GetBackBuffer call will return a new surface representing the current back buffer of the swap chain. This object will hook the device lost and disposing events, which will be at least 3 allocations (the actual surface, along with the 2 event handlers).

Worst than that though, this object (which is only used for a brief period of time) will never be collected as long as the device is still alive since it has hooked events on the device, so this memory (and these objects) will never be reclaimed. They will eventually get promoted to generation 2, and memory usage on your application will just steadily rise. Imagine a game running at 60 frames per second, each frame calling this code..

To think, we haven’t hit the end of the problems yet either! Imagine the game running @ 60 frames per second that has been running for 2 minutes. Now, the devices dispose event has 7200 objects hooked, and the dispose method has just been caused since the application is shutting down. It takes a significant amount of time to propogate this event, and it will appear your application has locked up (when in reality it is simply notifying every object the device is now gone).

A much more efficient way of writing this code would be something like:

using (Surface buffer = swapChain.GetBackBuffer(0, BackBufferType.Mono))
{
device.SetRenderTarget(0, buffer);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 500);
}
In this scenario you get rid of the objects immediately. Yet you still have the underlying ‘problem’ of the event hooking.

An even better solution would be to turn off the event hooking within d3d completely. There is a static property on the device you can use to do this, such as:

Device.IsUsingEventHandlers = false;

If you do this before you create your device, this will completely turn off the internal event handling for d3d. Beware of doing this though, since you will need to manage the object lifetimes yourself.

The default behavior of device hooks is extremely convient, but if you want top performance, you may want to avoid the default event code. At the very least understand when and how the events are hooked and structure your code to be as fast as possible (such as the 2nd code snippet over the first).

Matrix: Revolutions..

So we saw Matrix Revolutions yesterday, and if i had to sum it up in one word, it would probably be ‘eh’.

I don’t want to give away any plot lines or anything, but the ending really dissapointed me. It was somewhat slow starting, but the middle was quite entertaining. The battle when the machines first break through the dock to zion was awesome.

I also don’t think they did a great job explaining about Agent Smith. Why were the machines afraid of him? For the ‘final’ movie, i was hoping for it to answer a lot more questions than it did.

Don’t get me wrong, i enjoyed the movie thoroughly, but it wasn’t my favorite of the matrix trilogy, and i was quite disappointed in the ending.

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.

Managed DirectX Graphics And Game Programming Kickstart

In a bit of a shameless plug, i’d like to point out that my book on Managed DirectX is available now.

As i’m sure everyone is already aware, the documentation for the Managed DirectX API left a little to be desired. My book covers every component of the Managed DirectX API, including DirectInput, DirectSound, DirectPlay, DirectDraw, but focuses the majority of the content on Direct3D.

While the other components are discussed briefly, the Direct3D API is discussed in much detail. The book takes you step by step from drawing a simple triangle on the screen all the way through character animation, and even the high level shader language.

There is no other greater source of information on Managed DirectX. With that, i’ll end my shameless plug. =)