Skip to content

fix(videoout): support permitted high-frame-rate output for Quake II - #3886

Merged
adriadam10 merged 7 commits into
boykopovar:mainfrom
PrintOrb:fix/videoout-high-frame-rate
Oct 12, 2026
Merged

adriadam10 merged 7 commits into
boykopovar:mainfrom
PrintOrb:fix/videoout-high-frame-rate

Conversation

@PrintOrb

@PrintOrb PrintOrb commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

What

Yamagi Quake II (PPSA99007) stops before its first frame on main a11c8f7f7:

[ps5-output-mode] target=120 support=80290016 preset=ffffffff vrr=ffffffff result=ffffffff

Its packaged param.json declares attribute3=0x80040, but VideoOut rejects mode 15 unconditionally. Report mode 15 as supported when the window's current display runs at 120 Hz or above, require the HFR permission bit 0x40 to configure it, and deliver 119.88 Hz vblanks for that port. Mode 1 restores 59.94 Hz. Slower displays retain the unsupported-mode error; display-query failures throw. No game-specific branch, fallback, retry, or runtime environment switch is added.

Semantics: PS5_Vulkan R92 console measurements establish that support queries are independent of title permission, configuration requires HFR permission, and mode 15 halves the vblank period. The single-bit permission mask attribute3 & 0x40 is inferred from the measured full value 0x80040; it has not been isolated by a console measurement and is recorded as technical debt. Host display mode switching and VRR remain unimplemented and are recorded in TechnicalDebt.

Tested

Windows 11 Pro 10.0.26300, WinLibs GCC 15.2.0 r7, AMD Radeon RX 5600 XT, driver 32.0.21045.5002; current display 1920x1080 at 120 Hz. Release runtime libs built successfully, default SPIRV-Tools setting OFF.

  • guest_video_out_high_frame_rate, guest_video_out_output_mode, guest_video_out_resolution_status, and param_json_parser pass. Sixty vblanks measure 1.001 s in default mode, 0.500 s in mode 15, and 1.001 s after restoring mode 1. The test uses only HFR bit 0x40, and the existing output-mode test checks rejection when permission is absent.
  • Same high-frame-rate test executable, --require-high-frame-rate, against preserved main libraries fails with 120 Hz output not reported as supported; it passes with this change.
  • video_out_flip_tests controls passes on the native display. Its CTest offscreen invocation skips because that SDL backend has no Vulkan support here.
  • Quake II: unchanged executable/resources and relinker options; replace only libkernel and libSceVideoOut with this branch's builds. Output initialization changes to support=00000001 preset=00000000 result=00000000, the main menu renders, and the first run records at least 2,280 frames before a separate submission retirement failed termination. This fixes the startup blocker; sustained gameplay and keyboard input are not established.
  • Review follow-up: video_out_output_mode_policy tests the production mode validator directly with refresh rates -1, 0, 30, 59, 60, 119, 120, 144 and 240 Hz, plus option validation and error precedence. It opens no window and does not skip. The revised runtime libs build and this test plus param_json_parser pass. Removing the slower-display rejection makes the policy test fail at its threshold assertion; restoring it passes.
  • On this Windows host, a benchmark using the same built SDL static library and one hidden window measured the SDL_GetWindowDisplayIndex + SDL_GetCurrentDisplayMode pair over five 200,000-call rounds: 78.7-97.4 ns per pair. The per-present-loop query is retained; this does not benchmark other SDL backends or multi-display setups.
  • Conventions, test registration, and git diff --check pass. Full CTest and Linux execution were not run. The earlier native vblank and title results above predate this review follow-up; they were not rerun.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the approach (support from the host display, permission checked at configure, per-config vblank cadence) looks reasonable. Points to fix:

  • Output.cpp:242 masks attribute3 & 0x40, but the cited WINE_PS5_BUILD.md doesn't mention attribute3 or this bit (checked), and PS5_Vulkan R92/R51 only measured the full value 0x80040. Please cite the source that isolates 0x40, or add a TechnicalDebt line saying the single-bit mask is inferred from the full 0x80040 measurement.
  • Flip.cpp:291-292 and GuestVideoOutOutputMode.cpp:55-56 now accept either result, and every CI job runs with the offscreen SDL driver where these tests skip. Nothing in CI pins the unsupported branch any more. Please keep a check that fails when the display reports < 120 Hz (e.g. assert unsupported in the skip-free path you can reach, or expose the refresh-rate source so a test can inject it).
  • VideoOutDriver.cpp:613 calls SDL_GetWindowDisplayIndex + SDL_GetCurrentDisplayMode on every present-loop iteration. Refresh only when the window reports a display change/move event, or measure that the per-frame cost is negligible.
  • Not verified on our side: vblank periods and Quake II need a real 120 Hz display; the new test could not complete here (it times out on a real window, like the untouched resolution_status/wqhd_detection tests on this host, so I don't attribute that to the PR). Build and param_json_parser pass.

@PrintOrb

Copy link
Copy Markdown
Contributor Author

Addressed the three actionable review points in cef9742:

  • Removed the unsupported WINE_PS5_BUILD.md bit citation from the description. TechnicalDebt now explicitly says the 0x40 mask is inferred from the measured full value 0x80040 and has not been isolated by a console measurement.
  • Extracted the production output-mode validator so video_out_output_mode_policy can supply a refresh rate without opening a display. It checks -1, 0, 30, 59, 60, 119, 120, 144 and 240 Hz, with and without options, plus other mode results and option/error precedence. It has no skip return code. Removing the <120 rejection makes it fail with "mode 15 did not follow the display refresh threshold"; restoring the check passes.
  • Used the measurement alternative for the per-iteration SDL queries. With the same built SDL static library and one hidden window on this Windows host, five rounds of 200,000 SDL_GetWindowDisplayIndex + SDL_GetCurrentDisplayMode pairs measured 93.7, 85.1, 78.7, 97.4 and 82.2 ns/pair. I retained the queries. Other backends and multi-display setups were not benchmarked.

The revised Release libs build passes. video_out_output_mode_policy and param_json_parser pass 2/2; conventions, test registration and git diff --check pass. Native vblank/title testing was not rerun for this update, and Linux/full CTest were not run. This update does not claim Quake II gameplay; a later P20 shader stop is reported separately in #1413.

AI-assisted: yes (Codex).

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 11, 2026
@Recapi

Recapi commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

Linux result for this PR, with a gap that the Windows run can't show.

Setup: Ubuntu (GNOME, Wayland, so SDL runs through XWayland), GCC, Release, NVIDIA RTX 2080 SUPER, monitor at 143.86 Hz. Local merge of main 8fc53cb with this PR and #3840 (fcntl). Yamagi Quake II (PPSA99007, catalog 0.2.0-alpha.1), param.json attribute3 0x80040.

The gap. With this PR merged, Quake II still logged [ps5-output-mode] target=120 support=80290016 and stopped before its first frame. The bundled SDL reports the display's refresh rate as 0 on Linux unless it was built with XRandR. Here libxrandr-dev was missing, so SDL_VIDEO_DRIVER_X11_XRANDR was not defined (the SDL_X11_XRANDR option is ON), and GetDisplayRefreshRate() read 0. A probe linked against the same libSDL2.a:

driver=x11 displays=1
window display=0 rc=0 1920x1080@0      # without libxrandr-dev
window display=0 rc=0 1920x1080@144    # after installing it and reconfiguring

With XRandR, Quake II gets support=00000001 preset=00000000 result=00000000 and present-open. The menu draws, and it presents 960 frames in about 37 s at 120 Hz pacing. Then it hits the P20 case of #1413: last provoking vertex with explicit per-vertex flat interpolation is unsupported, the same stop @PrintOrb saw on Windows. #4030 doesn't cover it (P10 only).

So on Linux, this PR depends on SDL's XRandR support, and neither docs/dev/BUILD.md nor the Linux CI job installs libxrandr-dev (CI installs only the three audio packages). Two small additions would close the gap:

  • add libxrandr-dev (Fedora: libXrandr-devel) to docs/dev/BUILD.md and the Linux job;
  • have the configure step fail when SDL has no XRandR on Linux, the way it already does for audio. Alternatively, have updateDisplayRefreshRate throw on a refresh rate of 0 instead of taking it as "below 120 Hz". As it stands, a build without the package silently refuses 120 Hz on any monitor.

@PrintOrb

Copy link
Copy Markdown
Contributor Author

@Recapi thanks for the Linux reproduction. Could you verify commit 5c19601 on your Linux setup? In separate clean bundled-SDL configure directories, please confirm that missing XRandR development files (or SDL_X11_XRANDR=OFF) fail with the new diagnostic, while installed/enabled XRandR configures successfully. Then please rerun the focused tests and Quake II startup to confirm it still reaches the menu and the known P20 stop. Linux verification of this follow-up is pending; my guard harness and Windows results are below.

Implemented the configure-time approach from your report in 5c19601.

  • Added libxrandr-dev to both the Linux build and release workflows, and documented libxrandr-dev / libXrandr-devel in BUILD.md.
  • After configuring bundled SDL on Linux, check its HAVE_X11_XRANDR result. Configuration now fails with an actionable dependency/option diagnostic if the XRandR backend was not built. No change to runtime output-mode semantics or fallback was added. System SDL remains outside this bundled-build check.

Verification: the actual new CMake gate, extracted into a local directory-property harness, passes with the SDL capability true and rejects both false and unset with the expected message. This is a guard smoke test, not a native Linux build; this machine has no Linux environment.

Windows 11 / WinLibs GCC 15.2 r7: the Release libs build and five focused tests pass, including video_out_output_mode_policy, guest_video_out_high_frame_rate, guest_video_out_output_mode, param_json_parser and param_json_utf8. Native timing for 60 vblanks was 1.001 s default, 0.500 s high and 1.001 s restored. Two offscreen flip tests skipped because that SDL driver lacks Vulkan. Conventions, test registration and diff checks pass.

The Windows build/test comparison includes the existing #4021 fix for main's unrelated HostPoll compile failure. That commit is isolated on a local test branch and is not part of this PR update. Full CTest, Linux runtime and Quake II gameplay were not rerun.

AI-assisted: yes (Codex).

@Recapi

Recapi commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

@PrintOrb verified 5c19601 on Linux: Ubuntu, GCC, Release, NVIDIA RTX 2080 SUPER, 143.86 Hz monitor, SDL on X11 through XWayland. Each configure was in its own clean build directory with the bundled SDL:

  • -DSDL_X11_XRANDR=OFF: configure fails at CMakeLists.txt:118 with the new message (SDL has no XRandR support, so X11 display refresh rates cannot be queried. Install libxrandr-dev ...).
  • Default, with libxrandr-dev installed: configure succeeds and SDL_VIDEO_DRIVER_X11_XRANDR is defined.
  • I didn't check the "package not installed" case at the PR head. I can't uninstall it here, but before installing it the bundled SDL configured without SDL_VIDEO_DRIVER_X11_XRANDR even with the option ON. That is the state the new check catches through HAVE_X11_XRANDR.

The focused tests on the PR head pass 3/3 (--repeat until-fail:3): video_out_output_mode_policy, guest_video_out_high_frame_rate, guest_video_out_resolution_status, guest_video_out_output_mode and param_json_parser. guest_video_out_high_frame_rate ran and was not skipped.

Quake II (PPSA99007, catalog 0.2.0-alpha.1), relinked and run against the PR head alone:

  • [ps5-output-mode] target=120 support=00000001 preset=00000000 vrr=ffffffff result=00000000
  • [ps5-agc] present-open handle=00000001 framebuffer=0x208200000/67108864 buffers=2 alias=0
  • The menu draws, and it presents 1,920 frames in 52.9 s, about 36 fps.
  • Then it stops at the known P20 case (v_interp_mov P10/P20 of a FLAT_SHADE input without pass-through: deltas or raw vertices? #1413): presentation failed: AGC graphics: last provoking vertex with explicit per-vertex flat interpolation is unsupported.

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#3664 .github/workflows/build.yml L242-243
.github/workflows/release.yml L65
docs/dev/BUILD.md L29-30
#3994 docs/dev/BUILD.md L29
#4508 core/libs/prx/libkernel/AppMetadata/include/ParamJsonParser.hpp L11
core/libs/prx/libkernel/AppMetadata/src/ParamJsonParser.cpp L307
#4617 core/libs/prx/libkernel/AppMetadata/include/AppMetadata.hpp L25
core/libs/prx/libkernel/AppMetadata/include/ParamJsonParser.hpp L11
core/libs/prx/libkernel/AppMetadata/src/AppMetadata.cpp L91
core/libs/tests/ParamJsonParser.cpp L158

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 12, 2026

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-checked the new head (XRandR configure gate, libxrandr-dev in both workflows and BUILD.md): built on current main with the full ctest run (979 passed), including video_out_output_mode_policy, param_json_parser and guest_video_out_output_mode. @Recapi's Linux run covers the configure failure with SDL_X11_XRANDR=OFF and guest_video_out_high_frame_rate running unskipped on a 144 Hz display. Merging.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants