Sign in to follow this  
NineYearCycle

Multi-threading terrain generation requests

Recommended Posts

Beware this is a lot of thinking aloud stuff and a request for your eyes to glance over it :) I have a set of processor intensive terrain generation steps, at the moment these run in a main thread which causes it to halt whilst it deals with them. This causes some damned ugly frame rate chugs. At the worst these can last for a few 10s of second (30+ on this 2GHz pc). The idea is to break these terrain generation calls out to be done in another thread as I've got a dual-core cpu but by doing everything in a single thread I'm only using 50% of my processing resources! Once each of these jobs is done it needs to hand back the generated data to the caller. Or would it be better if the caller polled the status of the job? Yeah actually that sounds like it makes more sense as the caller has to maintain information about the job so that it doesn't try and generate the new data request again. Ok so with that in mind, I have an idea of the flow (and not much more):
  • Thread 1: Each terrain node is tested to see if it needs to split (its a quadtree LOD scheme) and when it does it generates a request for the terrain generator which is running in another thread.
  • Thread 1: At each subsequent split test it checks the status of the request to see if it's complete.
  • Thread 2: Meanwhile in thread 2 the terrain generator is generating the data. Once the generation is done it moves it into a completed list and moves onto the next request, repeat ad-infinitum for each request.
  • Thread 1: Back in requestee thread 1 the split test is done and the data is determined to be ready, so it pulls the data back out of the request and generates the next level in the quadtree.
Now several complications arise which may negatively affect performance as there will have to be some mutex'ing, locking and or critical section stuff. The renderer will be running in "Thread 1" along with update logic and some other tasks. This handles all the in game textures which "Thread 2" will need to request from the pool, generate some data into and then assign handles to the terrain node its building... actually that should be fine, requests for textures from the free texture pool will most likely only be coming from the terrain generating thread anyway since this is just a tech demo idea. Even if they aren't they're just a request for a free texture so aren't gonna hold things up. Hmm, I can't actually think of many other problems so what do people think of the basic concept? Is it horribly flawed or perfectly logical? Oh and are there any real gotchas that I should beware of using something like the system that I've just described but not yet implemented. Thanks for your time folks. Andy (aka NineYearCycle) EDIT: after chatting offline to *someone* they pointed out that I should mention that the terrain generator knows almost everything it needs too about the terrains parameters so it doesn't have to communicate with the outside world during the generation except for requesting the resources. The only data it needs from the requestee are the bounds of the area that it must generate.

Share this post


Link to post
Share on other sites
Right, given that the worker thread apparently requires little input, this should be simple really.

Thread 1 collects all data that Thread 2 will need to do its job.
Thread 1 starts off Thread 2 with a copy of this data.
Thread 2 does all its processing and comes up with result data.
Thread 2 then needs to lock the relevant structure and throw that data in.
Thread 1 finds new data in that structure and handles it accordingly.

The only things you really need to consider are the shared resources. One is the structure I mention at the end, for passing the data back. Usually something like any std::container is fine here; just protect all access to it from both threads with a mutex, eg boost::mutex. Thread 1 polls it periodically to see if it's empty, and if not, takes an item off, etc.

The other is the texture pool - why does thread 2 need to use this, and what for? Can it not be done either as part of the input to thread 2, or fixed up by thread 1 after thread 2 returns data? If not, just protect access to that pool with a mutex, too.

Share this post


Link to post
Share on other sites
My version is rather simple...

I simply generate the full resolution in the background, and locking the terrain while doing so. When generation is complete, I generate the indices from the full resolution mesh at runtime.

The fullres generation could of course be a problem with a highspeed moving camera, but for my needs (car combat over a LARGE area) this works like a charm, and is really fast too once the mesh is generated!

Share this post


Link to post
Share on other sites
Quote:
Original post by Rasmadrak
My version is rather simple...

I simply generate the full resolution in the background, and locking the terrain while doing so. When generation is complete, I generate the indices from the full resolution mesh at runtime.

The fullres generation could of course be a problem with a highspeed moving camera, but for my needs (car combat over a LARGE area) this works like a charm, and is really fast too once the mesh is generated!


Nice system but in this case I plan to do some work getting it to generated planets which precludes me pre-generating the full-resolution vertex mesh down to 1-metre for the whole object [grin]

The problem in this case isn't really that terrain generation, there's hundred of articles on that and I've written several terrain systems before. My main problem is in coming up with the scheme for implementing it as a split multi-threaded system, with the mesh/texture generation happening in another thread. However as Kylotan has said, it all seems quite simply really. I'll give it a go tomorrow and report back.

Andy

Share this post


Link to post
Share on other sites
Well I went ahead and implemented something like the original idea I had in an older terrain system I have lying around. It took about 2 hours to get everything up and running mostly due to the nature of the old method but wahey it worked a charm!

Hopefully I'll get some time to do it properly using the factories I mention before but the early test has been really effective. Currently this naive implementation causes quite a bit of blocking during rendering and generation as the objects generate their own children rather than that being done in a separate class. However that won't be the case in the actual implementation.

Thanks for the help everyone it really was almost as simple as I'd hoped but not dared believe :D

Andy

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this