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.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user