(note: this is slide 19 of the nulstein plog)
Long time between the last post and this one, there's been vacation followed by a long trip in the US to meet up with people doing the same kind of job as mine, share experiences, ideas and projects. People have been planting all sorts of clever ideas in my head and, as often, it feels like a life won't be enough to explore everything. Life is good. All the more reasons to get this plog to move forward, as what I expose here is just groundwork... So, where were we?
We were actually going to conclude on the Update phase of the game. I have shown that by splitting that phase in two, Input and Output sub-phases, we can easily handle a lot of what goes on in a game in parallel. The limitation being that an entity must expect an interaction with another to be able to collect the information it needs. This turns out to be too much of a limitation as there are entities like AIs that may need to interact with entities like bullets, unexpectedly. How does that fit in the model ?
It turns out that this can be implemented easily and efficiently: we need some messaging system. During the Output phase, the bullet finds it has hit the AI, and posts a message "AI 42, take 8HP damage from SilverBullet 12945". Next frame, Input phase, AI checks the notice boards and realizes "Arrrrgggghhhh, I'm dead". The message board is read-only during Input phase, post-only during Output phase, and cleared just before Output. Because it is post-only during Output, each thread can have its own queue, and we can simply concatenate+sort it before Input phase starts. You've now seen this enough times to conclude: no sync mechanism required. Because the notice board is really a sorted array of events of the type (dest,msg,parm,src), it can also be used to broadcast messages by defining conventions for destination ids. This gives us the ability to process all updates in parallel, with expected events processed same-frame and unexpected ones processed early next frame, which should be good enough in most cases.
The case where things can't quite work in parallel is when you have chain reactions that need to happen inside one frame. Typical case is a snooker ball hitting a corner, twice, before hitting a ball that's in contact with a couple others. We can't wait for events to flow through the message board across frames: the reaction must be computed correctly so what gets rendered is correct. Physics will have to be handled separately, probably in yet another phase. For now, this is an open problem and an interesting exercise for readers (don't hesitate to drop me a mail if you raise up to this interesting challenge)
One topic got mentioned at GDC online that I hadn't talked about so far (because, like the notice board, this is still on the TODO list), entities lifetime: how are they born, how do they die and how do they get recycled ?
Of course, nothing such can happen during the Input phase: an entity can be created or disposed only during the Output phase. The one thing to pay attention to is to not recycle an entity Id until the next frame: this has to do with the notice-board, if an entity posts a message for an entity that is currently being disposed, you don't want a new one to spawn right in its place and collect a message that isn't related to it. This precaution is enough to make this all work and there isn't much of anything else to it.
Other than Physics, this framework has the property I was looking for: it does parallelize and it does so without a fuss (and we'll work Physics in). No synchronisation objects required, no fine grained subdivision of aspects, just a few rules that anybody should be able to understand quite easily. Failsafe mechanism can be implemented by adding checksum tests to assert that data doesn't get changed outside of the correct time in the Output phase. It is even possible to imagine a scripting engine running a script per thread and working safely thanks to the rules we defined. Everybody on the team can participate in making the game run in parallel !
What about rendering?
Next time, we get started on making the Draw phase parallel
Spoiler (slides+source code): here
Para obter informações mais completas sobre otimizações do compilador, consulte nosso aviso de otimização.