Home

Physics !

March 27, 2013

After several weeks of coding and a travel to Oslo (\o/), I was able to make a lot of progress in Kadma, and AirMess.

I implemented BEPU Physics into Kadma, the multi-threaded way. There are a lot of threads running in Kadma and restarting an Engline from scratch gave me the opportunity to try something I was never able to do in my XNA based Engine.

Physic

There are 3 principal threads running in a game powered by Kadma:

  • The Game Thread, running things like Scene update, Game logic, and pushing drawing orders to the composer
  • The Composer Thread, reading frame commands from a work queue (populated by the Game Thread) and pushing them to DirectX via the DirectX 11 Api. I wanted to use DirectX 11’s multithreaded context here but I had some strange bugs with either SharpDX or my CG driver. So here I just have a plain DirectX 11 Device that eats orders coming in.
  • The Host Thread who is basically running the message pump for the Win32 event loop. I didn’t want to tie this thread to the Game Thread as Windows events are not even required to play it. For the input, I’m using DirectInput. The doc says it is deprecated but it’s quite simple and enough for now.

The beauty with using a deferred way of drawing objects here is that, if the composer is running late and the Game Thread (running at 60 fps) has pushed more that one frame since the last rendering process, the Composer can just skip frames up to the last one an process this one, trying to keep up with the Game. It shouldn’t skip frames, but if this happens the engine is still in control.

Also, instead of having 1/60 s for both Game Logic, animations, rendering and so on, I have 1/60 s for Game Logic, and 1/60 s for the rendering. This is 100% more time ! (at least, in theory). On my current rig I have quite poor CG but a fast CPU so my CG is the real bottleneck.

With that, I have additional worker threads (depending on the number of CPU cores) who are running various things, mainly animations because animations are not required to update the game and can be safely executed while the scene is being rendered until the next frame starts.

What I wanted to was to put BEPU into one (or several) of these working threads and in fact, it was very easy. With BEPU, multi-threading is available out of the box and to have it your way you just have to implement an interface to dispatch physics event on custom worker threads.

...

namespace Kadma.Engine.Game.Physics
{
    /// <summary>
    /// Thread manager bridging BEPU threads to
    /// Kadma's workers
    /// </summary>
    internal class PhysicsThreadManager : GameObject, IThreadManager
    {
		...

        #region IThreadManager Members

        public int ThreadCount
        {
            get { return currentThreadManager.PoolSize; }
        }

        public void AddThread()
        {
            // Ignored, we rely on the host
        }

        public void RemoveThread()
        {
            // Ignored, we rely on the host
        }

        /// <summary>
        /// BEPU Will call use in WaitForTaskCompletion to wait for
        /// everything to complete
        /// So each time we are queuing our things in this list
        /// </summary>
        private List<TaskContext> runningTasks = new List<TaskContext>();

        // Sync object used to prevent multi access to the runningTasks
        private object sync = new object();

        public void AddThread(Action<object> initialization, object initializationInformation)
        {
            if (initialization != null)
                throw new NotSupportedException("AddThread with a non null initialization routine is not supported");

            // Ignored, we rely on the host
        }

        public void EnqueueTask(Action<object> taskBody, object taskInformation)
        {
            if (taskBody == null)
                throw new ArgumentNullException("taskBody");

            lock (sync)
            {
                var taskContext = currentThreadManager.NewTaskContext();
                runningTasks.Add(taskContext);

                currentThreadManager.AddTask(() => taskBody(taskInformation), null, taskContext);
            }
        }

        public void ForLoop(int startIndex, int endIndex, Action<int> loopBody)
        {
            if (loopBody == null)
                throw new ArgumentNullException("loopBody");

            if (startIndex > endIndex)
            {
                // Well ...
                ForLoop(endIndex, startIndex, loopBody);
            }

            // Create our buckets of work
            var totalCount = (endIndex - startIndex);

            if (totalCount < ThreadCount)
            {
                // One thread, one iteration
                for (int i = 0; i < totalCount; i++)
                {
                    EnqueueTask((id) => loopBody((int)id), startIndex+i);
                }
            }
            else
            {
                var partSize = totalCount / ThreadCount;

                for (int i = 0; i < ThreadCount; i++)
                {
                    var bucketSize = i == ThreadCount - 1
                        ? (totalCount - partSize * i)
                        : partSize;

                    var bucketStartIndex = startIndex + partSize * i;

                    ForLoopIteration(bucketStartIndex, bucketStartIndex + bucketSize - 1, loopBody);
                }
            }

            // BEPU expects that we complete the foor loop before going out from there
            WaitForTaskCompletion();
        }

        ...
    }
}

And this is it. With this I have my physical world and now I can start to build the real game. The Engine is not perfect but as I said, I’m building a Game, not a Game Engine 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: