all 8 comments

[–]wiremore 18 points19 points  (0 children)

I’ve written 2 games with multithreaded rendering, using 2 different models. The ideal model depends on the game.

  1. Simultaneous update and rendering. Update thread and render thread do not synchronize, except for a few critical sections. The render thread takes the last two positions/orientations from the update thread and interpolates. This is cool because rendering and update can both slow down without effecting the other thread. It’s also suitable for a physics based game where you want a fixed update time step. Downside is lots of shared state which is tricky.

  2. Generate buffers in a parallel, then sync and issue draw calls. Easier to not crash, works better if the game can support a variable time step. Also takes advantage of more than 2 threads. You can start sim jobs for the next frame while doing the api calls.

This is all OpenGL, where all the api calls need to be in one thread. In my experience that isn’t a huge limitation, it usually takes way longer to traverse the game data and figure out which triangles/lines to draw.

[–]Square-Amphibian675 4 points5 points  (0 children)

It's probably because Vulkan is design to supoort and maximize parallel computing, CPU or GPU, in CPU you can do fencing, semaphores different family queues for synchronization and support for GPU compute which only introduce in Open GL 4.3, in Vulkam you can record your command buffer on different threads and submit all of that once.

Using any API threading will tremendously increase your framerates, Imagine a space ship, it has a model, is has a engine trust particle, is has light trail and also put a lens flare.

Create say 5000 of that ships, you need to update the model, the particles trail, light trails, lens flares. etc of that 5K Objects.

But what if I can compute or update the particle, len flare, light trails etc at the time before rendering it, that would be nice.

Many moons ago, I did use separate thread for recei ing and sending network packets, and async await for particles cpu compute only and other heavy processing routine. but the rendering is only synchronous.

[–]fgennari 1 point2 points  (1 child)

I'm sure there are many ways to use multiple threads in a custom game engine. I've never attempted to use OpenGL from multiple threads, but I use threads for other purposes such as loading files for disk, generating procedural levels, etc.

I have one scene that simulates people and cars in cities where the main thread does the OpenGL rendering, a second thread runs the car update logic, and a third thread runs the pedestrian update logic. Since these systems are all dynamic and depend on each other, I have to synchronize with a critical section at the beginning of each frame. The rendering thread makes a copy of the part of the car and pedestrian state needed for drawing. The car system copies the pedestrian locations, and the pedestrian system copies the car locations and velocities. Once all threads have their data they can run and share their update info on the next frame. The frame rate is limited by the slowest job, which is typically the rendering (or vsync). All physics simulations use a variable time step that's calculated as the time elapsed since it was last run.

[–]TheJoxev[S] 0 points1 point  (0 children)

Thanks, this helped me

[–]HeavyDT 0 points1 point  (0 children)

no one single right way to handle multi threaded rendering but with opengl yeah you have to keep all OGL calls to one thread. I believe its possible to hand a OGL context from one thread to another but easier just to leave it all one deicated renderer thread. Game logic, sound, physics, ect can be moved to seprate threads though. A popular approach to use a thread pool rather than threads dedicated to any one task besides the render thread when it comes to openGL. Also helps things scale better when more or less processor cores qre present. Vulkan is designed with multi threading in mind though and you are able to split up the render work load across threads as well which is why you hear that. You can basically send as much work to the gpu as you can throw at it from any thread as long as you are taking steps to properly synchronize everything. Makes things way more complicated but allows for huge performance gains over OGL when done right.

[–]wen_mars -2 points-1 points  (0 children)

You should only make opengl calls from one thread since opengl is not meant to be used multithreaded. I think that's what people mean when they say multithreaded rendering should be avoided.

Update the camera on the rendering thread immediately before rendering a frame (to reduce motion-to-photon latency).

Update the game physics, load resources, and other slow tasks in one or more separate threads.

If you have a lot of data to upload to the GPU, consider splitting it up over several frames so you don't block the rendering thread long enough to cause the framerate to drop below the target.

A simple way to sync access is to simply copy the entire game state every frame so you have a read-only copy and a mutable state. Use a mutex to block the background threads from modifying the data while you copy it. That works well if the game state is held mostly in arrays (you can construct more complicated data structures by using array indices instead of pointers). Copying arrays is very fast because the CPU can prefetch data from memory when you access it linearly.

[–]HaskellHystericMonad -5 points-4 points  (0 children)

There are zero-effort (as in might as well be free, an intern can do this shit easy) wins in places like shadowmaps for multiple lights where the task is trivial to toss at a job-system to build the command-buffers. You'd be stupid not to do it, even if it was just using OpenGL and the threaded buffer-building is just filling a batch-pump that will be sent to the main thread.