Fix to vsync measuring and detection and fixes fixestep so it snaps wallclock dt before applying speed

the display sync stuff i added was probing whether vsync was actually working, but it was measuring the wrong thing. during the probe we software-cap at 60 for safety, and the probe was looking at the gap between frames... which includes the sleep 😅 .....  so it always looked like sync was fine even when the driver was ignoring it. on something like the ally x on windows thats a real problem. vsync says on, probe says gated, we lift the cap and snap logic to the panel hz, then youre basically uncapped. at 2–4x that turns into hitching, dropped frames, dropped input, that weird half second freeze. speed swapping wasnt desyncing the driver, it was just making the bad path hurt more.
the solution is just we time present() itself now, not the gap after it, this way the warmup sleep cant fake a pass. if sync is unclear or broken we just stay on a capped 60 and dont snap logic. Also fixed fixedstep so it snaps wall clock dt before applying speed, so in general the 2-4x speed swaps dont screw the pacing math anymore
This commit is contained in:
1jamie
2026-08-30 11:12:19 -05:00
parent 308605fd61
commit f82f565cae
9 changed files with 181 additions and 35 deletions
+8 -2
View File
@@ -62,7 +62,7 @@ end
-- intended budget.
FixedStep.maxAccum = MAX_ACCUM
function FixedStep:update(dt)
function FixedStep:update(dt, speed)
-- A hitch's oversized dt lands on the frame AFTER discardCatchup was
-- called (the hitch itself already ran inside the current step); absorb
-- that one frame as a single step instead of the normal accumulator so
@@ -74,6 +74,12 @@ function FixedStep:update(dt)
self.callback(self.STEP)
return
end
-- Snap/smooth against the wall-clock frame dt first. Game speed is a
-- multiplier on how many logic steps that real frame buys — applying it
-- before refresh-period snap made 2–4X look like multi-period frames and
-- destabilized pacing under DISPLAY sync.
speed = tonumber(speed) or 1
if speed < 1 then speed = 1 end
local period = self.refreshPeriod
local snapped = false
if period and dt > 0 then
@@ -104,7 +110,7 @@ function FixedStep:update(dt)
local target = phaseOffset(period, self.STEP)
self.accum = self.accum - self.accum % self.STEP + target
end
self.accum = math.min(self.accum + dt, self.maxAccum or MAX_ACCUM)
self.accum = math.min(self.accum + dt * speed, self.maxAccum or MAX_ACCUM)
while self.accum >= self.STEP - STEP_EPS do
self.accum = self.accum - self.STEP
self.callback(self.STEP)