From 93b0a6b20f9e78106a7d4ea625547b327493eb03 Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Sat, 29 Aug 2026 02:44:30 +0000 Subject: [PATCH] re(ui): the gamma confound is refuted from source -- canary applies none of its own I had parked the tone-curve finding behind "this may be the emulator, not the game: canary applies kernel_display_gamma_type = 2 (BT.709) on output", with a planned run setting it to 0 and re-fitting. Reading the source kills both the confound and the experiment. VdGetCurrentDisplayGamma_entry is a kStub GETTER the guest calls (xboxkrnl_video.cc). Its own comment: "Used in D3D SetGammaRamp/ SetPWLGamma to adjust the ramp for the display." The cvar is a value REPORTED TO THE GAME, which then builds its own ramp. Canary's role is downstream: the guest writes DC_LUT, command_processor.cc reads it into gamma_ramp_256_entry_table_, and the swap path applies it via swap_apply_gamma_pipeline_layout with apply_gamma_table.ps / apply_gamma_pwl.ps compiled in. So there is no emulator-side BT.709 post-process to subtract, and any gamma in a captured frame is a ramp the game installed. What is NOT established, and the reach is stated: that this game installs a ramp at all, or that the measured 1.34-1.49 is it. The run logs cannot say -- kernel exports log at Debug and this harness masks Kernel logging (log_mask = 13, per boot_menu.sh's own comment), so their silence is guaranteed regardless of what the game did. The planned experiment was wrong in design: changing the cvar changes what the GUEST is told and therefore which ramp the GAME builds, so it could never isolate a stage that does not exist -- and it perturbs the capture harness, since skip_intro classifies movie-vs-static on an absolute rmse threshold that a brighter frame biases. The right run changes nothing about the output: LOG_MASK=12 LOG_LEVEL=3 and look for the call and the DC_LUT writes. Also for the port: the ramp depends on the display type the game is told, and canary hard-codes TV/BT.709 where hardware uses a console setting. So this is a display profile, not a fixed property of the game. METHOD: read what a cvar does before building an experiment around it; and an absence in a log is only evidence if the log would have shown it. --- docs/port/HANDOFF.md | 17 ++++-- docs/re/METHOD.md | 13 +++++ docs/re/REFUTED.md | 7 +++ docs/re/structures/ui-render-tone-curve.md | 63 ++++++++++++++++++---- 4 files changed, 87 insertions(+), 13 deletions(-) diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index 185fc50a..22ac327f 100644 --- a/docs/port/HANDOFF.md +++ b/docs/port/HANDOFF.md @@ -230,9 +230,20 @@ authored version can be deleted. 9.02). Nothing here constrains midtones or highlights. ๐Ÿ”ด The held-out control **failed to discriminate**: the splash's 2 918 flat patches are pure black (render 0โ€“4), so every model scores โ‰ˆ 0. - โ” **It may be the emulator, not the game.** Canary applies - `kernel_display_gamma_type = 2` (BT.709) on output. The discriminating run โ€” - set it to `0` and re-fit โ€” was not done. + ๐Ÿ”ด **My "it may be the emulator" caveat is withdrawn.** I said canary applies + `kernel_display_gamma_type = 2` (BT.709) on output. It does not โ€” that cvar is + a value a **kStub getter reports to the guest** (`VdGetCurrentDisplayGamma`), + which the game uses to build its own ramp; canary then applies **the guest's** + ramp from the `DC_LUT` registers in the swap path (`apply_gamma_table.ps` / + `apply_gamma_pwl.ps`). So there is no emulator post-process to subtract, and + any gamma in a capture is one the game installed. + ๐ŸŸก Still not established: that this game installs a ramp at all, or that + ฮณ โ‰ˆ 1.4 *is* it. The run logs cannot say โ€” kernel exports log at Debug and the + harness masks Kernel logging โ€” so that absence means nothing. + โš ๏ธ Note the ramp depends on the display type the game is *told*; canary + hard-codes TV/BT.709, which on hardware is a console setting. **So this is a + display profile, not a fixed property of the game** โ€” reasonable to expose as a + setting rather than bake in. [`structures/ui-render-tone-curve.md`](../re/structures/ui-render-tone-curve.md) * ๐ŸŸก **`screen render` silently drops one full-screen element per screen โ€” and diff --git a/docs/re/METHOD.md b/docs/re/METHOD.md index 78afb281..d4c57522 100644 --- a/docs/re/METHOD.md +++ b/docs/re/METHOD.md @@ -611,3 +611,16 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the ratio equally and drives *any* value toward 1, and fitting a noise term showed both hypotheses reproduce the observed numbers. Before believing a ratio, ask what it does as noise grows. +* **Read what a cvar DOES before building an experiment around it.** I planned a + run to decide whether a measured gamma was "canary's BT.709 output stage", + by setting `kernel_display_gamma_type = 0` and re-fitting. The cvar is not an + output stage: it is the value a `kStub` **getter returns to the guest**, which + the game uses to build its own ramp, and canary applies *that* ramp in the swap + path. The experiment could never have isolated a stage that does not exist โ€” + and it would have perturbed the capture harness as a side effect. One grep for + the cvar's definition replaced a planned emulator run with a better one. +* **An absence in a log is only evidence if the log would have shown it.** No + gamma lines appear in any run log here โ€” but kernel exports log at Debug and + this harness masks Kernel logging entirely (`log_mask = 13`), so their absence + is guaranteed regardless of what the game did. Check the logging configuration + before reading silence as a result. diff --git a/docs/re/REFUTED.md b/docs/re/REFUTED.md index 3684a490..a04e995d 100644 --- a/docs/re/REFUTED.md +++ b/docs/re/REFUTED.md @@ -482,3 +482,10 @@ neighbourhood, not just the line. โ€” but additive noise pushes any such ratio toward 1, and both "native + noise" and "bilinear upscale + noise" fit the observed values. The conclusion happens to be right; this test does not establish it. +* "the render-vs-capture gamma may be canary's own BT.709 output transform, since + `kernel_display_gamma_type = 2`" โ†’ **mine, and refuted from the source.** That + cvar is the value a `kStub` getter (`VdGetCurrentDisplayGamma`) hands the + **guest**; the game builds its own ramp from it and canary applies the guest's + `DC_LUT` ramp in the swap path. No emulator-side gamma post-process exists to + subtract. ๐ŸŸก Whether this game installs a ramp at all is still unestablished. + [`ui-render-tone-curve.md`](structures/ui-render-tone-curve.md) diff --git a/docs/re/structures/ui-render-tone-curve.md b/docs/re/structures/ui-render-tone-curve.md index 1a1e8611..8b390b08 100644 --- a/docs/re/structures/ui-render-tone-curve.md +++ b/docs/re/structures/ui-render-tone-curve.md @@ -61,18 +61,61 @@ So `capture โ‰ˆ 255ยท(render/255)^ฮณ` with **ฮณ โ‰ˆ 1.34 โ€“ 1.49**. * **Nothing here constrains midtones or highlights**, which is exactly where a ฮณ = 1.4 curve does its visible work. -## โ” The confound: this may be the emulator, not the game +## ๐Ÿ”ด The confound as I stated it is REFUTED โ€” canary applies no gamma of its own -The comparison is our composite against **what Xenia Canary displays**, and -canary applies its own output transform: -`kernel_display_gamma_type = 2` โ€” BT.709 (HDTV) โ€” in this container's config -(`0` linear, `1` sRGB, `3` a power set by `kernel_display_gamma_power`). +I wrote that "canary applies its own output transform: `kernel_display_gamma_type += 2` โ€” BT.709". **That is not what the cvar does.** Reading the source: -So the measured exponent may belong to canary's display stage rather than to the -game or the console. **The discriminating experiment is cheap and was not run:** -set `kernel_display_gamma_type = 0`, re-capture the same screen, and re-fit. If -the exponent collapses toward 1.0 it is canary's; if it survives it is upstream. -That needs one emulator run reaching the main menu. +```cpp +void VdGetCurrentDisplayGamma_entry(lpdword_t type_ptr, lpfloat_t power_ptr) { + // 1 - sRGB. 2 - TV (BT.709). 3 - use the power written to *power_ptr. + // Anything else - linear. + // Used in D3D SetGammaRamp/SetPWLGamma to adjust the ramp for the display. + *type_ptr = cvars::kernel_display_gamma_type; + ... +``` + +It is a **getter the guest calls** (`xboxkrnl_video.cc`, exported `kStub`). The +cvar is a value *reported to the game*, which then builds its own ramp. The +emulator's role is downstream and faithful: + +* the guest writes its ramp to the `DC_LUT` registers; +* `command_processor.cc` reads them into `gamma_ramp_256_entry_table_`; +* the **swap** (present) path applies them โ€” + `swap_apply_gamma_pipeline_layout`, with `apply_gamma_table.ps` / + `apply_gamma_pwl.ps` compiled in. + +So there is no emulator-side BT.709 post-process to subtract. Any gamma in the +captured frame is a ramp **the game installed**. + +### ๐ŸŸก What that does and does not settle + +โœ… The stated confound is gone: the measured exponent is not an emulator artefact +bolted onto the game's output. + +๐ŸŸก **Not established: that this game installs a ramp at all**, or that +ฮณ โ‰ˆ 1.34โ€“1.49 *is* that ramp. The run logs cannot say โ€” kernel exports log at +Debug and this harness masks Kernel logging (`log_mask = 13`, per +`boot_menu.sh`'s own comment), so the absence of gamma lines in them is expected +and means nothing. That is the reach of this negative. + +โš ๏ธ And the ramp a game builds depends on the display type it is *told*. Canary +hard-codes `2` (TV/BT.709); on hardware that is the console's display setting. So +the exponent is display-profile dependent **by design**, not a fixed property of +the game. + +### โœ… The corrected next experiment + +My planned run โ€” set `kernel_display_gamma_type = 0` and re-fit โ€” was the wrong +design: it changes what the *guest* is told and therefore which ramp the *game* +builds, so it could never isolate an emulator stage that does not exist. It also +perturbs the capture harness, because `skip_intro.sh` classifies movie-vs-static +on an **absolute** rmse threshold and a brighter frame biases it (see +[capture-harness-status](../capture-harness-status.md)). + +The right run changes nothing about the output: boot with `LOG_MASK=12 +LOG_LEVEL=3` (both are needed โ€” kernel calls log at Debug) and look for +`VdGetCurrentDisplayGamma` and the `DC_LUT` writes. Same frames, no perturbation. ## What a port should do with this