From 5342fcbede37a165d2f9f4f61d2e0e70b67fcd1a Mon Sep 17 00:00:00 2001 From: 1jamie Date: Tue, 1 Sep 2026 14:40:50 -0500 Subject: [PATCH] disables adaptive vsync as an option since few platforms support it and it causes issues on them --- src/core/VSync.lua | 16 +++++++++++++--- tests/engine/present_sync_logic.lua | 4 ++-- tests/engine/vsync_option.lua | 25 ++++++++++++++----------- tests/mod_ui_tests.lua | 4 +--- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/core/VSync.lua b/src/core/VSync.lua index 4888a8e6..36fec77a 100644 --- a/src/core/VSync.lua +++ b/src/core/VSync.lua @@ -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 diff --git a/tests/engine/present_sync_logic.lua b/tests/engine/present_sync_logic.lua index f6160923..adf580ec 100644 --- a/tests/engine/present_sync_logic.lua +++ b/tests/engine/present_sync_logic.lua @@ -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 diff --git a/tests/engine/vsync_option.lua b/tests/engine/vsync_option.lua index bb54876e..e9a231fb 100644 --- a/tests/engine/vsync_option.lua +++ b/tests/engine/vsync_option.lua @@ -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. diff --git a/tests/mod_ui_tests.lua b/tests/mod_ui_tests.lua index 98ba16d2..bb9e7c2d 100644 --- a/tests/mod_ui_tests.lua +++ b/tests/mod_ui_tests.lua @@ -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")