Threaded Game Engine

Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
Post Reply
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

That msdn article was cool, thanks!

It got me thinking about something.. I have heard for a long time that Ogre is already multithreaded (or perhaps I heard asynchronous, but isnt that the same thing?), however I never fully understood the details. In that article they talk about how you can run your actual rendering thread a frame or two behind your 'update' thread (input, physics, ect...).

Doesnt Ogre already do that? For example, while im running my input/gamelogic/ect..., isnt Ogre busy rendering the last frames content? So wouldnt that mean whenever you call anything related to ogre, youre working with a 'second' copy/buffer (while the other is actually being processed). Is that what people mean when they say rendering is already multithreaded (I swear ive heard people say that hehe)?
User avatar
CaseyB
OGRE Contributor
OGRE Contributor
Posts: 1335
Joined: Sun Nov 20, 2005 2:42 pm
Location: Columbus, Ohio
x 3
Contact:

Post by CaseyB »

Uh, no, Sinbad is working on making Ogre Threadsafe to allow for the background loading of resources, but it will never do any threading for you. All of the input stuff is done, currently, in the FrameListener, so you update it each frame.
Image
Image
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Zeal wrote: Doesnt Ogre already do that? For example, while im running my input/gamelogic/ect..., isnt Ogre busy rendering the last frames content? So wouldnt that mean whenever you call anything related to ogre, youre working with a 'second' copy/buffer (while the other is actually being processed). Is that what people mean when they say rendering is already multithreaded (I swear ive heard people say that hehe)?
You can run Ogre in its own thread if you like, but you cannot access any of the Ogre objects from another thread (other than the Resource objects which are being made threadsafe, as mentioned). If you plan to run Ogre in another thread and interact with it from your application, you need to set up a message queue or use some other decoupled configuration, to communicate with Ogre in its thread.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Hmm I know I heard/read somewhere that graphics/rendering was already multithreaded, thus it makes no sense to 'further multithread' your rendering thread.

But in anycase, it seems like that article was on to something. If you simply render one frame behind, you can run your input/physics/ect parallel with your main rendering thread. Youd just have to set up a 'double buffer'. When your done writing to your 'update buffer', swap it with the 'render buffer' and youll never have to worry about locking resources mid thread.

It seems like that, plus some 'fine grain multithreading' (as described in the valve article, where you offload simple calculations to idle cores) would make for a damn fine multithreaded engine. Eh?
Last edited by Zeal on Thu Nov 30, 2006 2:10 am, edited 1 time in total.
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Zeal wrote:Hmm I know I heard/read somewhere that graphics/rendering was already multithreaded, thus it makes no sense to 'further multithread' your rendering thread.
It's not. What you probably heard is that data processing on the GPU is massively parallel by nature, but that is not the same thing as multiprocessing or concurrent processing on the CPU.

The GPU, from the perspective of the CPU, is a single device and access to it is naturally serialized in the driver. There is no need to try to render in multiple threads, for that reason. That is not the same as running Ogre in its own thread and performing other tasks in their own threads. The thread-safe resource management classes are being made so in order that you can background-load resources, something that does benefit from threaded processing.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Hmm ok so right now when I call 'renderOneFrame', my app will just sit there until the entire frame is rendered, even if the cpu is idle (while the gpu is working), when it (the cpu) COULD be working on the next frames physics, animation, ect? Of course to work directly with anything ogre related, you would have to be writting to a second buffer/copy of your ogre resources (since the 'original' is still being processed) right?

*in other words, if it only takes 5ms for the cpu to send everything to the gpu, but it takes 10ms from that point for the gpu to render everything, what is the cpu doing for that 10ms? Just sitting there idle I imagine?
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Zeal wrote:Hmm ok so right now when I call 'renderOneFrame', my app will just sit there until the entire frame is rendered, even if the cpu is idle
[Edit: what I said previously was incorrect] The app will wait for the GPU to render to the current framebuffer, and then return control -- it's rare that your CPU is waiting on the GPU for any significant amount of time however, unless you are doing fillrate-limited rendering, or some absurdly heinous vertex or fragment programs.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Yeah I figured it would be rare that the cpu would really be waiting for the gpu..

So I guess the next question is, how can you run 'a frame behind' as suggested in that msdn article. It would require two 'copies' of your ogre resources would it not (one for your update thread to write to, and one for your render thread to read from/process)? Or perhaps that method isnt even all its cracked up to be?
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

The GPU is always rendering to the backbuffer; you are never seeing what you are rendering, it is always rendering at least one frame behind what you seeing.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Ah of course, that explains why they said TWO frames behind in that article (however when youre running at 60+fps this latency isnt noticed). But the same problem, you need two instances of your ogre resources in order to have a 'update' thread and a 'render' thread. How could you go about that?
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

You don't have two instances of Ogre resources. You have your game's objects, which reference Ogre resources (entities) as needed. Your game logic updates the renderer across the message queue, which then updates the Ogre objects on your behalf. The Ogre thread is free-running, and when it is done rendering one frame it just starts on the next with whatever data is waiting in the queue...you don't try to sync the rendering thread, indeed any thread, with any other thread -- to do so is just serializing your app all over again. Instead, you just let each thread be free-running and have it update other concerned threads as needed using messaging.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

you don't try to sync the rendering thread, indeed any thread, with any other thread -- to do so is just serializing your app all over again
It seems like our ultimate goal is (correct me if im wrong) to get the 'render thread' to have 0 idle time. In other words, we want one thread, that does nothing other than renderOneFrame, renderOneFrame, ect... We should always be ready to feed Ogre with a brand new set of renderable data after every frame, no waiting.

In that case, this 'render thread' will be the ultimate bottleneck for our app. I mean, whats the point of running your physics, animations, ect.. at 120fps, when the user is only SEEING 60fps? So it seems like it IS a good idea to 'sync' your threads, no? If your physics thread finishes while your render thread is still working, why would you want to run the physics thread again? Why not use that idle time to help other threads catch up. Again the ultimate goal is to make sure we are ready to begin rendering the next frame IMMEDIATELY after the current frame finishes.

So shouldnt we be aiming for something like...

Thread 1 - Render thread - call 'renderOneFrame' over and over

Thread 2 - Physics thread - Update physics for ONE FRAME, then STOP. Dont run again until your current 'update' is taken by the render thread.

Thread 3... - Same as thread 2

Sure this could cause some idle time if a thread finishes before the current frame has been rendered, but so what? As long as we achieve our ultimate goal (nonstop renders), who cares? Again, whats the point of running physics at a higher framerate than the eye will detect? Same goes for the other 'non render threads' (animation, ect...).
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Zeal wrote:We should always be ready to feed Ogre with a brand new set of renderable data after every frame, no waiting.
No, you should always be feeding the render thread data across the message queue regardless of frame status. That's what is meant by "free-running": you don't care whether it's rendering a frame or not, you just keep pumping updates over as they come available. The render thread will grab them at its convenience.

This works in an Ogre world because you are dealing (or should be) with Ogre on an object-oriented basis. Ogre keeps track of the objects it needs to render; your updates simply change the position, orientation, etc. of those objects at the convenience of your application.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
CaseyB
OGRE Contributor
OGRE Contributor
Posts: 1335
Joined: Sun Nov 20, 2005 2:42 pm
Location: Columbus, Ohio
x 3
Contact:

Post by CaseyB »

@Zeal
Not really, the goal is to use as much of the cpu as possible! Designing in idle time would be the exact opposite of what we're going for. If teh physics thread finishes before the render thread finishes that means that you can amm more physics in or it can sleep for a while and give it's core up to the thread pool so that someone else can parallelize their task. I think the key part that you're not seeing is that it's not a rendering core, a physics core and a cpu, They are system resources and our job is to put them to the best use!
Image
Image
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

No, you should always be feeding the render thread data across the message queue regardless of frame status.
I agree, so the 'update' thread is doing its thing regardless of the render threads status. By 'updating' I mean setting positions, orientations, cameras, ect... as you described. Or in other words, preparing the renderable data.

The problem seems to be, the update thread cant prepare that data while the current frame is being rendered (too many resources to be locked), so that article suggests using a double buffer approach. So when your update thread runs, it works with a unique buffer (while the render thread is working with a second buffer). When the render thread is finished, the buffers swap, and everything begins anew.
you just keep pumping updates over as they come available.
But like I said earlier, why would you bother 'pumping' another update when the CURRENT update hasnt even STARTED to be rendered? I think I understand what you mean when you say 'free-running', im just saying, whats the point?
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Zeal wrote:
No, you should always be feeding the render thread data across the message queue regardless of frame status.
The problem seems to be, the update thread cant prepare that data while the current frame is being rendered (too many resources to be locked),
You're still confusing the issue. Your main logic loop doesn't (can't) hold Ogre objects; it manages whatever data is needed to move things around in the virtual world. The graphics thread is simply rendering a visual representation of that world: it's not the primary thing in a game engine.

The graphics thread will render just fine when its time arrives. You don't have to worry about setting anything up -- Ogre takes care of the dirty details. You just send the graphics thread messages about updates to objects in the Ogre world (perhaps identified by a unique ID).
you just keep pumping updates over as they come available.
But like I said earlier, why would you bother 'pumping' another update when the CURRENT update hasnt even STARTED to be rendered? I think I understand what you mean when you say 'free-running', im just saying, whats the point?
You need to stop thinking in immediate terms -- Ogre is a deferred (queued) renderer. You can move an object (Entity) around in a scene any number of times before it actually gets rendered. This is the update you need to think about (updates to objects in the world), if you are going to build an engine based on a scene-oriented renderer like Ogre.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

You can move an object (Entity) around in a scene any number of times before it actually gets rendered.
This is my point exactly. As I have said, the update thread is simply setting the position of an entity. All of the work you do in your update thread (physics, animations, ect...) MEAN NOTHING until the render thread actually renders (writes to the frame buffer using the CURRENT frame/scene/object status). So in a situation where your 'logic' updates faster than your 'render' (as is the case most of the time), I see no reason why thread syncing is such a no no.

But confirm for me my original thesis. Our ultimate goal is to dedicate a single thread/core to NOTHING but rendering. It looks at the current 'scene status' (object positions, renderables, whatever you want to call it), and starts rendering (a very serial process as you described above). Once its done, it has a fresh set of 'data' ready to go for the next frame. There is ZERO delay between the end of one frame, and the start of another.

So assuming that IS the ultimate goal, WHO CARES what the other threads are doing? Who cares if they go idle for a bit, as they wait for the next frame to fire. As long as all other threads, via whatever means necessary, produce one complete 'set of scene status' before the NEXT frame is ready to start, we have accomplished our ultimate goal.
Your main logic loop doesn't (can't) hold Ogre objects;
Youre absolutely right. I have NO idea how you could achieve a 'double buffered' technique as described in that article. But if there is a way, I think it would work great.

*Maybe 'double buffering' in this sense should be a part of Ogre (or any graphics engine for that matter). Why shouldnt we be able to 'work' on the NEXT frame, while we wait for the cpu/drivers/gpu/fillrate to render the CURRENT frame?
Last edited by Zeal on Thu Nov 30, 2006 5:52 am, edited 1 time in total.
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Zeal wrote:
You can move an object (Entity) around in a scene any number of times before it actually gets rendered.
This is my point exactly. As I have said, the update thread is simply setting the position of an entity. All of the work you do in your update thread (physics, animations, ect...) MEAN NOTHING until the render thread actually renders (writes to the frame buffer using the CURRENT frame/scene/object status). So in a situation where your 'logic' updates faster than your 'render' (as is the case most of the time), I see no reason why thread syncing is such a no no.
What are you going to sync? Are you going to stop the render thread to wait on other stuff? That makes no sense whatsoever.

There is absolutely nothing wrong with updating the position of an object N times before it is rendered again. I don't really see what you are syncing on here.
But confirm for me my original thesis. Our ultimate goal is to dedicate a single thread/core to NOTHING but rendering. It looks at the current 'scene status' (object positions, renderables, whatever you want to call it), and starts rendering (a very serial process as you described above). Once its done, it has a fresh set of 'data' ready to go for the next frame. There is ZERO delay between the end of one frame, and the start of another.

So assuming that IS the ultimate goal, WHO CARES what the other threads are doing? Who cares if they go idle for a bit, as they wait for the next frame to fire. As long as all other threads, via whatever means necessary, produce one complete 'set of scene status' before the NEXT frame is ready to start, we have accomplished our ultimate goal.
I think we are talking at somewhat cross purposes here. You don't need a "complete" anything. Each thread runs its own loops, processing whatever data is available at the time it drains the message queue.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

What are you going to sync? Are you going to stop the render thread to wait on other stuff?
No of course not. When I say sync, I simply mean make sure the game logic doesnt run faster than the game rendering, as it is pointless (again please correct me if im wrong, I might be missing something).
There is absolutely nothing wrong with updating the position of an object N times before it is rendered again. I don't really see what you are syncing on here.
Akk how can you say that? What if you have a thousand objects, each requiring a intense physics calculation to determine their position? Why on earth would you run all those calculations 30 times, when you might only be able to DISPLAY 10 of those 'positions'? You could use that cpu time to help your other threads along.

Are you upset that your 60fps (rendered) game doesnt do 120fps worth of physic calculations? Of course not. What happens between frames doesnt matter (as long as each frame is accurate of course).

But what about my thesis? Is that not the best scenario (for a game at least)?

Also curious to hear anyones thoughts on...
Maybe 'double buffering' in this sense should be a part of Ogre (or any graphics engine for that matter). Why shouldnt we be able to 'work' on the NEXT frame, while we wait for the cpu/drivers/gpu/fillrate to render the CURRENT frame?
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Zeal wrote:
What are you going to sync? Are you going to stop the render thread to wait on other stuff?
No of course not. When I say sync, I simply mean make sure the game logic doesnt run faster than the game rendering, as it is pointless (again please correct me if im wrong, I might be missing something).
You want all of your threads to run as fast as they can. One of the hardest things for people new to concurrent programming to leave behind is this thing with worrying about what other threads are doing. Don't. Each thread should care less.

I would suggest that you want your physics world to simulate as fast as possible, for the highest precision, rather than have it waiting around because the rendering thread might not be "ready" for it yet. If the rendering thread is not ready, go ahead and do another iteration; when the rendering thread is ready to start another frame, it will get the data from the latest iteration of whatever thread it might be (game logic, physics, whatever) -- it doesn't really matter. There is absolutely no point in slowing down any one thread because of concerns in another.
[/quote]
There is absolutely nothing wrong with updating the position of an object N times before it is rendered again. I don't really see what you are syncing on here.
Akk how can you say that? What if you have a thousand objects, each requiring a intense physics calculation to determine their position? Why on earth would you run all those calculations 30 times, when you might only be able to DISPLAY 10 of those 'positions'? You could use that cpu time to help your other threads along.
[/quote]

First, I am talking in general terms -- allocation of computing resources is not the issue in this discussion. Think abstract for now; don't limit yourself on the basis of a single architecture. Assume for the sake of argument that you have 6 very fast processors that can each do a thread all by themselves (yes, the machine I have in mind begins and ends with "x", or maybe "P" and "3").

To answer: because you are getting the highest possible precision from your physics loop, which I find to be more desirable than stalling because some other thread is slower. Update the object positions (even replace them in a priority queue if you like), let the rendering thread deal with them in its own time.
Are you upset that your 60fps (rendered) game doesnt do 120fps worth of physic calculations? Of course not. What happens between frames doesnt matter (as long as each frame is accurate of course).
It's also a mistake to think in terms of "frames" for things like physics; physics doesn't have "frames", it has "time" and it likes to run with the smallest timestep possible for the highest level of accuracy.


But what about my thesis? Is that not the best scenario (for a game at least)?

Also curious to hear anyones thoughts on...
Maybe 'double buffering' in this sense should be a part of Ogre (or any graphics engine for that matter). Why shouldnt we be able to 'work' on the NEXT frame, while we wait for the cpu/drivers/gpu/fillrate to render the CURRENT frame?
Double-buffering is something done by the drivers, since it's a hardware-level facility. You could say Ogre already does this; it uses whatever the drivers make available. What you are describing in fact is precisely how GPUs operate; they couldn't work any other way, in fact.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

You want all of your threads to run as fast as they can. One of the hardest things for people new to concurrent programming to leave behind is this thing with worrying about what other threads are doing. Don't. Each thread should care less.
I agree, and in the 'traditional' multithreading sense, that does seem like the most logical way to go. And youre right about precision, if you can afford to run your physics a million times, you might as well, BUT it should never stall your rendering thread.

I guess what im trying to articulate is, what if there was a way to maintain TWO 'scene states'. What if you could double buffer your entire engine? Wouldnt that free you from any locking/access issues? Thus you could 'set up' the next frame while the rendering thread was chomping away at the current scenes state, and youd NEVER have to worry about the two threads stepping on each other.

Since you would only have two 'buffers', you couldnt run your 'update' thread again (the 'current' buffer is fresh, and the old buffer is currently being used by the render thread). Thats the ONLY reason I mention 'stopping' the update thread.

Again im thinking about this specific to games obviously.
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Buffers have nothing to do with any other world in the game. Physics, audio, main logic and graphics all have their own "scene graph" as it were, and each has nothing to do with any other (other than sending updates to interested threads, for example, physics sending positional updates to the main logic, which then has the option to pass it along to graphics or audio if it likes). I still don't understand where you think that graphics is going to stall physics?
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Lets say I had a game with two functions.

Code: Select all

setBallPosition() {

//do physics stuff
//talk to ogre, node->setPosition(x,y,z)

}
and

Code: Select all

render() {

//ogre does its stuff, send the ball to the gpu, gpu writes to the frame buffer, ect..

}
Now, in a traditional single threaded design the above would be no problem. You would call setBallPosition(), then render(), then setBallPosition(), then render(), ect... However, what would happen if you put each function in its own thread? SetBallPosition() could not simply 'write' to ogre, telling it about the balls new position, because render() might be smack dab in the middle of processing that very object (correct?).

Cue a double buffer. If you maintained TWO 'scene states' (I guess thats the proper term), you could run the two threads parallel no problem (no resource locking needed). And the only reason I even brought up the concept of 'stopping' the setBallPosition() thread was because youd have nowhere to 'write' the new data if you ran the thread again (unless you used a third buffer). You want to stop the setBallPosition thread as soon as it runs once, so youre 100% sure you have a COMPLETE update ready to go the SECOND render() finishes (so the buffers can be cleanly swapped).

Thats what I mean when I talk about 'scene state' double buffers (nothing to do with traditional frame buffers). Whether or not its possible to implement is beyond me :p, but it seems logical does it not?
User avatar
Game_Ender
Ogre Magi
Posts: 1269
Joined: Wed May 25, 2005 2:31 am
Location: Rockville, MD, USA

Post by Game_Ender »

You are not listening to Xavier at all, and your example shows it. Instead of called "ogre_node->setposition", which would mean that you would have to wait for ogre to finish before making the call you do "GraphicsMgr->sendMessage(SetPosition(node, position))". Then when Ogre finishing rendering it would process all messages and render another frame. If you are worried about one thread using to many resources, use priorities, that's what they are for.

So you do everything *at the same time*, insulating them from messing each other up by having them pass messages instead of making calls on each other objects.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

insulating them from messing each other up by having them pass messages instead of making calls on each other objects.
That works exactly the same way as my 'double buffer' theory. The only difference is you maintain messages instead of two 'scene states'.

I wonder though, would there be any delay at the end of a frame, when the render thread has to go through every message, set the state (position, orientation, ect...) for all objects? If the answer is no, then I guess a message system would be just as good as a 'double scene state buffer' (a lot easier to implement too).

*btw it was that msdn article that brought up the concept of buffers...
Because the update and rendering threads work in lockstep with each other, their communication buffers are simply double buffered: at any given time, the update thread is filling one buffer while the render thread is reading from the other.
*oh and one more thing. I see how a messaging system would work fine for things like setting node positions, but what about more complex stuff like animation? Could you really animate with simple messages?
Post Reply