Sunday, March 3, 2013

Task Based Game Engines

It's been a few months since my last blog, because work has really picked up and I haven't had much time to work on my own engine. But, whenever I do get a chance, I poke around my engine a bit to see how crazy I can make it.

So far I managed to do the following:

1. Shader Reflection
2. Add webserver for debug controls through web page
3. Redo all the DX based tutorials using a sort of platform independent architecture - restrict all the platform dependent stuff to a real low level and make sure higher level is all the same)
4. Multhi-threading

Today I'm going to talk about the last point: Multi-threading.

I had zero experience in multi threading. Sure there was that course during my undergrads where we memorize about few multithreading concepts, but never had a chance to actually work on it. And now, with the advent of multi-core machines, making a game engine multithreaded is probably a good way to go because we need to make every cycle count, and perform as much computations as possible per frame to reach our goal: Creating a perfect world.

A recent discussion with my colleagues inspired to investigate more about Task-Based Architectures. After searching around the net, I came across this link:

http://software.intel.com/sites/default/files/m/d/4/1/d/8/Efficient_scaling_in_a_Task-Based_Game_Engine16-9.pdf

After reading this and watching the presentation, I realized that we didn't have to spend too much time thinking about how to order the threads for the best CPU utilization. This architecture made it possible to mostly utilize all the cores, no matter the amount of cores, to execute all of the updates and also the rendering. So I built a basic task assignment based system, and what I noticed is that the results are amazing.

Following is an easy way to implement this system:
1. Detect number of cores
2. Assign thread affinity of main thread to Core 0
3. Create N-1 threads (one thread for each core, except for Core 0) in suspended state
4. Have a task scheduler to assign tasks to a free thread
5. Once task is done,let the thread pick up next task from the task queue

On my laptop with 8 logical cores, it was pretty cool to see all the cores getting used (using Task Manager). Now, you don't really have to worry about changing code based on the number of cores. This architecture automatically takes care of that. Also if you're planning to try out deferred context rendering, this is also an awesome way to use it, as you can assign different tasks to create draw commands in parallel and then use the immediate context to execute the deferred contexts in order ! This is the plan for me. Watch out for more updates on this.

No comments: