fix(vk): apply PsychoV35 to the adapted scene permutation #400

Merged
HumanBean merged 1 commit from futondestroyer/Longshot:codex/psychov35-scene-variants into main 2026-11-14 11:19:27 +00:00
Member

Why

Camera movement can switch between two scene-mapping permutations while PsychoV35 is selected. One was left on the vanilla curve, producing the repeated warm/cool flashes recorded in Lon Lon Ranch.

What changed

  • scene_tonemap_pass.h recognizes the adapted permutation's extra shared exp2 exposure multiplier and includes it in the complete PsychoV35 gain.
  • RGB must share both the base exposure and the adaptation expression; the peak must still come from the base exposure's bank. Unsupported or mismatched shapes remain untouched.
  • Synthetic IR tests cover both multiplication orders, early colour writes, six adaptation values and rejection without mutation. Four measured-run records are in docs/tested/.

Flags and settings

None added. Reproduce with Native HDR and PsychoV35; DLSS/DLAA continues to use the existing opt-in RX_VK_PSYCHOV35_DLSS=1.

Measurements

main: 0caf0618 (2026-11-14)
this PR: codex/psychov35-scene-variants @ 4b3729ff
Baseline: development base @ 514591a3 (original matcher)

The agreed shared development base was retained to keep the host and all other renderer code identical. Its original matcher and PsychoV35 math are identical to main 0caf0618. dev_packs.py built renderer-only packs containing the original/fixed matcher and the same diagnostic logging. The measured fix header is b20f94fdf355a01d; afterward only its introductory comment was reflowed and the run records added. No new full game build or base movement was needed.

Hardware: RTX 4070, NVIDIA 621.01, Core i7-13700F, 32 GB RAM, Windows build 26300 / 26H2.
Scene: Lon Lon Ranch daylight alley; 2560x1440, 16:9, Native HDR 200/1000 nits, PsychoV35, DLAA K, FG Off, game cap 61.
Method: fresh copies of one saved checkpoint, two-pitch left/right camera sweeps, interleaved original/fixed/original/fixed. Recordings start before camera input. Each run has complete records; startup/menu transitions are excluded. No FPS/performance result is claimed.

Metric per run development base @ 514591a3 (original matcher) development base @ 514591a3 + this PR @ 4b3729ff
Stable shader switches checked 45, 49 31, 49
Large chroma steps at switches (>1 capture code) 45, 37; median 41 0, 0; median 0
Median absolute chroma step 2.12625, 3.05500; median 2.59063 0.03625, 0.03251; median 0.03438
Maximum absolute chroma step 5.06750, 4.37625 0.12250, 0.08876

The metric is the median block change in R-minus-B over 98 blocks of 20x20 pixels, taking the largest absolute step within five frames of each logged shader switch. Counts are detections at transitions, not independent flash episodes. The diagnostic control also matched all 45 stable switches to the expected warmer/cooler direction at the fixed one-frame capture offset. Raw PQ samples support relative colour comparison, not calibrated brightness.

How to reproduce: load child Link in the ranch alley facing the entrance, tilt toward the ground, pan left/right, then raise the view toward the sky and repeat. On main, the image alternates curves; here both permutations retain PsychoV35. For the game-free regression, run python -I -B tests/test_scene_tonemap_pass.py with the new synthetic fixture: it fails unchanged current main at the adapted-exposure assertion and passes here.

original: program 7370b01162e62427: scene tone map left as the game's: the fit's input is not times a constant
fixed:   program 7370b01162e62427: scene tone map PsychoV35
fixed:   program 672e593076ac390a: scene tone map PsychoV35

Testing

Tested: two paired in-game runs above; original recorded reproduction; renderer pack built and linked with zero compiler failures; synthetic interpreted outputs agree with PsychoV35 at the complete adapted gain; unsupported graphs remain unchanged. Full python -I -B tests/run_all.py: 521 passed / 6 failed / 34 skipped here and the same results and failures on clean main 0caf0618. Shared failures: test_framegen_resources, test_module_ids, test_oot_state_tap, test_pad_layout, test_release, test_tested_configurations. No PR-only failure. Final focused matcher test passes. New run files validate through scripts/tested_configurations.py; the catalogue unit retains main's Windows ASCII-pipe CRLF failure.

Not tested: Linux, AMD/Intel, a fresh full current-main game build, or long gameplay beyond the captured views. The reported Lake Hylia/Field transition symptom needs a retest; the newer log's occasional format fallback is a separate lead. This PR addresses the recorded shader-permutation flashes.

Needs other testers: Linux C++20 game-free matcher build/regression: T-S724. Run the development guide's game-free check selection python -I -B tests/run_all.py scene_tonemap on this branch and report compiler/OS/result. No GPU or game dump is needed. A maintainer must add testing wanted before the request can be claimed. Linux gameplay remains untested.

Screenshots

A local before/after comparison is prepared. Awaiting explicit permission to attach it; keeping this PR WIP until it is attached.

Risk and rollback

The matcher now accepts one additional, narrowly constrained exposure shape. Incorrectly accepting a different shape could change its colour; shared RGB exposure/adaptation checks, the existing scene/luminance/peak guards and negative fixtures limit that risk. Select Vanilla to bypass PsychoV35, or revert this commit. Translator changes invalidate the shader cache normally.

Reviewer notes

Read the matcher and tests/scene_tonemap_ir.cpp first. No host runtime, platform interface or shipped GLSL/SPIR-V file changes. The earlier hue-continuity experiment is not included: it did not eliminate the reported flashes. No merge or auto-merge requested.

Issues

See #344

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Screenshots for a change that shows on screen. (comparison prepared; attachment permission pending)
  • A file in docs/tested/ for each new measured run (format in docs/tested-configurations.md; no appended row or assembled view).
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows passes; Linux coverage requested as T-S724)
  • Docs updated.
## Why Camera movement can switch between two scene-mapping permutations while PsychoV35 is selected. One was left on the vanilla curve, producing the repeated warm/cool flashes recorded in Lon Lon Ranch. ## What changed - `scene_tonemap_pass.h` recognizes the adapted permutation's extra shared `exp2` exposure multiplier and includes it in the complete PsychoV35 gain. - RGB must share both the base exposure and the adaptation expression; the peak must still come from the base exposure's bank. Unsupported or mismatched shapes remain untouched. - Synthetic IR tests cover both multiplication orders, early colour writes, six adaptation values and rejection without mutation. Four measured-run records are in `docs/tested/`. ## Flags and settings None added. Reproduce with Native HDR and PsychoV35; DLSS/DLAA continues to use the existing opt-in `RX_VK_PSYCHOV35_DLSS=1`. ## Measurements main: 0caf0618 (2026-11-14) this PR: codex/psychov35-scene-variants @ 4b3729ff Baseline: development base @ 514591a3 (original matcher) The agreed shared development base was retained to keep the host and all other renderer code identical. Its original matcher and PsychoV35 math are identical to main 0caf0618. `dev_packs.py` built renderer-only packs containing the original/fixed matcher and the same diagnostic logging. The measured fix header is b20f94fdf355a01d; afterward only its introductory comment was reflowed and the run records added. No new full game build or base movement was needed. Hardware: RTX 4070, NVIDIA 621.01, Core i7-13700F, 32 GB RAM, Windows build 26300 / 26H2. Scene: Lon Lon Ranch daylight alley; 2560x1440, 16:9, Native HDR 200/1000 nits, PsychoV35, DLAA K, FG Off, game cap 61. Method: fresh copies of one saved checkpoint, two-pitch left/right camera sweeps, interleaved original/fixed/original/fixed. Recordings start before camera input. Each run has complete records; startup/menu transitions are excluded. No FPS/performance result is claimed. | Metric per run | development base @ 514591a3 (original matcher) | development base @ 514591a3 + this PR @ 4b3729ff | |---|---|---| | Stable shader switches checked | 45, 49 | 31, 49 | | Large chroma steps at switches (>1 capture code) | 45, 37; median **41** | 0, 0; median **0** | | Median absolute chroma step | 2.12625, 3.05500; median **2.59063** | 0.03625, 0.03251; median **0.03438** | | Maximum absolute chroma step | 5.06750, 4.37625 | 0.12250, 0.08876 | The metric is the median block change in R-minus-B over 98 blocks of 20x20 pixels, taking the largest absolute step within five frames of each logged shader switch. Counts are detections at transitions, not independent flash episodes. The diagnostic control also matched all 45 stable switches to the expected warmer/cooler direction at the fixed one-frame capture offset. Raw PQ samples support relative colour comparison, not calibrated brightness. How to reproduce: load child Link in the ranch alley facing the entrance, tilt toward the ground, pan left/right, then raise the view toward the sky and repeat. On main, the image alternates curves; here both permutations retain PsychoV35. For the game-free regression, run `python -I -B tests/test_scene_tonemap_pass.py` with the new synthetic fixture: it fails unchanged current main at the adapted-exposure assertion and passes here. ```text original: program 7370b01162e62427: scene tone map left as the game's: the fit's input is not times a constant fixed: program 7370b01162e62427: scene tone map PsychoV35 fixed: program 672e593076ac390a: scene tone map PsychoV35 ``` ## Testing **Tested:** two paired in-game runs above; original recorded reproduction; renderer pack built and linked with zero compiler failures; synthetic interpreted outputs agree with PsychoV35 at the complete adapted gain; unsupported graphs remain unchanged. Full `python -I -B tests/run_all.py`: **521 passed / 6 failed / 34 skipped** here and **the same results and failures on clean main 0caf0618**. Shared failures: `test_framegen_resources`, `test_module_ids`, `test_oot_state_tap`, `test_pad_layout`, `test_release`, `test_tested_configurations`. No PR-only failure. Final focused matcher test passes. New run files validate through `scripts/tested_configurations.py`; the catalogue unit retains main's Windows ASCII-pipe CRLF failure. **Not tested:** Linux, AMD/Intel, a fresh full current-main game build, or long gameplay beyond the captured views. The reported Lake Hylia/Field transition symptom needs a retest; the newer log's occasional format fallback is a separate lead. This PR addresses the recorded shader-permutation flashes. **Needs other testers:** Linux C++20 game-free matcher build/regression: T-S724. Run the development guide's game-free check selection `python -I -B tests/run_all.py scene_tonemap` on this branch and report compiler/OS/result. No GPU or game dump is needed. A maintainer must add `testing wanted` before the request can be claimed. Linux gameplay remains untested. ## Screenshots A local before/after comparison is prepared. Awaiting explicit permission to attach it; keeping this PR WIP until it is attached. ## Risk and rollback The matcher now accepts one additional, narrowly constrained exposure shape. Incorrectly accepting a different shape could change its colour; shared RGB exposure/adaptation checks, the existing scene/luminance/peak guards and negative fixtures limit that risk. Select Vanilla to bypass PsychoV35, or revert this commit. Translator changes invalidate the shader cache normally. ## Reviewer notes Read the matcher and `tests/scene_tonemap_ir.cpp` first. No host runtime, platform interface or shipped GLSL/SPIR-V file changes. The earlier hue-continuity experiment is not included: it did not eliminate the reported flashes. No merge or auto-merge requested. ## Issues See https://git.magicbean.dev/MagicBeanDev/Longshot/issues/344 ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [ ] Screenshots for a change that shows on screen. (comparison prepared; attachment permission pending) - [x] A file in `docs/tested/` for each new measured run (format in `docs/tested-configurations.md`; no appended row or assembled view). - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows passes; Linux coverage requested as T-S724) - [x] Docs updated.
fix(vk): apply PsychoV35 to the adapted scene permutation
Some checks failed
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request_target) Has been skipped
PR description / Description follows the template (pull_request_target) Failing after 3s
4b3729ffca
Recognize the shared exp2 exposure multiplier around the existing scene
and base-exposure product. Keep the complete gain in the PsychoV35
anchor so camera-driven permutation changes retain the selected curve.

Require the same base exposure and adaptation value across RGB, preserve
the peak-bank guard and leave unsupported shapes untouched. Cover both
product orders, early colour writes, adapted gains and rejected shapes
with synthetic IR regressions.

Assisted-by: OpenAI Codex
Author
Member

Local validation is complete: original/fixed/original/fixed yielded 45 and 37 large chroma-step detections versus zero in both fixed runs; full suite has the same six failures on the PR and clean main. The fixed renderer applies PsychoV35 to both scene permutations. Description/checklist now explicitly retain Linux build coverage as pending T-S724; could a maintainer add testing wanted so the game-free Linux check can be claimed? The prepared comparison image is awaiting explicit attachment permission. Keeping WIP until both applicable boxes are settled.

Local validation is complete: original/fixed/original/fixed yielded 45 and 37 large chroma-step detections versus zero in both fixed runs; full suite has the same six failures on the PR and clean main. The fixed renderer applies PsychoV35 to both scene permutations. Description/checklist now explicitly retain Linux build coverage as pending T-S724; could a maintainer add testing wanted so the game-free Linux check can be claimed? The prepared comparison image is awaiting explicit attachment permission. Keeping WIP until both applicable boxes are settled.
HumanBean changed title from WIP: fix(vk): apply PsychoV35 to the adapted scene permutation to fix(vk): apply PsychoV35 to the adapted scene permutation 2026-11-14 11:19:23 +00:00
HumanBean deleted branch codex/psychov35-scene-variants 2026-11-14 11:19:28 +00:00
Some checks failed
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request_target) Has been skipped
PR description / Description follows the template (pull_request_target) Failing after 3s
Some workflows are waiting to be reviewed.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!400
No description provided.