Eliminating input lag WITH VSync on—does this method work?

A place for people with an interest in developing new shmups.
Post Reply
Hakuromatsu
Posts: 3
Joined: Fri Sep 30, 2011 2:59 am

Eliminating input lag WITH VSync on—does this method work?

Post by Hakuromatsu »

Hi all! :D

I thought to ask about this on Shmups Forum because I've seen some folks here very educated on VSync input lag (and this sub is surprisingly active for a niche of a niche, wow). So, I'm building a danmaku engine and am looking at doing everything within my power to make "VSync On" the default (and therefore making sure input lag is negligible). I have a solution in mind, but it feels...too easy, and too obvious, like I'm missing some drawback.

The idea is this (abstracted) loop of events:
1. Process bullets
1a. Move bullets
1b. First pass of bullet collision detection (quick spatial check to eliminate ~95% of bullets)
2. Wait for screen refresh
3. Screen refresh
4. Fetch player input
4a. Move player
5. Second pass of bullet collision detection (precise check for remaining ~5% of bullets)
6. Respond to collisions

The idea being that collision is always visible on monitor before the collision is actually detected by the engine; the player has a full frame (plus some negligibly small number of microseconds between step #3 and step #4) to react to impending bullets.

The drawback I see is that there can be a visible collision after step #3 that the player moves away from in step #4a, leaving a false positive collision visible on monitor for a full frame. But for me that's okay, since the joy of danmaku is escaping from close shaves.

What other drawbacks do you see? Is there something insurmountable? Or something that can be improved on? TIA!

EDIT: Alternate idea I'm thinking of:
Spoiler
1. Process bullets
1a. Move bullets
1b. First pass of bullet collision detection (quick spatial check to eliminate ~95% of bullets)
2. Fetch player input
2a. Move player
3. Fetch player input again at regular intervals while waiting for screen refresh
3a. Update/change player movement accordingly

4. Screen refresh
5. Fetch player input one last time
5a. Update/change player movement one last time
6. Second pass of bullet collision detection (precise check for remaining ~5% of bullets)
7. Respond to collisions
Cagar
Posts: 2234
Joined: Fri Nov 25, 2011 5:30 pm

Re: Eliminating input lag WITH VSync on—does this method wor

Post by Cagar »

Can't wait for the perfect game loop V-sync experts in Shmups Chat to get on this one.
I'm really curious about it.
From what I gathered, it should be possible to eliminate the actual input lag, not just make it artificially irrelevant.
What are you releasing your game for? (or imaginary game)
User avatar
trap15
Posts: 7835
Joined: Mon Aug 31, 2009 4:13 am
Location: 東京都杉並区
Contact:

Re: Eliminating input lag WITH VSync on—does this method wor

Post by trap15 »

I don't see how that'd eliminate input lag in any way? You'd just have bullet collisions 1 frame "behind" their visual position, which is more disorienting than anything. And splitting up the passes only adds error at best.
@trap0xf | daifukkat.su/blog | scores | FIRE LANCER
<S.Yagawa> I like the challenge of "doing the impossible" with older hardware, and pushing it as far as it can go.
Hakuromatsu
Posts: 3
Joined: Fri Sep 30, 2011 2:59 am

Re: Eliminating input lag WITH VSync on—does this method wor

Post by Hakuromatsu »

Thanks for the reponses!
trap15 wrote:I don't see how that'd eliminate input lag in any way? You'd just have bullet collisions 1 frame "behind" their visual position, which is more disorienting than anything.
Did you see the spoiler I edited into the first post?—I'm looking to update player input and position as late in the frame as possible to cut down on false positive collisions in the next frame.

Example:
1. Screen refresh—beginning of Frame #1; "Bullet A" is now one frame away from colliding with player unless player moves left, and player can see this
2. Bullets are processed—Bullet A is moved into a position that would collide with player, but collision isn't detected yet
3. Long gap (waiting for screen refresh)
4. Player position update—if "left" has been inputted, player moves left
5. Short gap (ideally <100 microseconds)
6. Screen refresh—beginning of Frame #2; Bullet A position is now exactly as shown on monitor; player position is now exactly as shown on monitor unless player changed input during the short gap
7. Final player position update—player position is still exactly as shown on monitor unless the player changed input since the last player position position update
8. Collision detection—if left has been inputted since the beginning of Frame #1, there's no collision with Bullet A

So for the last ~1% of a frame, player movement won't be (visually) registered in the next screen refresh and a false positive collision will be shown for the entirety of the next frame. But, ideally, all player movement in the first ~99% of the frame is visually shown in the next frame. So still the potential for "output lag," but doesn't this eliminate all input lag? (i.e. doesn't the player always have a full frame to react to collisions that will happen in the next frame?)
And splitting up the passes only adds error at best.
Don't worry about that; I shouldn't have bothered writing it. The collision detection I have is accurate and not the problem I'm trying to solve.
Ixmucane2
Posts: 773
Joined: Mon Jan 19, 2009 3:26 pm
Location: stuck at the continue prompt

Re: Eliminating input lag WITH VSync on—does this method wor

Post by Ixmucane2 »

Never depend on random delays, for example collecting different player input depending on how long drawing a frame takes. The game needs to be reliable.

You seem to be attempting to process input at a higher frame rate than output (apparently, double) but doing so doesn't eliminate lag, it only allows more input per frame. You also confusingly split game state updates between the slow rate and the fast rate, causing great complication and probably horrible bugs.

I suggest running everything at the highest possible frame rate, i.e. the Vsync rate.
Example game loop:
  • Register player input.
  • Given the new player input and the current enemy state, move everything and do all collision detection computing a new game state, with a fixed time step of 1 frame (e.g. 1/60th of a second).
  • Draw the new game state to the back buffer.
  • twiddle thumbs waiting for the frame timer, then when it comes swap buffers, which should be very fast (causing very little jitter in the subsequent input collection).
rfeese
Posts: 30
Joined: Fri Nov 15, 2013 4:56 pm

Re: Eliminating input lag WITH VSync on—does this method wor

Post by rfeese »

There are different strategies for implementing a game loop. Most of the time around here I believe the developers are targeting a certain frame rate and use a fixed time-step. I wanted to use variable time step in mine and after reading the fix your timestep article, I have arrived at a mixture (variable rounds of small fixed timestep). Basically, I have my engine process in small fixed time increments as many times as it can between screen refreshes. Doing things this way made my game run more smoothly and consistently.

I think you can probably do complete collision detection in one step. You should be able to use your "spacial check" optimization and then "precise check" all in one step. I'm doing this in my game with a grid that breaks down the space (spatial partitioning) in which I check for objects colliding with each other. I believe this is a well known optimization strategy around here.
e_tank
Posts: 148
Joined: Wed Apr 23, 2008 5:04 am

Re: Eliminating input lag WITH VSync on—does this method wor

Post by e_tank »

@Hakuromatsu
i read your post a couple times and i'm having a hard time following you here, maybe it's me (i'll try and reread it when i'm not so tired, i'm about to go to sleep) but i'm with trap15 in that the way described it sounds like your player ship is essentially getting processed 1 frame behind the other entities, which doesn't seem like a good idea to me.

however, this method reminds me of something similar that john carmack described and christer ericson touched on too, which is to delay polling input and player response to right before scanout of the active display begins. the problem with these methods are that they aren't very practical to do on pc, it's really a method more suitable for fixed hardware like consoles. unless you've got a way to query the current scanout position, which i'm pretty sure isn't possible w/o some kind of custom/hacked display drivers, there simply isn't an easy or reliable way to get the timing right that i'm aware of. you _might_ be able to use opengl timers to accomplish something like this, but i don't know enough about them to give you a yes or no on that (i only gave that article i linked to a cursory glance).

imho it's prob not worth the effort, besides we're talking about eliminating up to 1 frame of latency at best, on avg it'll be less. i'm all for grabbing low hanging fruit, but if you ask me this ain't it. i think you'd be much better off spending your time optimizing your display code for minimum latency, really get a good grasp on what your gpu is actually doing when you submit draw cmds and maybe experiment with using fences in order reduce excessive buffering and/or to be able to achieve immediate rendering. retroarch and i think the gfx-rs gfx api both are able to do this, i'd look at what they're doing as a starting point.

better yet, just have your game target libretro. that way you leave all the nasty details of putting frames on to the screen as fast as possible on virtually every platform out there to the expert retroarch devs, as well as the end users who can configure it optimally for their specific setups.

p.s. if you are going to try and use the approach described by carmack & ericson, rather than doing 2 pass collision detection it might be simpler to just expand the colliding shape of your player by the max distance it can travel in a frame, record all collisions as possible collisions in a list, then when you finally poll input shrink the colliding shape of your player to actual size and its true position and check it again against the list of possible colliding entities. in a way that's also 2 passes, but more work will get done in the first and there's no need for a broad phase.

p.s.s. for those of you thinking of using a non-naive broad phase for collision detection (aka some type of spatial partitioning), you may not actually need it. it's common for ppl to think they need to have one when in reality their game might even be faster w/o. broad phases will only provide a speed up if your narrow phase collision tests are complex and/or if you need to test a lot of entities against a lot of other entities. for your avg danmaku style stg neither of those apply. most tend to use axis aligned bounding boxes or circles for collision tests, and most entities on screen are enemy_bullets which typically only need to be checked against a single entity (the player). a broad phase does absolutely nothing for you in that situation. it will help cull player_bullets vs enemy tests, but unless your player is pumping out massive amounts of bullets and/or you've got a ton of enemies on screen at once the difference, at least on modern hardware, is probably going to be negligible.

p.s.s.s. for those of you using the methods in the article written by glenn fiedler re time steps that rfeese linked to, keep in mind the final method he describes may not be the best choice for an stg. that method will smooth out the motion of entities on screen but it does so at a cost of up to 1 frame of latency.
Post Reply