[programming] Higher refresh rates on input and game update

Advanced display talk, display hackers, advanced game programmers, scientists, display researchers, display manufacturers, vision researchers & Advanced Display Articles on Blur Busters. The masters on Blur Busters.
User avatar
sharknice
Posts: 292
Joined: 23 Dec 2013, 17:16
Location: Minnesota
Contact:

Re: Higher refresh rates on input and game update [programmi

Post by sharknice » 05 Jan 2014, 06:25

flood wrote:
Ahigh wrote: pseudocode:

Code: Select all

unsigned int msec( void )
{
    return real_time_clock_in_milliseconds;
}

void update( void )
{
    const unsigned int game_update_dtms = 4;
    unsigned int ms = msec();

    while( game_update_ms < ms ) // iterates multiple times per visual frame
    {
        ms = msec();
        // state of input can be different on each iteration
        grab_latest_input_state( game_update_ms );
        game_update( game_update_dtms );
        save_position_of_all_game_objects( game_update_ms );
        game_update_ms += game_update_dtms;
    }

    // interpolate from previous two game state as visuals are on average game_update_dtms/2 older than game state
    assert( ms <= game_update_ms );
    interpolate_visually_displayed_position_of_all_game_objects_for_visuals( ms );

    draw_everything(); // always drawing position of game objects at or behind their most current game state at 4ms boundaries
}
You typically also have a maximum number of iterations and some skew for when the game gets paused and what-not but that's beyond the scope of this discussion.
Not quite understanding this. How does the program know when to leave the game update while loop?
it seems what's wanted is something like
(g for game update)
g-g-g-draw frame 1-g-g-draw frame 2-g-g-g-draw frame 3 etc...
I don't quite understand it either. I think what you would do is have a maximum amount of time you want to run the update loop before drawing the frame. I think that is what this is doing but I don't understand how it is calculating that amount of time.

btw Rush 2049 on the Dreamcast (the addition of wings was amazing) is my all time favorite racing game and I have been waiting FOREVER for a real sequel of some sort. I'm keeping a close eye on Distance which is an indy game that is somewhat similar.

User avatar
Ahigh
Posts: 95
Joined: 17 Dec 2013, 19:22

Re: Higher refresh rates on input and game update [programmi

Post by Ahigh » 05 Jan 2014, 15:51

flood wrote:
Ahigh wrote: pseudocode:

Code: Select all

unsigned int msec( void )
{
    return real_time_clock_in_milliseconds;
}

void update( void )
{
    const unsigned int game_update_dtms = 4;
    unsigned int ms = msec();

    while( game_update_ms < ms ) // iterates multiple times per visual frame
    {
        ms = msec();
        // state of input can be different on each iteration
        grab_latest_input_state( game_update_ms );
        game_update( game_update_dtms );
        save_position_of_all_game_objects( game_update_ms );
        game_update_ms += game_update_dtms;
    }

    // interpolate from previous two game state as visuals are on average game_update_dtms/2 older than game state
    assert( ms <= game_update_ms );
    interpolate_visually_displayed_position_of_all_game_objects_for_visuals( ms );

    draw_everything(); // always drawing position of game objects at or behind their most current game state at 4ms boundaries
}
You typically also have a maximum number of iterations and some skew for when the game gets paused and what-not but that's beyond the scope of this discussion.
Not quite understanding this. How does the program know when to leave the game update while loop?
it seems what's wanted is something like
(g for game update)
g-g-g-draw frame 1-g-g-draw frame 2-g-g-g-draw frame 3 etc...
Let me answer with a specific example, and maybe that will help.

I typically update the game update loop with a fixed delta time in integral milliseconds.

So let's just say I choose to update the game at every 4 milliseconds.

I have a separate thread with a dummy window that takes USB input data from the keyboard and from the mouse. This thread operates at a maximum of 1000hz when the mouse is moving violently. But normally operates at a rate much lower than that when there is not much data coming in. It is basically an interrupt driven thread. It wakes up on hardware interrupt, takes input data, stuff it into a memory resident FIFO and then it's done.

The graphics and game update are in a single thread. Each time the graphics draws, the time stamp for the graphics is between 0 and 4 milliseconds BEHIND the game update time stamp. So graphics, in general, renders an AVERAGE of 2ms behind the latest input data. This is because graphics intrinsically has to be clamped to the nearest 16ms, and my latest input data may be up to 4ms "fresher" and therefore should not be applied to the latest graphics output.

So the main loop doing game update and graphics update is going to do something like

game_update( 4 ); game_update( 8 ); game_update( 12 ); game_update( 16 ); game_update( 20 );
graphics_update( 16.66 );
game_update( 24 ); game_update( 28 ); game_update( 32 ); game_update( 36 );
graphics_update( 33.33 );
game_update( 40 ); game_update( 44 ); game_update( 48 ); game_update( 52 );
graphics_update( 50.00 );
game_update( 56 ); game_update( 60 ); game_update( 64 ); game_update( 68 );
graphics_update( 66.66 );

Each time the graphics updates, it looks at the position and orientation of each game object for the previous TWO game_update iterations and it interpolates between those two positions to get an accurate portrayal of where the object should be for that visual frame. This is to get perfectly smooth temporal movement data.

So the first graphics update has a time stamp of 16.66 ms. 16.66 ms - 16 ms = .66 ms. 0.66 / 4.0 = 0.165

So you blend 16.5% of game_update( 20 ) 's positions and (100% - 16.5% =) 83.5% of game_update( 16 ) to get an interpolated position that represents 0.66 ms away from game_update( 16 )'s resulting position and orientation for each game object and 3.33 ms away from game_update( 20 )'s resulting position and orientation.

You generally want to use integral delta-time on the game_update loop and more accurate floating point on the graphics to get the smoothest possible movements from your interpolated results.

I hope this is helpful. You would be amazed how many game programmers consider these details unimportant. But the top fast-moving game programmers all understand this stuff, I can assure you. When I worked for Red 5 Studios with the former leads from the World of Warcraft, nobody cared. So it's not required for a game that makes history. Only for games that require serious hand-to-eye coordination and rapid, I guess, "twitch skill" as a component of gameplay. If you just kill boars all day, this is just a bunch of garbage that doesn't matter.

flood
Posts: 926
Joined: 21 Dec 2013, 01:25

Re: Higher refresh rates on input and game update [programmi

Post by flood » 06 Jan 2014, 19:27

flood wrote: but what can you do if the rendering takes a long time (10ms), which is totally normal for modern 3d games? how can you update the game loop without threads or something
I guess my question remains then...

User avatar
Chief Blur Buster
Site Admin
Posts: 8804
Joined: 05 Dec 2013, 15:44
Location: Toronto / Hamilton, Ontario, Canada
Contact:

Re: Higher refresh rates on input and game update [programmi

Post by Chief Blur Buster » 06 Jan 2014, 21:31

flood wrote:
flood wrote: but what can you do if the rendering takes a long time (10ms), which is totally normal for modern 3d games? how can you update the game loop without threads or something
I guess my question remains then...
Input reads are typically queued for the subsequent frame. The freshest input saved from the other thread, at the time of beginning to render the frame, is the input that is used.

My understanding is that the game loop can then read the queue of input, and use the most recent input found in the queue. Or if smoothing is enabled (in a game option), it would do an averaging algorithm on several preceding input reads.

Render variances can mean skew between input read timings and frame presentation timings. This is a potential source of microstutter in many game engines.
Head of Blur Busters - BlurBusters.com | TestUFO.com | Follow @BlurBusters on Twitter

       To support Blur Busters:
       • Official List of Best Gaming Monitors
       • List of G-SYNC Monitors
       • List of FreeSync Monitors
       • List of Ultrawide Monitors

User avatar
Ahigh
Posts: 95
Joined: 17 Dec 2013, 19:22

Re: Higher refresh rates on input and game update [programmi

Post by Ahigh » 11 Jan 2014, 11:19

Chief Blur Buster wrote:
flood wrote:
flood wrote: My understanding is that the game loop can then read the queue of input, and use the most recent input found in the queue.
The game update always uses old input data. The only time the most recent data can be used is if the last iteration of the game update per visual frame. Input data is generally never interpolated. It could be, but it has never made sense for me to do it that I can recall. The time value of the input loop is passed to the routine to obtain the input sample from the input queue. You are simulating an environment with increasing precision as you take more steps (from 1ms steps for 1000hz to 10ms steps to do 100hz). The real time clock, generally, has no relevance whatsoever to the game update loop itself. Instead, it just gets the input data that corresponds to that time value as it steps through integral milliseconds for the game update process to step up towards the current real time clock in integral steps for the game update processing. In my opinion, all games should have a game update frequency no slower than 100hz and all games should use integral millisecond time values at the top-level update.

Interpolation happens when taking the resulting positions and drawing the game's objects in the right place. Not on the input data.

Using my suggested technique for integral ms game updates, game update frequencies turn out to be ten possible values. You can use floating point dtms if you want, but it is nice to have your delta time (fixed as constant) in milliseconds at a small integral number in order to make the game update process more predictable and to prevent errors that can occur. Especially when you want to have things like instant replay and reproduce-able results, this can be a great benefit.

1000Hz -> const int game_dtms = 1
500Hz
333.33Hz
250Hz
200Hz -> const int game_dtms = 5
166.67Hz
142.85Hz
125Hz
111.11Hz
100Hz -> const int game_dtms = 10

User avatar
Ahigh
Posts: 95
Joined: 17 Dec 2013, 19:22

Re: [programming] Higher refresh rates on input and game upd

Post by Ahigh » 16 Apr 2014, 03:19

I shared a link to this website to VPForums here

http://www.vpforums.org/index.php?showt ... 2&p=257320

Then here

http://www.vpforums.org/index.php?showt ... 6&p=261239

We see a developer using the same technique described in this post to update Visual Pinball's engine.

Kudo's to the developer, mukuste. One more person who understands how to do this now. Anyone else learns this technique from this post, I would be curious of your story for how it improves the quality of your game.

flood
Posts: 926
Joined: 21 Dec 2013, 01:25

Re: [programming] Higher refresh rates on input and game upd

Post by flood » 17 Apr 2014, 21:33

wow reading this again, now I understand exactly what you mean and it makes a lot of sense. Back then I was thinking about updating the game loop at fixed times literally.

What about multiplayer games like CS? I think there it would be advantageous to have two threads: one for the game loop and one for graphics. This would be beneficial as network performance would be independent of graphics performance. AFAIK, currently in the source engine, network performance can be bottlenecked by poor framerates

Post Reply