Posts Tagged graphics

Threaded EndDraw in XNA (Crouching WaitOne, Hidden Lock)

After finishing up the materials for my Level Up 2009 entry, today I spent a little while trying out an idea I had recently:

One of the problems with using vertical sync in a video game is that it eats into the available CPU time for performing game updates. The way vsync is implemented in most graphics APIs, it causes your Present/EndDraw/SwapBuffers call to block until the card enters vertical blank and the frame is shown to the user. While this is ideal from a correctness perspective, it’s a tremendous waste since it means you can end up sitting there for up to 16 milliseconds, waiting for vertical blank. If your game spends lots of time doing both updating and drawing, all that time could be spent performing updates instead. Ouch.

Currently, my game spends about as much time drawing as it does updating. A significant portion of the time spent drawing (20-30%) is within the EndDraw function. Turning off vertical sync drops the amount of time spent in EndDraw considerably, but introduces tearing. So, as a potential solution, why not call EndDraw on a background thread? While the thread waits for vertical blank, I can begin performing the next frame’s Update, and in the event that I finish updating before the previous frame is visible, I simply wait for that previous EndDraw call before beginning to paint the next frame. In the optimal case, this means I can come much closer to the best possible framerate without introducing tearing, and in the worst case, the cost of rendering an individual frame is only *slightly* increased by the use of thread synchronization. The fact that I’m only doing EndDraw on another thread means that I don’t have to worry about protecting my game data with locks and other synchronization techniques, since the GraphicsDevice doesn’t use any of my game data when performing the EndDraw operation.

So, to test this out, I overrode my Game class’s BeginDraw and EndDraw methods. This turns out to be all we have to do to change the way drawing is performed, because the XNA Framework developers were kind enough to make both of these methods virtual.

        protected override bool BeginDraw () {
            _DrawCompleteEvent.WaitOne();
            _DrawCompleteEvent.Reset();
            return base.BeginDraw();
        }

        protected override void EndDraw () {
            _DrawRequiredEvent.Set();
        }

Of course, at this point, the two events used here are never set, so this code won’t work. Thus, we add a background thread to perform our painting:

        AutoResetEvent _DrawRequiredEvent = new AutoResetEvent(false);
        ManualResetEvent _DrawCompleteEvent = new ManualResetEvent(true);

        public Game () {
            ...

            _DrawThread = new Thread(DrawThreadFunc);
            _DrawThread.IsBackground = true;
            _DrawThread.Start();
        }

        protected void DrawThreadFunc () {
            while (true) {
                _DrawRequiredEvent.WaitOne();
                base.EndDraw();
                _DrawCompleteEvent.Set();
            }
        }

Fairly simple thread programming here: We create a thread, and set IsBackground to true so that it will stop as soon as the main thread exits. The thread spends all of its time waiting for a ‘required draw’ signal, and then performs an EndDraw call. Once the call is complete, it sets another signal to inform the Game class that the previous draw has finished and it’s safe to perform a BeginDraw call (this lets us make sure that we never use the GraphicsDevice on the main thread while the background thread is performing an EndDraw).

Once this is all done, I start up my game, and… the framerate isn’t any different. Huh? What’s more, my frame profiler indicates that Update is now taking ten times as long as it used to, while Draw isn’t any faster. Huh???

In situations like this, it’s always good to consult a profiler to see if you’re missing something important:

profile_01

So, we can see that the DrawThread is definitely doing its job – it calls EndDraw, then waits for a signal asking it to draw again. Both are taking about as much time as we’d expect. But why is Update taking so long…?

profile_02

… oh. Oops.

So it turns out that I was using GraphicsDevice.Viewport.Width and GraphicsDevice.Viewport.Height in my camera code. Accessing the Viewport property caused the XNA framework to call into Direct3D to retrieve the viewport, which acquired the exact same lock being used by EndDraw, causing my main thread to stall until the draw completed. WHOOPS.

This is especially embarassing since the viewport size never changes anyway, so I could have just stored the width/height into constants. After doing just that and starting the game again, the profile looks more like you’d expect:

profile_03

What’s more, this is actually an improvement: With vertical sync enabled, this results in a significant reduction in the amount of time spent inside the BeginDraw/Draw/EndDraw functions on the main thread, which means there’s more time left to perform Updates. This means that I can maintain a solid, smooth 60fps easier on dual-core/hyperthreaded machines.

Even with vertical sync disabled, this is still an improvement, though not as significant – apparently other things are happening inside EndDraw (not a big surprise), so by shifting that work off onto a second thread, I’m still gaining some time to spend performing the next update. When I disable the built in framerate balancer, this brings my framerate from ~350fps up to ~380fps. Not bad for a couple dozen lines of code!

Of course, it’s worth pointing out that the XNA Framework documentation doesn’t make any promises here, so it’s possible that this technique is unsafe. When it comes to concurrency, it’s very easy to do the wrong thing and get away with it – as you might have noticed here, I was doing something utterly stupid and unsafe in my Update function, and I got away with it because the DirectX developers had the foresight to put a lock in the right place. If they hadn’t, my game might have corrupted state from accessing the GraphicsDevice on two threads, and crashed intermittently.

Regardless, this is a handy technique – once I’ve had the chance to do lots of testing on various PC configurations (and the XBox 360), I’ll probably be using it in my game when I ship.

Tags: , , , , , ,

Water

Among the various things I worked on this week, I spent a good portion of time implementing a basic fluid system in the game engine. The fluid system lets me create volumes of moving fluid that alter the player’s physics and can flow down off ledges and interact with objects, so that levels like the aqueducts look and feel more convincing.

The two major pieces of the fluid system are physics and rendering. The physics system is arguably more important, but ended up mostly being a matter of fine-tuning. Here’s how it works:
Previously, every frame I did a sweep of the area below onscreen entities to locate the nearest surface to stand on, and used that to perform some motion and collision detection calculations so that the player can properly move up/down slopes, stand on moving objects, and drop when standing over a gap.

To implement the water system, I extended the standing sweep code to also locate the nearest volume of fluid that intersects the entity, and store it. What this allows me to do is detect whether or not the player character is currently inside a fluid, regardless of whether or not he’s standing on a surface at the time (so it even works while jumping/falling).

Once I had this functioning, I added the ability to attach ‘Material’ information to any piece of geometry in the game, including fluids. These two pieces of functionality combined allow me to control the physical attributes of a surface, and then further alter those attributes when the player is standing inside water or other fluids. This not only allows me to implement slippery surfaces like ice, but cause the player to move more slowly and have different control characteristics when in the water.
In the future, this should also allow me to alter the characteristics of surfaces in response to gameplay events – enemies that spray sticky goo on the ground, spider webs that slow you down, or a potion that freezes water, turning it into slippery ice you can stand on.

After a bit of fine-tuning, I came up with some physics parameters for the basic material types that I’m happy with, that make the differences between various materials obvious without breaking gameplay mechanics. The jumping mechanics were a particularly tough detail – even minor changes to the acceleration and speed characteristics of the player render some of my jumping puzzle prototypes completely impossible to solve, so I had to carefully test against those puzzle prototypes each time I adjusted the physics values for a given material. In the final game, I’m going to have to address this by only using a specific set of materials in each level, so that it’s not necessary to retest the entire game after physics changes.

Of course, water isn’t particularly interesting if you can’t see it, so the other thing I did was build a fairly simple bit of rendering that allows fluids to flow across surfaces and down off ledges.

Read the rest of this entry »

Tags: , , , ,

Fixed XBox 360 Controller Shoulder Button Images

If you’re using the stock XBox 360 controller button images provided by Microsoft, you may have noticed that they mislabelled the two shoulder buttons. I spent a few minutes fixing the labels in Paint.NET, and I’ve uploaded the corrected images here for others to use:

I’ve also provided both PNGs and the Paint.NET source images in a ZIP archive.

Please note that the original images were made available under the Microsoft Permissive License.

You may also want to consider using alternate button graphics, like those available in Jeff Jenkins’ Button Pack 1 and Button Pack 2.

Tags: ,

luminance is Digg proof thanks to caching by WP Super Cache