Skip to content

perf(P1): avoid redundant software waits after VSync presentation - #283

Closed
Roxas2712 wants to merge 1 commit into
UNDERdecoded:mainfrom
Roxas2712:codex/upstream-perf-p1
Closed

Roxas2712 wants to merge 1 commit into
UNDERdecoded:mainfrom
Roxas2712:codex/upstream-perf-p1

Conversation

@Roxas2712

@Roxas2712 Roxas2712 commented Oct 26, 2026 •

Copy link
Copy Markdown

The software frame deadline can add a second wait after a VSync-paced present. Track actual presentation and skip that wait when VSync is active and the FPS cap is at least the reported display refresh rate. Keep the carried software deadline, short sleep chunks and stall re-anchor for VSync off, unknown/faster displays and frames without presentation.

Independent patch against main 13af468; no compatibility prerequisite stack is included. Sites: main.lua:1264 and :1305, src/core/FrameCap.lua:56. Existing rendering/update order, simulation timing, options and mod callback sites are unchanged. Display flags are sampled once per second; provider/VSync changes invalidate the sample. Other refresh changes are observed at the next sample.

Rollback switch: require("src.core.FrameCap").vsyncPacing = false (default true). F11 adds frame pacing: sleep alongside the existing present section. docs/frame-pacing.md documents behavior and the guarded reproducible native probe.

Validation:

  • 27 pacing assertions pass on this standalone patch and the fork. They execute the real main run-loop body and cover VSync/adaptive/multiple intervals, lower caps, unknown rate, no present/provider, disable, display resampling, VSync transitions and stall recovery.
  • Standalone: 65/75 engine suites versus 64/74 on unchanged main, with exactly the same 27 inherited FAIL lines and no additions/removals. SDK 3/3.
  • Composed fork: 418/418 engine suites, SDK 3/3, gallery 253/253; 200 contract comparisons / 400 isolated loader runs against pinned 535a5ec088c1ae1bf4d91dd3e35a56f64cf46d91. The authenticated external package gate passes its allowed named intermediate sprite-module gap; full follower acceptance is still open.

Actual desktop FrameProfile before/after on this standalone source (macOS arm64, 60 Hz, VSync 1, cap 60, 120 warm-up + 120 measured frames per state):

Backend Software pacing ms/frame off → on Present ms/frame off → on
LÖVE 11.5 OpenGL 8.92 → 0.01 7.67 → 16.58
LÖVE 12 Metal 13.19 → 0.02 3.37 → 16.84

Enabled runs made zero extra sleep calls. Process CPU means were 1.233 → 0.714 ms/frame (OpenGL) and 0.934 → 0.818 (Metal). Both remained near 60 FPS; each independent enabled run had one isolated long interval (30.87/50.93 ms), without a repeating 60/30 cadence. The separate composed-fork short runs had no interval above 1.5 display periods. These are blank-window pacing measurements, not a universal FPS/CPU claim or loaded-world acceptance. Physical handheld/Android measurements: not measured. Raw profile logs and source-file SHA-256 receipts are retained by the guarded tool.

Original additions by Roxas2712 are offered to Cedric / UNDERdecoded under the specific PR contribution permission at https://github.com/Roxas2712/Gen2Recomped/blob/4fb81fbf/LICENSE-ROXAS2712.md, with visible contributor credit. Existing rights, notices, credits and earlier permissions remain effective.

Final composed acceptance and native Emerald profile

The completed composed fork runtime 9532ee36 passes 493/493 engine suites, 3 SDK suites, 253 gallery checks, 200 pinned API-3 comparisons and all 17 unchanged external entrypoints in complete mode. The complete public performance stack in #323 (runtime a620d0c7) passes 179/179 suites, 3 SDK suites, 253 gallery checks, 48 contract comparisons and all 17 complete entrypoints. It reuses repair PRs #128–#134 and #294. These results supplement the older standalone/baseline snapshots above; the eleven inherited failures are resolved on that final stack.

Real imported Emerald / Pacifidlog Town, actual native Game/Overworld and ordinary DRAMATIC_SHAPE loading on Apple M2 ARM64, LÖVE 12 Metal (profile source 79ff56cb): FrameProfile frame pacing: sleep = 10.7076 → 0.3172 ms/frame, flag off → on, 240 measured frames per state and two real 120-frame profile windows. This composed pacing section includes the P2 idle-GC work. At VSync 1 / live cap 60, interval p95 is 18.241 → 17.859 ms; the enabled p99 is 18.598 ms in this sample.

The guarded full-game starter freezes committed sources and uses a fresh owned ROM import/profile. It explicitly admits scripted QA into the existing native pacing/idle-GC body in its frozen copy; the timing implementation is unchanged. P1 uses live cap 60 / VSync 1, other phases the normalized native cap 160 / VSync off. The additional OpenGL replay passes all 14 native phases, then is stopped by the shared 20 GiB reserve during the optional voxel replay; no complete OpenGL voxel result is claimed.

These are sequential wall/submission-time samples, including slower values, not GPU completion times or a causal universal FPS gain. See the programme ledger and all samples/source hashes. Physical Android/Switch/handheld timings: not measured; the measured Mac is ARM64.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant