Mathias Dierickx

Engine programmer


Multithreaded Game Engine

This project shows off a 2D multithreaded game engine, designed from scratch and implemented using C++ and SDL.

About the project

The whole project was completed from start of research to completed implementation in seven weeks time. The first three weeks consisted of pure research on multithreaded game engines, while the last 4 weeks were more about testing certain systems and creating the actual game engine from scratch. My other 2D engine was used as reference.
The engine features an entity component system, controller support, keyboard and mouse support, asynchronous loading and multithreading. The core of the multithreading lies in the Task manager, the main thread and the worker threads.

A more in depth explanation on the project can be read in my paper.

Code snippets

This code snippet shows how the task manager works. Important to note is the component map used in nearly all functions in the task manager. This is a map that holds a vector of components per component type. This map is used to create all tasks, and to execute these tasks. With this design, the task manager becomes a bottleneck when many threads want to access it at the same time, this will be changed in future version but could not be done in time for the deadline. The paper lays out several methods that could be used to get rid of this bottleneck, but they are untested.

The next code snippet shows the implementation of the thread pool. This pool holds a number of worker threads (depending on the number of physical cores in the system) that constantly pull tasks from the task manager and execute them using the current scene's component map.

The following code snippet shows an implementation of a quad tree, that can be used in a multithreaded environment. A tradeoff has been made to accommodate multiple threads inserting new collider components without blocking by having the tree always be at max size. This means we don't have to lock at runtime to split a node but gives us a performance hit if the objects with a collider are not distributed along the scene well. To compensate for this, each scene can choose how deep the tree goes, depending on how spread out the objects will be. Even though this seems like a big deal, multithreading should only be used in scenarios where we can split up the work anyways.