Multithreaded drawing and logic

Started by
10 comments, last by Scourage 10 years, 1 month ago

I've separated the drawing and the sim logic of an RTS into two threads.

The problem is updating unit drawing position. The drawing framerate might be lower than the sim framerate, but the sim must be kept at 30 FPS. If I use a mutex with infinite wait time, that essentially slows down the sim to the same framerate as the drawing thread?

Is there a simple solution?

Advertisement

I am trying to understand your problem first, which is a little bit difficult because I don't speak english very good (ironically for a software engineer).

> When I got it correctly you have multiple threads which are not independent from one another which is propably an artifact from your design decision to program it at the beginning as a single core game.

So to sinc them you could let your drawing thread wait in an endless loop to be invoked by the sim thread using a simple boolean or vice versa. So they would run both at the same time but one thread would wait for the other to finish.

> Your exact problem is that you have problems updating your unit drawing position. This is strange because shouldn't the position of your object be computed in your sim-thead?

You should maybe provide more information what your issue exactly is.

I personally can't really locate the problem.

What happens when the drawing framerate is lower (or higher(?)) then the other thread?

If these are two decoupled threads, updating at different frequencies, then you need double-buffering. i.e. You need to be able to produce/store more than one set of drawing positions.
Each update, the update thread can lock one "buffer" and fill it with data. Each draw, you lock the most recently produced buffer available and draw from it.
You may find that you need 3 of these buffers. One that's full of valid data, ready for the next draw, one being used for drawing now, and one being used for updating now.
The problem is if I'm updating the unit position in the sim thread at the same time as I'm reading that position in the draw thread, it crashes.

What I'm thinking of doing is adding a render-state class to each object that gets update only if the sim thread can get a mutex lock. Otherwise it doesn't wait for it and the draw thread draws at a stale position or a unit at a different frame or something.


The problem is if I'm updating the unit position in the sim thread at the same time as I'm reading that position in the draw thread, it crashes.

Thats why Hodgman suggested multiple buffers, you update one of them while drawing from the other. After both threads have finished, you swap the buffers and repeat.

I see. That's what I'm doing. It's making my code ugly though, and I don't know if I will benefit.

There's problems with multithreading for me

- must set all the render-state buffer variables for each object each sim/update frame, wasting cpu cycles, insteading of just setting what changes

For example, for a building here are all the variables that are relevant to rendering:


	class RenderState
	{
	public:
		Vec3f drawpos;
		int type;
		int stateowner;
		int corpowner;
		int unitowner;
		bool finished;
		int pownetw;
		int crpipenetw;
		list<int> roadnetw;
	};

Is it worth it?

[edit] It's probably too much copying because entire vertex arrays might change during a frame.

In Doom 3 BFG, does the renderer frontend that sends draw commands to the renderer back end (that sends them to the GPU) also send a copy of the vertex arrays to draw? http://fabiensanglard.net/doom3_bfg/threading.php
Another option is to change your threading model. You could run your update phase in a multithreaded fashion, using worker threads to update multiple groups of entities at the same time. Then if it's time to render the scene, create all your draw calls (also could be done in a bunch of worker treads) and send them off to the gpu.

Cheers,

Bob

[size="3"]Halfway down the trail to Hell...

run your update phase in a multithreaded fashion, using worker threads to update multiple groups of entities at the same time

The result of one unit's update might depend on another, so this isn't a solution for lockstep multiplayer games.

create all your draw calls (also could be done in a bunch of worker treads) and send them off to the gpu

Sending them off to the GPU in each worker thread? They share the same GL context and would have to constantly switch with wglMakeCurrent. Plus what if they require different shaders?

I've decided that there's too many problems with multithreading, so I'm going back to single-threading. Mutex locks everywhere, not knowing if I might be missing one somewhere...

This topic is closed to new replies.

Advertisement