0
\$\begingroup\$

I have been thinking about this a lot and don't know if i'm thinking incorrectly.

Most games have one game loop that can be split into three functions. A basic game loop would look something like this:

while(true){
    handle_Input();
    update();
    render();
}

It's good when the handle_Input() and update() function are called as often as possible to create more responsive controls. But there is no point in calling the render() function more often then your monitor refresh rate. You could of course limit the speed of the loop in order to hit your monitor refresh rate but it would make the controls less responsive.

Wouldn't it be better to create two game loops?

The first game loop would call the handle_Input() and update() function as fast as possible, while the second game loop would take the latest frame the first game loop calculated and only call the render() function. The speed at which the secend game loop runs would be limited by the monitor refresh rate. In order for the concept to work, the game loops should be running on separate processor cores.

Wouldn't this create a lot less overhead for both the CPU and GPU by not wasting time on the worthless render() calls? And allow the game to either run with a higher fps count or better graphics? Wouldn't it also allow to give unbalanced systems, which have a weak GPU compared to the CPU, a more playable experience, because the weak GPU would only limit the fps you see but not the handle_Input() and update() calls?

I have never seen somebody implement a concept like which make me think something like this wouldn't work.

\$\endgroup\$
  • \$\begingroup\$ You rarely have to call the input method more, than how many times you want to render stuff. It's not just that people can't really press and release a button in 0.016 seconds, but also that inputs usually get queued, they don't go away until you query them at least once. \$\endgroup\$ – Bálint Aug 11 '18 at 2:55
  • 1
    \$\begingroup\$ But that doesn't mean people don't do it. In fact, letting the physics run a fixed amount of times a second, completely separate from the render loop is a pretty common thing. Unity does this for instance. \$\endgroup\$ – Bálint Aug 11 '18 at 2:57
  • \$\begingroup\$ @Bálint But does it make sense to make two loops for the render() and update() calls? I already knew that it's done for physics \$\endgroup\$ – Dolfos Aug 11 '18 at 3:02
  • \$\begingroup\$ @Bálint I also don't expect people to press and release a button. Pressing or releasing is enough. \$\endgroup\$ – Dolfos Aug 11 '18 at 3:05
  • \$\begingroup\$ Some similar ground is covered in this Q&A thread, which may be of interest to readers here: What is the point of update independent rendering in a game loop? \$\endgroup\$ – DMGregory May 23 at 16:15
4
\$\begingroup\$

That's an interesting idea, however...

With multi-threading, you lose your advantage because you have to stop the update thread when you update your graphics.

Think about it: if you render at the same time you update you simulation and your scene graph, chances are that at some point you'll be updating it while you're rendering it. What will happen? You'll draw some nodes twice because they'll have changed position in the scene graph? Two nodes that should never be drawn together will be drawn because of the order in which they're updated by your logic and the order they are drawn in the scene graph does not really match?

A lot of things could go wrong with your rendering.

So basically you'd have to suspend your update thread for the time you're rendering your scene, just to make sure that nothing goes wrong.

Then why do you need threads?

You don't.

Glenn Fiedler wrote an interesting (and very popular) article in 2004 titled Fix Your Timestep. He also suggests to use two loops. But they're nested, not parallel.

The idea is roughly to update the physics until it's time to draw, then draw, then rinse and repeat:

while( ! quit ):
  while time for this frame is not up:
    updateAndPhysicsForOneStep()

  render()

The article explains it much better than I would.

Additionally, threads add another layer of complexity (not talking about the headaches) of an already complex piece of software, so if you can achieve something with only one thread, you should favour that instead of a multi-threaded approach.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ But you don't know how exactly long the update and the physics take. If you set it up to draw every 1/60 second, couldn't you miss a frame because you don't know how long the update and the physics take? The only way to fix this you would have to stop the update and physics midway in order to not miss the frame, which would result in the same problem as my concept has. \$\endgroup\$ – Dolfos Aug 11 '18 at 3:27
  • 1
    \$\begingroup\$ In fact, for any physics simulation, you should not use a variable timestep, you should have a fixed timestep, and you should make sure that your game can support that fixed timestep. This is the best way to make sure that your players will have a smooth experience. And to fix the issue you mention: since you know if you'll have time to update the physics or not (because your DT is fixed), you can interpolate the state between the current state and the previous state, and draw this. \$\endgroup\$ – Vaillancourt Aug 11 '18 at 3:33
  • \$\begingroup\$ There are other approaches that avoid the "stop the update" problem - most notably, rather than modifying the state, you do the changes in a copy of the state (or as much of a copy as you need). This also allows some fun gameplay elements for a certain kind of game, and make multiplayer code a lot simpler. \$\endgroup\$ – Luaan Aug 14 '18 at 7:55
1
\$\begingroup\$

Just to expand on the other answers a bit:

Unity and Unreal both use separate threads for update (typically called the "game thread") & render, specifically to keep them from slowing each other down. You'll typically see the game rendering lagging a frame behind update / physics because of this.

In Unity, graphics operations are internally queued up in a device & API-agnostic queue in the main thread, and then dispatched by the render thread. The CPU overhead for that is minimal. This also allows the render thread to fast-forward through the queue if the render thread gets too far behind. Nothing new here, but synchronization can be challenging. Typically, the time to populate the queue is minimal, and takes far less than actually dispatching to the GPU.

This two-thread arrangement is very common. But, things are changing.

In Unity's the new(ish) job system, candidate operations can be automatically vectorized to take advantage of all available CPU cores. This typically means SIMD-style vectorization of identical operations on different GameObjects & components.

I'm not sure of the state of Epic's threading model, but last I checked this was a competitive advantage of Unity.

Implementing this in your own engine is not impossible, nor even extremely difficult. Keeping your thread sync points to a minimum, use of lightweight synchronization primitives and data structures and a very detailed sequence diagram will help.

If using multiple render threads, be aware that only the explicit APIs support actually rendering in that fashion, and it can actually be slower in some circumstances. My preferred approach is that used by Unity: threads populate a priority queue, while a dedicated thread actually dispatches the commands to the GPU driver. Keeping things in the proper order can be an issue, but is a solvable problem.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

I was, and I am thinking about this a lot. A couple of years ago I did some browser project and separating the loops, it was OK.

And if you for example have a server/client game, there are already at minimum 2 game loops. The server loop is calculating and keeping the state, sending changes to the client and then the client renders them in its own loop.
I'm not an expert and I think the only problem can be when some object should be rendered only very short time that it can be already destroyed in the game loop and never shows in the render loop, but I think it can be achieved by other solutions.

Here are some references for separating loops ideas:

and I found some references for nested loops:

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.