Skip to content

fix(libSceVideoOut): report the output resolution from the host display as measured on a PS5 - #7814

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
ionut27001:fix/videoout-output-status-resolution
Oct 24, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
ionut27001:fix/videoout-output-status-resolution

Conversation

@ionut27001

@ionut27001 ionut27001 commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

What

sceVideoOutGetOutputStatus filled resolution from the size of the registered buffers (cfg.width and cfg.height, 1920x1080 until the first buffer registration), so a title that reads it right after sceVideoOutOpen got 1 on every host. By #7635's reading of its disassembly and crash, NHL 27 (PPSA34063) builds its hardware profile from that call before it registers a buffer and then reads a null entry for the 1080p profile its data has no entry for.

Measured in a payload process on a PS5 (firmware 12.70; payload SDK v0.44, clang 18.1.8), with libSceVideoOut.sprx loaded into the process through sceKernelLoadStartModule, right after sceVideoOutOpen(0xff, 0, 0, NULL) and with no buffer registered. The console is connected to a 4K HDR display with HDR on; the first run has its resolution setting on Automatic, the second the same display with the setting changed to 1080p. Probe p76_libvideoout, source and both logs attached: p76-videoout-output-status.zip; the lines below are quoted unchanged with a p76: prefix, except that the 160-byte aa poison pattern of the last line in the first block is shortened to aaaa…:

p76: case open user=0xff bus=0 index=0 param=null ret=0x4e100100
p76: case output_status handle=1309671680 ret=0 touched=48 bytes=020000000200000003000000000000000000000000000000000000000000000000000000000000000000000000000000
p76: case output_status_words dword0=2 dword1=2 qword1=3 qword2=0
p76: case resolution_status handle=1309671680 ret=0 touched=48 bytes=000f000070080000000f0000700800000300000000000000000070420000000000000000000000000000000000000000
p76: case output_status_vrr handle=1309671680 ret=0x8029001c touched=0 bytes=aaaa…
p76: case output_status handle=1309671680 ret=0 touched=48 bytes=010000000200000003000000000000000000000000000000000000000000000000000000000000000000000000000000
p76: case output_status_words dword0=1 dword1=2 qword1=3 qword2=0
p76: case resolution_status handle=1309671680 ret=0 touched=48 bytes=000f000070080000000f0000700800000300000000000000000070420000000000000000000000000000000000000000

So with no buffer registered, resolution was 2 with the console's resolution setting on Automatic on the 4K display and 1 with it set to 1080p: it changed with the console's resolution setting. dynamicRange was 2, refreshRate 3 and flags 0 both times; sceVideoOutGetResolutionStatus reported 3840x2160 for the full and pane sizes both times, refreshRate 3, screenSizeInInch 60 and flags 0 (the resolution_status_words line in the logs splits those bytes as if they were the output status; read the hex); sceVideoOutGetOutputStatusWithVrr returned 0x8029001c, the global-flag check its debt entry describes.

The change:

  • VideoOutDriver keeps the display's resolution class next to the refresh rate, from the same SDL_GetCurrentDisplayMode call for the display the window is on (2 when the mode is at least 3840 pixels wide or 2160 high, 1 below, the threshold the buffer rule used), and outputStatus reports it, so it no longer depends on the registered buffers. sceVideoOutGetOutputStatusWithVrr shares outputStatus, so its first 48 bytes change the same way. The present loop reads the mode every iteration, as it does for the refresh rate, so a window moved to another display changes the next status. On Wayland SDL's current mode is the output's logical size (from SDL's Wayland source, not run), so a scaled 4K output reports 1 (recorded in debt).
  • New flip test mode resolution (video_out_flip_resolution): a freshly opened port reports the class of display 0, and registering and flipping a linear buffer of the other class (3840x2160 on a display below 4K, 1920x1080 on a 4K display) leaves it unchanged, while the port records the buffer's size. Like the other video_out_flip_* tests that open a window, it is skipped where the SDL driver has no Vulkan surface, which includes the default offscreen driver CI uses.
  • Debt: the sceVideoOutGetOutputStatus entry records what was not measured, the measurement, that the payload process reported dynamicRange 2 with flags 0 while this code sets flag bit 0 whenever it reports dynamic range 2, and the Wayland case; the sceVideoOutGetResolutionStatus entry records the 48 bytes the payload process wrote and that this code reports the registered buffers' size where the payload process reported 3840x2160 at both settings. Neither of those two is changed here.

Not measured: the status after a buffer is registered or flipped, a 1440p output, and a console on a display below 4K with the resolution on Automatic (the 1080p row is the setting on the 4K display). On a host whose display is below 3840x2160 this PR still reports 1, so NHL 27's missing 1080p profile entry (#7635) stays the title's data on such hosts, which is why this PR does not close the issue; the title was not run here.

Overlaps: #6879 changes the same lines of updateDisplayRefreshRate in VideoOutDriver.cpp. #4040 (Output.cpp, the debt file), #7008 (VideoOutDriver.cpp), #674 and #6044 (CMakeLists.txt; #6044 also edits tests/Flip.cpp without conflict) touch the same files but already conflict with main without this PR (git merge-tree --write-tree against each refs/pull/N/head, with and without this branch). #7259 adds sceVideoOutGetCurrentOutputMode_ with a resolution code derived from cfg->width and cfg->height whose top tier is the rule this PR removes from outputStatus; no textual conflict.

APS5_OUTPUT_RESOLUTION=<width>x<height> (for example 1920x1080) overrides the size the host display contributes to the reported output resolution. sceVideoOutGetOutputStatus and sceVideoOutGetOutputStatusWithVrr then report resolution 2 when the override is at least 3840 wide or 2160 high and 1 otherwise, instead of reading the display. Unset or empty keeps the follow-the-display behaviour above. A value that is not two positive decimal integers separated by x makes the call throw, naming the variable and the value. The variable is documented in docs/dev/ENVIRONMENT.md and noted in the sceVideoOutGetOutputStatus debt entry. sceVideoOutGetResolutionStatus still reports the registered buffers' size and is not affected.

Tested

Windows 11 Pro 10.0.26300, WinLibs MinGW-w64 GCC 15.2.0 r7 (posix, UCRT), Ninja, Release, -DBUILD_TESTING=ON, branch built and tested on main 6030b31 and then rebased on 3fdd1f5, whose 42 changed files since then touch no VideoOut, SDL or test file (core/libs/SceTypes.hpp gained five lines away from the VideoOut structs); NVIDIA GeForce RTX 4080 SUPER (driver 617.42), host display 3440x1440 at 164 Hz, so the host class is 1 and the new test registers and flips a 3840x2160 linear buffer.

  • With the default ANYPS5_VIDEO_OUT_TEST_DRIVER=offscreen the flip tests that open a window are skipped on this host (resolution, lifetime and ps4 checked: "DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform"; decode, which opens no window, passes), so the VideoOut tests ran with -DANYPS5_VIDEO_OUT_TEST_DRIVER=windows, a real window: ctest -R "video_out_|guest_video_out", 27 tests: 25 passed, guest_video_out_wqhd_detection_no_vulkan skipped, video_out_hdr_probe failed with "FAIL: a window without a Windows HDR monitor report reads as HDR although only the surface offers HDR10 (driver windows)"; this host's monitor is HDR, and with Output.cpp, VideoOutDriver.cpp and VideoOutDriver.hpp from main it fails with the same message.
  • Revert check: with those three files from main and the new test kept, video_out_flip_resolution fails with "the flipped buffer's size changed the reported resolution" (run before and after the rebase); with the branch's files it passed in every run.
  • The test's SDL_GetCurrentDisplayMode is imported from libSceAgcDriver.prx, the SDL copy the driver uses (objdump -p on the test executable and on libSceVideoOut.prx).
  • python tools/check_conventions.py --base origin/main passes.
  • Probe p76_libvideoout built with the payload SDK v0.44 and clang 18.1.8 (-target x86_64-sie-ps5), launched twice through the payload manager; both logs are in the attachment.

Not tested: Linux (CI's offscreen driver skips the window tests, so the new test does not run there; where SDL binds on Linux was not checked), a 4K host display (the 1920x1080 branch of the test), NHL 27.

Override commit, rebased onto main e25333e, Windows 11, WinLibs GCC 15.2.0 r7, NVIDIA-less laptop (AMD Radeon 8060S): ANYPS5_VIDEO_OUT_TEST_DRIVER=windows ctest -R "video_out|videoout|flip" twice: 31 of 31 pass both times. The new test video_out_flip_resolution_override is skipped by ctest here (the offscreen SDL driver has no Vulkan device on this machine), so it was run directly with the windows driver, twice: with the variable unset the status equals the display's; 1920x1080 and 1280x720 give 1 and 3840x2160, 2560x2160 and 3840X1 give 2 from both status calls; twelve malformed values throw a message naming APS5_OUTPUT_RESOLUTION; clearing the variable returns to the display's value. Revert check: with VideoOutDriver.cpp restored from the previous commit the test fails on the 3840x2160 case. Not run: Linux and macOS.

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 under Silent stubs in their library's technical debt file
  • 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
  • Fixes: none
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 4080 SUPER, driver 617.42 (32.0.16.1742), Windows 11 10.0.26300
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 674 core/libs/prx/libSceVideoOut/CMakeLists.txt
core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp
PR 1896 docs/dev/ENVIRONMENT.md
PR 4040 core/libs/prx/libSceVideoOut/src/Output.cpp
docs/dev/debt/libSceVideoOut.md
PR 5021 core/libs/prx/libSceVideoOut/CMakeLists.txt
core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp
core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 6186 docs/dev/ENVIRONMENT.md
PR 6617 docs/dev/ENVIRONMENT.md
PR 6924 docs/dev/ENVIRONMENT.md
PR 6977 core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp
core/libs/prx/libSceVideoOut/tests/Flip.cpp
docs/dev/debt/libSceVideoOut.md
PR 7201 core/libs/prx/libSceVideoOut/CMakeLists.txt
core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp
core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp
PR 7449 docs/dev/ENVIRONMENT.md
PR 7457 docs/dev/ENVIRONMENT.md
PR 7484 docs/dev/ENVIRONMENT.md
PR 7604 docs/dev/ENVIRONMENT.md
PR 7642 docs/dev/ENVIRONMENT.md
PR 8004 docs/dev/ENVIRONMENT.md
PR 8077 docs/dev/ENVIRONMENT.md
PR 8246 docs/dev/ENVIRONMENT.md
PR 8484 docs/dev/ENVIRONMENT.md
PR 8542 docs/dev/ENVIRONMENT.md
PR 9356 docs/dev/ENVIRONMENT.md
PR 9387 docs/dev/ENVIRONMENT.md
PR 9400 docs/dev/ENVIRONMENT.md
PR 9401 docs/dev/ENVIRONMENT.md
PR 9431 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9432 core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp
core/libs/prx/libSceVideoOut/tests/Flip.cpp
docs/dev/debt/libSceVideoOut.md
PR 9669 docs/dev/ENVIRONMENT.md
PR 9672 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9673 core/libs/prx/libSceVideoOut/tests/Flip.cpp
docs/dev/debt/libSceVideoOut.md
PR 9674 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9675 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9676 core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp
core/libs/prx/libSceVideoOut/tests/Flip.cpp
docs/dev/ENVIRONMENT.md
docs/dev/debt/libSceVideoOut.md
PR 9842 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9852 docs/dev/ENVIRONMENT.md
PR 9891 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9892 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9893 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9895 core/libs/prx/libSceVideoOut/tests/Flip.cpp
PR 9898 docs/dev/ENVIRONMENT.md
PR 10112 core/libs/prx/libSceVideoOut/CMakeLists.txt
docs/dev/debt/libSceVideoOut.md
PR 10193 docs/dev/ENVIRONMENT.md
PR 10231 docs/dev/ENVIRONMENT.md
PR 10244 docs/dev/ENVIRONMENT.md
PR 10254 docs/dev/ENVIRONMENT.md
PR 10264 docs/dev/ENVIRONMENT.md
PR 10272 docs/dev/ENVIRONMENT.md
PR 10420 docs/dev/ENVIRONMENT.md
PR 10472 docs/dev/ENVIRONMENT.md

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@ionut27001 thanks, reporting the resolution from the host display like a console on Automatic is the right default, and we'd like to keep it.

One addition before merge: on PC this means anyone with a 4K monitor always gets a title's 4K mode, even on a GPU that can't sustain it, and there's no way back. Could you add an override for the reported output resolution, for example APS5_OUTPUT_RESOLUTION=1920x1080 (or whatever form fits the existing settings), with a row in docs/dev/ENVIRONMENT.md? Unset should keep the new follow-the-display behaviour.

Once that's in, we'll review the delta and run our title test with the override set to the previous resolution, so it measures this change rather than the jump to 4K.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 21, 2026
@ionut27001
ionut27001 force-pushed the fix/videoout-output-status-resolution branch from ae0907b to eaadab6 Compare October 21, 2026 06:29
@ionut27001

Copy link
Copy Markdown
Contributor Author

Added APS5_OUTPUT_RESOLUTION=<width>x<height>, for example APS5_OUTPUT_RESOLUTION=1920x1080. When it is set, sceVideoOutGetOutputStatus reports resolution 2 for a size at least 3840 wide or 2160 high and 1 otherwise, instead of reading the host display, so a 4K monitor can still be given the 1080p mode. Unset or empty keeps the follow-the-display behaviour, and a malformed value throws with a message naming the variable and the value instead of falling back. There is a row in docs/dev/ENVIRONMENT.md, a sentence in the debt entry and a guest test, video_out_flip_resolution_override, for the override and the malformed values. The branch is rebased onto current main; the Tested section has the new runs.

@ionut27001
ionut27001 force-pushed the fix/videoout-output-status-resolution branch from eaadab6 to f65e06b Compare October 21, 2026 07:02
@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed and removed needs rebase Conflicts with main, rebase needed labels Oct 21, 2026
@adriadam10
adriadam10 force-pushed the fix/videoout-output-status-resolution branch from f65e06b to 4e7d372 Compare October 24, 2026 08:16
@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed and removed needs rebase Conflicts with main, rebase needed labels Oct 24, 2026
…ay as measured on a PS5

sceVideoOutGetOutputStatus derived resolution from the size of the
registered buffers, so a title that reads it right after sceVideoOutOpen
got 1 (1080p) whatever the display. In a payload process on a PS5
(firmware 12.70), with no buffer registered, the field changed with the
console's resolution setting: 2 with it on Automatic on a 4K display, 1
with it set to 1080p. Read it from the display mode SDL reports for the
window's display, next to the refresh rate, and keep it independent of
the registered buffers.
@adriadam10
adriadam10 force-pushed the fix/videoout-output-status-resolution branch from 4e7d372 to 983a81d Compare October 24, 2026 10:43
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 24, 2026
@adriadam10
adriadam10 merged commit f863d6a into boykopovar:main Oct 24, 2026
10 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Re-checked after main changed docs/dev/ENVIRONMENT.md again. The code is unchanged since the last review. We rebased onto current main: the APS5_OUTPUT_RESOLUTION row now sits next to main's new APS5_NO_WGI row in the VideoOut table. Conventions check passes on the rebased head; merged.

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