11.19.2010

Engine Overhaul

I felt so bad for always NOT working on my text game, I had to make a little redesign with my newly acquired multithreading knowledge. As I don't have one PC without a subdivision into multicores (via lowlever software or hardware), I think it's time to get rid of those massive CPU time poblems I would've had without redesigning it with multiple threads. As I do seem to have three cores in my desktop PC, I seperated the core parts of the engine - graphics, physisc and logic. I quickly designed a system of strong division between graphical, physical and logically object and map properties and a "task" stack for every thread it empties and locks before going into the next calculation loop. It's quite a nice approach without so many locks and almost without any waiting between. Basically, there are several threads with a task stack: it holds tasks which the thread has to perform before it enters it's own output/operation loop (in case of the graphics thread it's raytracing and displaying the current scene). These consist of changes to the thread's map and object data (the scene's graphical, physical and logical representation, for each thread one of them), which again changes what the the thread will send to another thread during it's output/operation loop. So we can have a logical thread to control which object does which move, which we put on the physic thread's task stack. At the moment the threads task completition time has come, he recognizes the "move event", does set the object's movement parameters and continues to calculate all position changes of all objects after applying all data changes found in it's stack. During this calculation it also sends changes to the graphics thread (object pointer on the graphical map data changes) and the logical thread (object pointer on the logical map data changes), which will again execute their data change tasks if before their main loop repeats again. So basically, I'd need to lock all task stacks to prevent endless refilling of the same stack when the sending threads fill it while the executing thread executes them, I use two stacks - it's similar to double buffering as I simply give a free, to-be-filled stack while executing the other, now not anymore visible stack. So I can execute a stack while the other is getting filled. Of course could one argue that even with such a communication the sending threads can still spam the executer's thread while increasing the time it requires to get to their main loop. Well, in a game, every thread has a maximum delay time between updates to prevent them from consuming more CPU time than they'd need or simply to get a constant frame or game update rate. And that's exactly the gap we can use to execute our task stacks. The tasks are quite simple (mostly overwriting array elements) and need less time to execute than the main loop. In order to preven threads from beeing to busy and task to be executed, we exploy the time we'd usually waste CPU time to empty out stacks and swap time after executing all tasks. So we then execute our main loop and can take the next full stack and so on. This might generate some differences and disadvantages compared to normal single-threaded games (some frames delay between the way from game logic to physics to graphics), but the resulting performance increase makes it up in the final result. I don't have much experiences with real multicore-based programming (I always hade hyperthreading processors), so I'm interested to find out how effective it will be when implemented in a game. I can't wait to realize it! The next weeks are coming and I think this is worth using, especially for the image processing assignment I still don't have any instructions for. See, as we process a number of images and maybe I need to make several branches of filtered images to join them later. It could effective reduce the required CPU time by the shortest of all parallelly processed branches. And you DO need a lot of CPU time in image processing. So it's cool to have a multithreading toolkit available. And ITK can archieve one more effective feature, generalized of course.

No comments: