This week, I begun work on the threading model for the engine. Since having a thread for each component (rendering, physics, main game loop, input, etc) wasn't feasible and left a lot to be desired for the engine, I changed it to a Fork/Join or Job model. This allows easy use of a thread pool, which is easy and intuitive to use. I created a ThreadPool class that manages the queueing of tasks and the management of threads.
This was new territory to me, since I wanted to play with C++0x features like condition variables, return_type, std::futures/std::forward, etc. I also learned about more than the typical lambda function, and made the ThreadPool class accept any type of method: class method, static methods, functions, lambda expressions, etc. The interface looks like the following, and returns an std::future for the result:[code=:0]ThreadPool::create(std::thread::hardware_concurrency() - 1);// ...//auto = std::futureauto result1 = ThreadPool::enqueue([]{return "test"});//getInt returns 42.//auto = std::futureauto result2 = ThreadPool::enqueue(&getInt);// ..std::cout << "Result 1: " << result1.get() << std::endl;std::cout << "Result 2: " << result2.get() << std::endl;// ...ThreadPool::destroy();
I have the threads sleep on the condition_variable in ThreadPool until there's tasks for them to complete. Each call returns an std::future, from which the result is received.
Once I had the threading model, I started using it! I chunked out the world, and threaded different aspects of it (loading, unloading, generation, etc.). Below is an example of it working:
Lastly, I noticed some issues with my mesh generation. It was taking 125-160ms, and that is WAY too long -- my Java version managed to generate chunk meshes in about 30ms. After a long time looking through the code, unrolling loops, etc., I was able to get it down to a whopping 22-25ms!! Now I can generate chunks (threaded) about 2-4 per frame, rather than one at a time! AND since I've got a Job framework going, I can have mesh generation take most of the frame time, and have the renderer grab the result and render it at the end!
This next week, I hope to start putting together a noise library for creating terrain. Alongside that, I need to start working on transparency (UGH It's already giving me a headache...) in order to handle water, liquids, and translucent materials.
Best,
ST
This is looking good. I use threading exclusively for the chunk generation since generating voxels can be done independently, and the same with mesh generation.
I haven't thought about unrolling loops, though. My data is stored in 3D arrays and thus uses loops nested 3 deep for more readable code.