Engine Core Design - Part 2

Aug 7, 2019 • openjge-dev

It feels like a lot of time has passed since the last time I wrote one of these posts, but I’ve got some good news this time, which is that I’ve finally finished the Core module. At least for the time being, lol. As of now, everything seems to fit together quite nicely, so I’m hoping that there isn’t anything I’ve forgotten that’ll screw things up later down the line. Once I started coding, I actually ended up deviating a little bit from the plan I briefly talked about in the previous blog post. In practice, what I needed to do turned out to be a bit different than what I had planned out in my head. The biggest of these changes was probably made to the multithreading implementation. Originally, I was planning on just containing all of it within the ModuleCSM, but this turned out to be problematic because it made splitting tasks up amongst each executor in a thread-safe manner a bit of a challenge. It also meant that the ModuleCSM would be responsible for multithreading Event tasks, which didn’t make much sense. Why should the ModuleCSM need to know about Events if its purpose is to manage States? This led me to make the decision of creating my own ThreadPool class and then defining a custom thread class to be created by the pool. The ThreadPool would be able to do things such as monitor the number of currently active threads, allocate and reserve threads, and bundle Component updates and Events into Runnables (which I refer to as tasks) to be distributed amongst all threads. Each thread could then receive these tasks in a queue and run them one by one. And once run, the thread would be able to notify the ThreadPool of the task’s completion. A custom implementation allowed all of this to be done without the use of locks or synchronization. All ThreadPool functionality would then be driven by the EngineLoop, which would pull data from the EventQueue and ModuleCSM, and supply that to the ThreadPool.

In terms of the actual threading concepts used, much of the concurrency model remains the same. I’m still going with the hybrid data/task parallelism design, but with a few modifications when it comes to the application of these threading types. Here’s an updated version of the data-parallel threading approach taken for Component updates:

Whoops - no image :(

I also made up a little flowchart describing the task-parallel threading for Events:

Whoops - no image :(

I also decided to put Event handling at the start of the input and render phases. Why? Well, I figured that the Component updates processed in the update phase would probably be the most computationally expensive (you know, calculating stuff like physics and AI), so being able to dedicate all available threads to that phase made sense. The input and render phases, which would most likely take less computation, then split the number of available threads up into two groups: those for Event handling and those for Component updates. So while the Event handling tasks are being processed by the first group of threads, the EngineLoop can then immediately start updating Components across the second group of threads. Handling Events at the beginning of the input and render phases also means that these tasks will start being processed at the highest frequency possible (since the EngineLoop is a fixed timestep loop) which is desirable. This made the EngineLoop look like so:

Whoops - no image :(

With these improvements to the multithreading solution in place, I also had to slightly rework a small part of the ModuleCSM to accommodate for the changes. Small enough, however, that there isn’t much point going over it here, since most of the work I did was on the ThreadPool. And thankfully enough, I didn’t have to make any changes to the EventQueue.

So, what’s next? As of now, there are really only two options: the input module or the graphics module. The input module should be a fair bit easier to get up and running, but on the other hand, getting the graphics module working will be a lot cooler since there’ll actually be something to see. So graphics it is! Hopefully it doesn’t take much longer than it took to get the Core working (although I do have my reservations), and I’ll try to write some short, periodic updates along the way.