Sgt. Conker We are "absolutely fine"

27Nov/097

Article : Multi-threading your XNA

5. Conclusions

So that's about it, for now. In this tutorial, I tried to explain and show how to make a multi-threaded game architecture in XNA. The focus of the tutorial was separating the updating and drawing code on parallel threads, and keeping data correctly synchronized between these two threads. We saw an example of using this architecture in practice, and we could see the performance we gained by multi-threading.

However, this is not the only way to use multi-threading. There are plenty other ways not covered in this tutorial. You can use it for an animated loading screens (which can be seen in the GameStateManagement sample on creators.xna.com), complex asynchronous A.I. computations, loading data during gameplay without a loading screen, etc. All these require different achitectures for the code, and come with their own pitfalls and sensible spots, but they are doable. The results vary from a little extra polish that makes your game feel right, to more intelligent enemies, or to that extra bit of performance we're all craving for.

6. Downloads

The code for the framework alone can be downloaded here: MultithreadingFramework.zip.

The code for the Balls example can be dowloaded here: MultithreadedBalls.zip.

7. References

About Sgt. Conker

The Sergeant!
Comments (7) Trackbacks (6)
  1. Hi Catalin, I originally went down a very similar research path as what you are describing in your threaded-rendering system.

    However I did some prototyping and came to the realization that the GPU is already running asynchronously, and only forces a CPU-side block if the previous frame hasnt finished when the next .Begin() is called. This result plus the added complexity of caching game-state led me to abandon this system.

    What we are planning to do on our engine is to use a seperate cpu thread to process vertex data (batch instancing), but that’s really no different than multithreading other cpu-side modules.

  2. Hi Jason.
    Yes, the GPU does indeed run asynchronously from the CPU. However, the speed of the GPU is rarely the main performance bottleneck. Most time, the problem is with the communication between the CPU and the GPU which happens at each DrawXXX() call. Having a high number of draw calls eats up lots of CPU time, and that is what I am trying to reduce in this article. So what I am threading is not actually the GPU-drawing, but the CPU invoking of draw calls (which happens at driver-level).
    In most multi-threading approaches, you either try to distribute the non-graphics CPU-work on multiple threads, or try to distribute the GPU-communication work done by the CPU.

    But yes, the approach is not what I’d recommend for a truly advanced system. It is good for learning purposes, and it is definitely a robust way to add threading to your game and obtain a good performance boost, but at the cost of extra memory needed for the two buffers.

    For a more complex threading system, there are some other ways to do it, as presented in some of the papers I linked to at the bottom of the article. Each method has it’s advantages, and you can’t always decide that one way is better then others. It usually depends on the structure of the rest of the engine.

  3. Nice one. It will help me a lot.

    Thanks,
    Timo

  4. yah, I think your system is a great intro to the very complex world of multithreading. Like I said, I originally went down a very similar path to what you are describing, so I do feel that there are benefits, but in my situation the drawbacks outweighed them.

  5. a simpler approach might be:
    a) each GameComponent maintains two DrawState objects
    b) Draw() method ONLY uses information in current DrawState object to draw
    c) Update() keeps only ONE version of “UpdateState”
    d) single point of control for flip flop using Game.CurrentDrawStateIndex = 0 or 1
    e) GameComponent.Draw() { CurrentState = DrawState[Game.CurrentDrawStateIndex]; }
    this is easy to design – anything that Draw() requires goes into DrawState

  6. When I try using Multiple Threads, the controls don’t seem to work, however they do work if I use a single thread (uncomment the line in the draw method and comment out the one in load). Any idea why this is?

  7. I should notice something: because of the way xna handles input, Keyboard input can be received only from the main thread, due to this you have to create your own input handler to fix this


Leave a comment


*