Jump to content
  • Advertisement
Sign in to follow this  

Decoupling the rendering thread and the game thread

This topic is 2845 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

From watching the Android game programming Google conference, they mention that it is a good idea to separate the rendering and the game logic, ie via threads. My question is, how does the rendering thread knows that when it is rendering the gaming data, that it is not being altered at the same time?

Has anyone used this type of method before?

For reference here is the video:

Share this post

Link to post
Share on other sites
You'll have to make a real good plan when splitting threads, otherwise get ready for a world of pain! As you mentioned, the trick is to prevent reading/writing at the same time. This can be done with "mutexes" / "critical sections". Basically you look a section in one thread so that another has to wait until the lock is gone.

var X : integer; // my shared global variable
enterCriticalSection( mutex_X_Handle );
x := something;
leaveCriticalSection( mutex_X_Handle ); // Release the lock

enterCriticalSection( mutex_X_Handle ); // If thread 1 locked via mutex_X, then wait
x := something_else;
leaveCriticalSection( mutex_X_Handle );

That gives a second problem, preventing not waiting too much for each other. The problem with sharing game-logic and rendering is that stuff such as matrices/positions are required a lot by both threads. AI routines such as pathfinding on the other hand can be seperated quite easily. One method is working with lists or "thread pools".

----------------------- PUTTING A REQUEST -----------------
<main Thread>
requestObjectt.startPos := position
requestObject.targetPos := position
requestObject.otherParameters := xyz
requestObject.requesterHandle := &my_AIobject;
// Put the request. Don't forget to lock the list while doing so!
list := pathFinding_RequestList.getLockedList();
list.add( requestObject );
// Go on with whatever you were doing... The result will come later

<Pathfinding thread>
// Check if there is a new request
list := pathFinding_RequestList.getLockedList();
if list.count > 0 then
newRequestObject := pathFinding_RequestList.items[0]; // FIFO
pathFinding_RequestList.unlock; // Unlock list again so that the other thread can

resultObject := pathfinder.solve( newRequestObject ); // Do the pathfinding
// When we are done, put it in a "result list"
list := pathFinding_ResultList.getLockedList();
list.add( resultObject );

----------------------- GETTING A RESULT -----------------
< main Thread >
// Poll for results
list := pathFinding_ResultList.getLockedList();
if list.count > 0 then begin
result := pathFinding_ResultList.items[0]; // FIFO
handleResult( result ); // Pass result to the requester

The overlap time that both threads are working with on the same thing, the 2 lists in this case, is minimal. The real work is within the pathfinding itself, and this is nicely executed in the background without stalling other threads.

I think currently more and more graphical API's also offer routines to render stuff in another thread, but that requires knowledge about the specific API you'll be using.


Share this post

Link to post
Share on other sites
Separating these things does not require threads, nor is it usual to use threads to separate them. Just set up a main loop that interweaves calls to the top-level rendering and physics functions, and don't alter the data in the rendering functions.

Share this post

Link to post
Share on other sites
The best way to deal with this is to split your models into two(or three) parts.

What I have is:

1) A model class, eg static mesh. This contains data which does not changes, such as vertex buffers, material mappings etc. It can safely be used from any thread.

2) A model instance, this references the model and contains per instance data which often changes. For example the model transform, drawing mode etc. This class is used by the game/entity thread.

3) A model proxy class, this contains a copy of the rendering specific instance data. For example the transform for the current frame.

Then you have a pair of game loops something like this, one loop runs on the entity thread and the other on the game thread.

Render thread:

Wait for entity thread to finish.

>> Update proxies from entity model instances by copying relevant data. eg the instance transform.

Signal entity thread that it can start processing.

Pre render setup, eg updating light and material bindings.
Draw Render proxies

Entity thread:

Wait for signal from render thread to start

Perform entity update, physics etc using model instances.

Signal render thread that we are complete

Of course this can be extended to more threads, but typically this is more complicated and individual parts of each thread may be multi threaded.

For instance the render thread can start multiple threads to render shadow maps(easy since the proxies only change when they are updated after the entity thread finishes).

Or the entity thread can run the physics on multiple threads(probably with additional copies of the relevant state).


Share this post

Link to post
Share on other sites
Here is another thread on this topic I've had bookmarked for a while.


It is also worth checking out the sources for Replica Island. I don't recall offhand the exact approach it uses, but there is a separate rendering thread. The developer's blog and talks have also indicated this topic is one which he plans to integrate more thoroughly into the game.


Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!