The port pre-registered a test and ran it: against live-splash-publisher.png a cropped render scores RMSE 558.1 (0.85%) and a scaled one 10118.8 (15.4%). Cropping is 18x better. Confirmed here independently, from a different observable: the committed captures are 1279x675, 1280x690 and 1252x754. VARYING heights. A fixed presenter resample produces one size; crops of differently-sized windows produce exactly that spread. And ui-render-tone-curve.md had already recorded every capture aligning at dy=0 dx=0 with correlation 0.9466, which a 0.9375 vertical scale cannot produce -- the evidence was in the corpus before I wrote the claim. So the captures are crops of a 1:1 surface, and every RMSE, glyph count and surface mean against them is pixels to pixels with no filter to caveat. The blanket "everything measured off a PNG carries the resample" is withdrawn. Not refuted: the cvar reading. Canary does letterbox by default. What is refuted is my inference that the corpus's capture path went through it. Whether the presenter is bypassed, the window is 1:1, or the tool crops before saving is open and unestablished. The error is the one this session keeps paying for: I read a configuration and inferred a consequence FOR THE DATA without testing it against the data. The test costs one render and one RMSE and I had every capture needed to run it. Also downgrades my refutation of the corpus's oracle principle from "survives with a qualifier" to "survives, and my qualifier was wrong", kept rather than deleted because the failure is the instructive part. Section 1 (gamma: VdGetCurrentDisplayGamma is kStub, the splash shader has no pow/ramp/lookup) and the two-path distinction stand unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
144 lines
6.9 KiB
Markdown
144 lines
6.9 KiB
Markdown
# What Canary does between the guest's draw and a captured pixel
|
||
|
||
> # 🔴 CORRECTION 2026-09-02, same day — §2's CONSEQUENCE is REFUTED
|
||
>
|
||
> I wrote that the presenter's letterbox-and-scale is in the capture path, that
|
||
> it explains the 1279×675 surface, and that **"everything measured off a PNG
|
||
> carries the resample."** The port pre-registered a test and ran it: against
|
||
> `live-splash-publisher.png`, a **cropped** render scores RMSE **558.1 (0.85 %)**
|
||
> and a **scaled** one **10 118.8 (15.4 %)**. **Cropping is 18× better.**
|
||
>
|
||
> ✅ **Confirmed independently here, from a different observable.** The committed
|
||
> captures are **1279×675**, **1280×690**, **1252×754** — *varying* heights. A
|
||
> fixed presenter resample produces one size; **crops of differently-sized
|
||
> windows produce exactly this spread.** And `ui-render-tone-curve.md` already
|
||
> recorded every capture aligning at `dy=0 dx=0`, correlation 0.9466, which a
|
||
> 0.9375 vertical scale cannot produce. The evidence was in the corpus before I
|
||
> wrote the claim.
|
||
>
|
||
> **So the captures are CROPS of a 1:1 surface, not resamples**, and every RMSE,
|
||
> glyph count and surface mean against them is pixels to pixels with no filter to
|
||
> caveat.
|
||
>
|
||
> ⚠️ **What is NOT refuted:** the cvar reading itself. Canary *does* letterbox by
|
||
> default. What is refuted is my inference that the corpus's capture path went
|
||
> through it. Whether the presenter is bypassed, the window is 1:1, or the tool
|
||
> crops the letterbox before saving is **open and unestablished**.
|
||
>
|
||
> 🔴 **The error is the one this session keeps paying for.** I read a
|
||
> configuration and inferred a consequence *for the data* without testing it
|
||
> against the data — the same shape as reading a base-address change as a decode.
|
||
> The test that refutes it costs one render and one RMSE, and I had every capture
|
||
> needed to run it.
|
||
>
|
||
> §1 (gamma) and the two-paths distinction in §3 stand; §3's blanket caveat does
|
||
> not. Corrected in place below.
|
||
|
||
|
||
|
||
**Status: ✅ decoded from Canary's own source.** Instrument: ⟨canary-source⟩,
|
||
with ⟨capture⟩ for the dumped guest shader. 2026-09-02.
|
||
|
||
Answers question 3 of [`../agents/PLAYTEST-2026-09-02.md`](../agents/PLAYTEST-2026-09-02.md)
|
||
— *"present cadence, and any resolve, scale or gamma between the guest's draw and
|
||
a capture's pixels."*
|
||
|
||
---
|
||
|
||
## 1 — gamma: **Canary applies none**
|
||
|
||
`VdGetCurrentDisplayGamma` is the export the play-test warns about. Reading it:
|
||
|
||
```cpp
|
||
void VdGetCurrentDisplayGamma_entry(lpdword_t type_ptr, lpfloat_t power_ptr) {
|
||
*type_ptr = cvars::kernel_display_gamma_type; // default 2 = TV (BT.709)
|
||
*power_ptr = float(cvars::kernel_display_gamma_power);
|
||
}
|
||
DECLARE_XBOXKRNL_EXPORT1(VdGetCurrentDisplayGamma, kVideo, kStub);
|
||
```
|
||
|
||
**It is declared `kStub` and it transforms nothing.** It *reports* a gamma type to
|
||
the guest, which D3D would use to build a ramp. So the question becomes whether
|
||
the **guest** applies one — and for the splash it demonstrably does not. The
|
||
splash pixel shader, dumped from the running game, is four ALU ops:
|
||
|
||
```
|
||
tfetch2D r2, r1.xy, tf0
|
||
mul r1.___w, r2.wwww, r0.wwww
|
||
mul r0.xyz_, r2.xyzz, r0.xyzz
|
||
mul r1.xyz_, r0.xyzz, r1.wwww
|
||
max oC0, r1, r1
|
||
```
|
||
|
||
**No `pow`, no ramp, no lookup.** Nothing in the splash path applies gamma —
|
||
neither side of the emulation boundary.
|
||
|
||
## 2 — geometry: ⚠️ the presenter CAN resample, but the corpus's captures are CROPS
|
||
|
||
`presenter.cc` defaults:
|
||
|
||
| cvar | default | effect |
|
||
|---|---|---|
|
||
| `present_letterbox` | **true** | aspect preserved, bars added rather than stretching |
|
||
| `present_safe_area_x` / `_y` | **100** | nothing cropped |
|
||
|
||
So Canary *would* scale the guest's 1280×720 to fit the host window and letterbox
|
||
it. 🔴 **But the committed captures did not go through that**, per the correction
|
||
above — they are crops. The 1279×675 surface is a **cropped window grab**, not a
|
||
scaled one, which the varying capture sizes (1279×675, 1280×690, 1252×754) show
|
||
directly.
|
||
|
||
⚠️ **The `wait_title.sh` single-pixel failure is still real** and still explained:
|
||
a coordinate valid at 1280×720 lands outside a 1279×675 *crop* just as surely as
|
||
outside a scaled one. The failure was the fixed coordinate, not the transform.
|
||
|
||
## 3 — 🔴 So there are TWO measurement paths, and only one has Canary in it
|
||
|
||
| path | route | Canary processing |
|
||
|---|---|---|
|
||
| **pixels** | guest draw → EDRAM → resolve → front buffer → **presenter (scale + letterbox)** → X11 → `screenshot` → PNG | **a resample**, plus whatever the window system does |
|
||
| **vertex stream** | guest CPU writes a vertex buffer → **the draw logger reads guest memory directly** | **none** |
|
||
|
||
📌 **The per-frame alpha series is the second path.** The `k_8_8_8_8` colour is
|
||
read out of the guest's own vertex buffer *before* it reaches a shader, a render
|
||
target, a resolve or the presenter. **There is no Canary processing between the
|
||
guest's intent and that number** — which is why
|
||
[`splash-interpolates-every-frame.md`](splash-interpolates-every-frame.md) can
|
||
state per-frame alphas as the game's values rather than as pixels we measured.
|
||
|
||
🔴 **The blanket caveat I attached here is WITHDRAWN.** I claimed everything
|
||
measured off a PNG carries a resample. It does not: the captures are crops, and
|
||
pixel-exact comparison against them is pixels to pixels. The two-path
|
||
*distinction* stands — the vertex stream still has strictly less between the
|
||
guest and the number — but the practical gap is far smaller than I said, and a
|
||
large body of shared evidence needs no qualifier.
|
||
|
||
## Refutation attempt, recorded per the adversarial duty
|
||
|
||
**Target:** this corpus's own founding principle, stated at the top of three
|
||
documents — *"the oracle is the real game running in Xenia Canary, captured."*
|
||
|
||
**Result: it SURVIVES, and my proposed qualifier was WRONG.** I claimed a PNG
|
||
capture is "the oracle plus a resample". The port tested it and it is not — the
|
||
captures are crops, and the principle needs no amendment. Recorded as a failed
|
||
refutation rather than deleted, because the failure is instructive: I tried to
|
||
attach a caveat to a large body of evidence on the strength of a config file, and
|
||
the check that would have stopped me was one render and one RMSE.
|
||
|
||
**The vertex stream is still the cleaner instrument** — strictly less sits between
|
||
the guest and the number — but that is now a statement about robustness, not a
|
||
correction to anything measured.
|
||
|
||
## Reach
|
||
|
||
⟨canary-source⟩ for the gamma stub and the presenter defaults — these are facts
|
||
about *this build*, and a different `--present_*` or `kernel_display_gamma_type`
|
||
would change them. ⟨capture⟩ for the shader, which is the splash's; **other
|
||
screens' shaders have not been checked for gamma** and the negative in §1 covers
|
||
the splash only.
|
||
|
||
❔ **Not measured here: the resample's actual filter.** I read the cvars that say
|
||
scaling happens, not the kernel that does it. What a 1280×720 → 1279×675 resample
|
||
does to a thin glyph is unquantified, and that is the number anyone doing
|
||
pixel-exact work against a PNG would need.
|