Skip to content

fix(libSceHmd2): gate EnableMirroring, GetPredictedDisplayTime and SetRenderConfig on the reprojection session - #15361

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
oneandonlydean:fix/hmd2-reprojection-session-gate
Nov 3, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
oneandonlydean:fix/hmd2-reprojection-session-gate

Conversation

@oneandonlydean

Copy link
Copy Markdown
Collaborator

What

Since #7658, sceHmd2ReprojectionInitialize creates a reprojection session, but sceHmd2ReprojectionEnableMirroring, sceHmd2ReprojectionGetPredictedDisplayTime and sceHmd2ReprojectionSetRenderConfig (added in #12634) still return 0x8a72000b ("no session") inside one. Their technical-debt entry says to gate them once Initialize can create a session; a probe reported on #8645 found it still unmet. PPSA05666 calls EnableMirroring and SetRenderConfig right after SetMirroringOption, so it is told there is no session while it has one.

The three now test the session first, like their neighbours: without a session each still returns 0x8a72000b for every argument and writes nothing. Inside one, the answers measured for rejected arguments in a PPSA01317 session are returned: sceHmd2ReprojectionGetPredictedDisplayTime with a null output answers 0x8a720008, and sceHmd2ReprojectionSetRenderConfig with a bit other than bits 0 and 32 in the first argument or a nonzero second or third argument answers 0x8a720009. Every other form (all of sceHmd2ReprojectionEnableMirroring, accepted SetRenderConfig forms, GetPredictedDisplayTime with an output) throws through NotImplemented_nid_no_patch, as the other unimplemented reprojection exports do. The 0x8a720019 that GetPredictedDisplayTime returned in that session without a headset is deliberately not returned, because the answer with a headset is unknown. The debt entry says so.

GuestHmd2.cpp could not tell the two cases apart, because every earlier call ran without a session. It now calls the three inside a session: the measured answers are pinned, and for the forms that still throw it requires only that the call does not answer as without a session (either a return or a throw), so the not-yet-implemented body is not pinned. It also re-runs the no-session checks after sceHmd2ReprojectionTerminate.

Tested

  • Linux workstation (main f4489e210f): guest_hmd2 passes. tools/check_conventions.py passed.
  • Control: with Export.cpp from main and the new test, guest_hmd2 fails with "HMD2: mirroring inside a reprojection session answered as without one"; with this change it passes. The no-session assertions are unchanged and still pass.
  • Not run: Windows, macOS, the GitHub runner, a console.

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; silent stubs are listed in technical debt (none added)
  • No notes, investigation .md files or images added to the repository
  • New third-party code is a submodule built from source (none added)
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: none needed (no graphics code)
  • AI-assisted: yes

…tRenderConfig on the reprojection session

Since Initialize creates a reprojection session, these three still returned 0x8a72000b inside one. Gate them on reprojectionState like the neighbouring exports. Inside a session GetPredictedDisplayTime with a null output and SetRenderConfig with a bit outside bits 0 and 32 or a nonzero second or third argument return the codes measured in a PPSA01317 session; every other form keeps its throwing body. The test tells inside from outside a session and the debt entry says so.
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

Progress report (f6232fc → a3876ad)

📉 System libraries: 26.36% (-0.01%, -3 reverted functions)

⚠️ 3 went back to stubs
Library Name
libSceHmd2 sceHmd2ReprojectionEnableMirroring
libSceHmd2 sceHmd2ReprojectionGetPredictedDisplayTime
libSceHmd2 sceHmd2ReprojectionSetRenderConfig

Changed libraries (implemented exports)

Library Before After Change
libSceHmd2 22/153 (14.38%) 19/153 (12.42%) -1.96%

@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ AMD GPU test: passed

PR head a3876ad merged onto main 7feb37e · tested 2026-11-03 03:23 UTC · 17 min

GPU AMD Radeon RX 6300 (RADV NAVI24), driver Mesa 25.2.8-0ubuntu0.24.04.4, Vulkan 1.4.318
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-42-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 1,125 passed · 4 failed (0 new, 3 also fail on main, 1 unstable on main) · 7 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 1,136 of 3,743 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (538 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.1 s, ⚠️ agc_driver_image_sample_unnormalized 44.3 s, ⚠️ agc_driver_sample_multisample_target 40.6 s, ⚠️ agc_driver_lazy_resolved_abi 39.8 s, ⚠️ public_headers 38.0 s
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 5 of the last 7 main runs
Failing on main too (3, not counted against this PR)
agc_driver_image_table
agc_driver_native_depth_bda_clear
agc_driver_native_multisample_depth
Validation IDs already present on main (4 IDs in 461 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (461 tests): agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, agc_driver_bda_span_reads, agc_driver_bindless_images, and 453 more
VUID-vkCmdCopyImage-srcImage-01548 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth, agc_driver_stencil_null_feedback
VUID-vkCmdCopyImage-srcImage-01551 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth, agc_driver_stencil_null_feedback
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_srgb8_color_target
Skipped (7)
agc_driver_copied_writer_label_order: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_float16_unused_nan_payloads: skipped, the device has no native f16 conversions with RTE rounding and kept f16 denormals
agc_driver_linear_target_direct_write_completion: skipped, the device does not keep host imports write-watched, so no completion stamp over the target is tracked
agc_driver_ngg_vertex_wave_reduction: skipped, s3 describes a 32-lane wave only on 32-lane subgroups, and the device has 64 lanes
agc_driver_scattered_runs: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
Reproduce
git fetch origin a3876adc8484ee0a0335e90218ea24ba1418c2a0 7feb37ee3e30e10139b483fb4df689d5b5b69ab8
git checkout 7feb37ee3e30e10139b483fb4df689d5b5b69ab8 && git merge --no-ff a3876adc8484ee0a0335e90218ea24ba1418c2a0
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 12 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 16 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed — looks good

The session gate and measured error paths match the implementation evidence, and the exact-head Windows build and focused test pass.

What I ran

Reviewed all three changed files at head a3876adc8484ee0a0335e90218ea24ba1418c2a0 against base f6232fcfda70644495273f6b8dd88cf0603463d6; the current-base merge preview is clean. Local environment: Debian Linux, Python 3.11.2. The hosted Windows workflow built the changed guest_hmd2 test; I did not build locally.

python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 15361
git diff --check f6232fcfda70644495273f6b8dd88cf0603463d6...a3876adc8484ee0a0335e90218ea24ba1418c2a0
python3 tools/pr_abi_audit.py --repo /marc/AnyPS5 --base f6232fcfda70644495273f6b8dd88cf0603463d6 --head a3876adc8484ee0a0335e90218ea24ba1418c2a0 --json
python3 tools/pr_test_quality.py --root /marc/AnyPS5 --json core/libs/tests/GuestHmd2.cpp
python3 tools/pr_overlap.py --branch refs/review/15361/current --repo boykopovar/AnyPS5 --jobs 4
gh run view 41569771032 --repo boykopovar/AnyPS5 --log | grep -i -C 2 'guest_hmd2'

Results

Check Result Note
Source, tests and evidence passed Session and argument precedence are covered.
Diff and conventions passed No whitespace or template errors.
Export ABI audit passed Warnings do not name the three changed exports.
Test registration passed Existing guest_hmd2 target is registered.
Test-quality heuristic passed Possible-registration warning is a false positive; CMake registration was verified.
Current-base merge preview passed Clean against the PR base.
Hosted Windows build and test passed Exact head; guest_hmd2 passed.
Other applicable hosted checks passed Conventions, portability, labels, eligibility and report passed.
Local build or CTest not run Hosted Windows supplied exact-head build/test evidence.
Automated overlap helper failed GitHub response parser error; targeted search found no duplicate of these three functions.
Precheck table and raw outputs
Check Status Note
Build and compile not applicable Precheck does not build.
Diff check passed Exact head/base diff.
Conventions and template passed All convention checks passed.
Changed-export ABI audit failed to launch Optional helper absent from isolated snapshot; workspace audit ran.
Python checks not applicable No relevant Python files changed.
Dependency and mergeability passed Exact-head current-base merge preview clean.
Build-dependent C++ tests not applicable Precheck does not build.
Test-quality heuristics failed to launch Optional helper absent from isolated snapshot; workspace heuristic ran.
Negative controls not applicable No changed Python test supports a no-build control.

Workspace ABI audit summary:

status: passed_with_warnings
symbols: 142
findings: 175
findings naming the three changed exports: 0

The audit warnings are explicit NID-versus-symbol-hash alias warnings; the changed signatures are unchanged. The test-quality helper reported possible-unregistered-cpp-test; I verified the existing nested CMake target and CTest registration.

Precheck optional-helper errors:

/usr/bin/python3: can't open file '/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15361-a3876adc8484/head-a3876adc8484-71517a23/tools/pr_abi_audit.py': [Errno 2] No such file or directory
/usr/bin/python3: can't open file '/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15361-a3876adc8484/head-a3876adc8484-71517a23/tools/pr_test_quality.py': [Errno 2] No such file or directory

Overlap helper output:

pr_overlap: Invalid \uXXXX escape: line 1 column 263591 (char 263590)

Hosted Windows test output:

Start 2485: guest_hmd2
1/1 Test #2485: guest_hmd2 .......................   Passed    0.02 sec
100% tests passed, 0 tests failed out of 1

Other hosted checks:

conventions pass
intake pass
labels pass
library-portability pass
report pass
eligibility pass
linux and specialized jobs skipped by workflow filters

Negative control

Not run by me. The PR body does not report a negative control for this change.

Findings

Blocking: None found in the three changed files.

Non-blocking: Open #8645 covers five different reprojection exports, not these three. Its branch is based on an older main and pairwise merging shows shared-file conflicts; this PR independently merges cleanly against current main, so no dependency on #8645 is indicated.

Sources

Not verified

No local build or CTest, physical-console run, headset-attached behavior, or independent reproduction of the firmware 13.40 measurements was performed. Linux and specialized CI jobs were skipped. The automated overlap helper failed to parse GitHub’s response; targeted PR search and file inspection were used instead.

To get this to a good state

No further action is needed for this head. I will review again if it changes.

@oneandonlydean oneandonlydean self-assigned this Nov 3, 2026
@oneandonlydean
oneandonlydean merged commit ff58973 into boykopovar:main Nov 3, 2026
13 checks passed
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