• 12
• 14
• 13
• 10
• 11

# responsiveness of main game loop designs

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

## Recommended Posts

for maximum responsiveness, it seems you must render after every update, and before each input.

can anyone think of an example that doesn't do this without being less responsive?

you have to render before each input, so the user knows whats going on, so they can respond to the situation.

you have to get input before or during each update, to update the player entity.

and you have to render after each update to display the results of user input (and update in general) in as timely a manner as possible.

so for maximum responsiveness, i don't see how this could be avoided.

can anybody think of anything that would/could be different, but not less responsive?

i can't think of anything that would not be less responsive.

##### Share on other sites

>> You're overthinking this.

<g>  probably a good thing.  i'm one of those people who likes to boil things down to their essence.   sometimes you discover interesting underlying truths.

like it seems you can't monkey around with the basic render-input-update cycle without negatively impacting responsiveness. never even occurred to me, but it appears to be true.

and for a game that doesn't require dx10 or 11 or 12 (pick any one), higher versions of Dx are just a possible optimization method, not a requirement (in retrospect this is pretty obvious).

and for a game where a single thread can do it all, multi-threading is likewise just a possible optimization method, not a requirement (in retrospect this is pretty obvious too).

and it would seem you should always be developing (testing actually) on the target PC, which will likely be an "above average" game capable PC (depending on game sys reqts and dev time), and always maintain your target FPS at all times on the target machine - IE optimize where needed, when needed, and as needed as you go along. which means nothing is considered to be "done" until its fast enough for release.  this avoids 11th hour optimizations.
Edited by Norman Barrows

##### Share on other sites

>>>> can anyone think of an example that doesn't do this without being less responsive?

>> A game running at 144hz with a 2 frame render lag (~7 ms per frame, or 14ms latency with lag) is still more responsive than a 60hz game (~16ms latency).

that sounds like one right there to me.

thanks all!

##### Share on other sites

In your other thread you brought up destiny and their simultaneous update/drawing routines and how this will increase latency. This isn't necessarily true and becomes obvious once we draw some timelines.

Let's say we've got three CPU tasks in a frame, with these costs, which must occur in this serial order:
Poll Inputs: 1ms
Update Simulation: 15ms
Draw Scene: 17ms

        0ms      1ms        16ms     33ms     34ms       49ms     66ms
Core1:  | Poll#1 | Update#1 | Draw#1 | Poll#2 | Update#2 | Draw#2 |

Dual threaded, no buffering / pipelining:

        0ms      1ms        16ms     33ms     34ms       49ms     66ms
Core1:  | Poll#1 | Update#1 | Idle   | Poll#2 | Update#2 | Idle   |
Core2:  | Idle              | Draw#1 | Idle              | Draw#2 |

        0ms      1ms        16ms     17ms       32ms   33ms
Core1:  | Poll#1 | Update#1 | Poll#2 | Update#2 | Idle | Poll#3...
0ms                 16ms                       33ms       50ms
Core2:  | Idle              | Draw#1                   | Draw#2   |

Single-threaded, this takes 66ms for two frames.
Putting draw and update onto their own threads, but enforcing mutual exclusion still takes 66ms for two frames.
Running Update and Draw in parallel, by pipelining two frames together, reduces the critical path to 50ms for two frames if you include the pipeline warmup time. Once the pipeline is warmed up, it's actually just 34ms per two frames from that point onwards!

There's still no extra latency for the user -- the path from input polling to finished drawing is 33ms in all three situations.

The only difference is that first two options pump frames at ~30Hz, while the third option pumps frames at ~59Hz - so it's increased framerate while leaving input latency exactly the same as it was before.

Now, extending this. Let's say that your Draw cost is still 17ms, but your Update cost is only 2ms. If we pipeline this as above, then the critical path goes through the Draw tasks, so the best framerate we can achieve is still ~59Hz as above.

So, seeing that our user is only able to perceive the game world at 59Hz... you could argue that polling any faster than this is not required. We can then use the exact same timeline as above, but replace the |Update#N| block with |Update[#N - #N+8)| , and replace Draw#1/Draw#2 with Draw#8/Draw#16 - i.e. we do 8 updates per poll/draw.

If you accept the argument that there's no need to poll faster than the drawing rate, then this will be just as responsive as before, even though we're "dropping" seven out of eight frames :)

Edited by Hodgman

##### Share on other sites

>> If you accept the argument that there's no need to poll faster than the drawing rate

assuming you update no faster than you poll or render.

just cause you can only draw the screen once every 8 games turns doesn't mean you should let the computer move every turn and only let the user move every 8 game turns.

you have to preserve the fair play of "its my turn, ok, now its your turn, ok now its my turn again."

"i cant draw fast enough to show you whats going on - so you don't get a turn until i can" - that's just silly.

yet from what you say, it seems folks actually do this. no wonder games are such piles of crap these days.

Edited by Norman Barrows