diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index 185fc50..22ac327 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 78afb28..d4c5752 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 3684a49..a04e995 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 1a1e861..8b390b0 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