Merge pull request #2073 from 1Jamie/android-xbox-vsync

disables adaptive vsync as an option since few platforms support it and it causes issues on ones that incorrectly detect it as a supported
This commit is contained in:
bryanthaboi
2026-09-01 15:49:21 -04:00
committed by GitHub
4 changed files with 30 additions and 19 deletions
+13 -3
View File
@@ -1,6 +1,10 @@
local VSync = {}
VSync.MODES = { "on", "off", "adaptive" }
-- Adaptive (swap interval -1) is parked. EGL/KMSDRM reject it, and offering
-- it on a mixed matrix sent PresentProbe into fail-closed after one OPTIONS
-- step. Saved "adaptive" keys fold to ON. Restore by putting "adaptive"
-- back on MODES and dropping the fold in normalize().
VSync.MODES = { "on", "off" }
local INTERVAL = { on = 1, off = 0, adaptive = -1 }
local LABELS = { on = "ON", off = "OFF", adaptive = "ADAPTIVE" }
@@ -15,7 +19,8 @@ local live = nil
local function fromInterval(interval)
interval = tonumber(interval)
if not interval then return nil end
if interval < 0 then return "adaptive" end
-- Parked adaptive: a driver still reporting -1 is treated as ON.
if interval < 0 then return "on" end
if interval == 0 then return "off" end
return "on"
end
@@ -33,6 +38,7 @@ function VSync.default()
end
function VSync.normalize(mode)
if mode == "adaptive" then return "on" end
for _, m in ipairs(VSync.MODES) do
if mode == m then return m end
end
@@ -73,7 +79,11 @@ function VSync.apply(mode)
end
function VSync.applyOptions(opts)
VSync.apply(opts and opts.vsync)
local mode = VSync.apply(opts and opts.vsync)
if type(opts) == "table" and opts.vsync == "adaptive" then
opts.vsync = mode
end
return mode
end
-- Drop the live swap interval without changing wanted and without re-entering
+2 -2
View File
@@ -109,8 +109,8 @@ VSync.apply("on")
PresentProbe._testSetState({ needsSoftwareCap = true, gated = false })
T.check(PresentSync.vsyncEnableBlocked(), "broken sync blocks enabling vsync")
T.check(PresentSync.vsyncStepAllowed("on", 1), "but one step to OFF is allowed")
T.check(not PresentSync.vsyncStepAllowed("on", -1),
"while a step that stays on/adaptive is not")
T.check(PresentSync.vsyncStepAllowed("on", -1),
"and stepping back is also OFF")
-- FixedStep snaps wall-clock dt, then applies speed (not the reverse).
FixedStep.refreshPeriod = 1 / 60
+14 -11
View File
@@ -5,27 +5,26 @@ local VSync = require("src.core.VSync")
VSync.reset()
T.same(VSync.MODES, { "on", "off", "adaptive" }, "three modes, in row order")
T.same(VSync.MODES, { "on", "off" }, "two modes, in row order")
T.eq(VSync.default(), "on", "with nothing to ask, vsync reads ON")
T.eq(VSync.normalize(nil), "on", "so a save with no key is ON")
T.eq(VSync.normalize("junk"), "on", "and so is garbage")
T.eq(VSync.normalize("adaptive"), "adaptive", "a real mode is kept")
T.eq(VSync.normalize("adaptive"), "on", "a parked adaptive key folds to ON")
T.eq(VSync.label("on"), "ON", "ON prints as ON")
T.eq(VSync.label("off"), "OFF", "OFF as OFF")
T.eq(VSync.label("adaptive"), "ADAPTIVE", "and ADAPTIVE spells itself out")
T.eq(VSync.label("adaptive"), "ON", "and a parked adaptive key prints as ON")
T.eq(VSync.cycle("on", 1), "off", "ON cycles to OFF")
T.eq(VSync.cycle("off", 1), "adaptive", "OFF to ADAPTIVE")
T.eq(VSync.cycle("adaptive", 1), "on", "and ADAPTIVE wraps to ON")
T.eq(VSync.cycle("on", -1), "adaptive", "stepping back wraps the other way")
T.eq(VSync.cycle("off", 1), "on", "OFF wraps to ON")
T.eq(VSync.cycle("on", -1), "off", "stepping back is also OFF")
T.eq(VSync.cycle(nil, 1), "off", "a missing key normalizes before it steps")
T.eq(VSync.apply("off"), "off", "apply answers with what it stored")
T.eq(VSync.isOn(), false, "and OFF is not on")
T.eq(VSync.apply("adaptive"), "adaptive", "adaptive applies")
T.eq(VSync.isOn(), true, "and counts as on: it still syncs a frame in time")
T.eq(VSync.apply("adaptive"), "on", "apply(adaptive) becomes ON")
T.eq(VSync.isOn(), true, "and counts as on")
VSync.applyOptions({})
T.eq(VSync.isOn(), true, "an options table with no key falls back to the boot mode")
@@ -43,11 +42,15 @@ T.eq(VSync.isOn(), false, "and the run loop sees vsync off")
VSync.apply("on")
T.eq(calls[#calls], 1, "ON sets the swap interval to 1")
T.eq(VSync.isOn(), true, "and the loop sees vsync on")
VSync.apply("adaptive")
T.eq(calls[#calls], -1, "ADAPTIVE asks for the late-swap interval")
calls = {}
T.eq(VSync.apply("adaptive"), "on", "parked adaptive applies as ON")
T.eq(calls[#calls], 1, "and asks for interval 1, never -1")
VSync.applyOptions({ vsync = "off" })
T.eq(calls[#calls], 0, "and OFF turns it off")
T.eq(#calls, 3, "one driver call per apply, no repeats")
local opts = { vsync = "adaptive" }
T.eq(VSync.applyOptions(opts), "on", "applyOptions folds a saved adaptive key")
T.eq(opts.vsync, "on", "and rewrites it so later writes stay on the on/off ring")
-- Driver reports 0 after we asked for ON (vblank_mode=0 / Gamescope quirk):
-- isOn stays true so PresentProbe still tries a real wait on native X11.
+1 -3
View File
@@ -421,9 +421,7 @@ orow(om, "vsync").step(om.game, 1)
check(om.game.save.options.vsync == "off", "VSYNC steps ON to OFF")
check(orow(om, "vsync").value(om.game) == "OFF", "and renders it")
orow(om, "vsync").step(om.game, 1)
check(om.game.save.options.vsync == "adaptive", "then OFF to ADAPTIVE")
orow(om, "vsync").step(om.game, 1)
check(om.game.save.options.vsync == "on", "and ADAPTIVE wraps to ON")
check(om.game.save.options.vsync == "on", "then OFF wraps to ON")
do
local PS = require("src.core.PresentSync")