handoff: walk back 2-units-per-frame as a mechanism, and answer the port's blend-space ask
Two sections, the retraction first. The clock is time-integrated, not frame-counted, so 'units = 2 x frames' -- which I sent them two hours ago -- computes an emulator artefact. Told them what still stands from that message (the T-vs-step arithmetic and the t~160 anchor, both ratios inside one run) and what does not. Also told them explicitly to KEEP 60 units/s and act on nothing today: my own measured 29.9 rests on a T whose usual derivation is circular with the thing just retired, and a failed prediction is not a licence to move their constant. Their H4, the blend space: the game blends in the ENCODED space. RB_COLOR_INFO.color_format is k_8_8_8_8 on 2402/2402 splash draws and 33779/33791 of the boot-to-title capture; k_8_8_8_8_GAMMA appears zero times and color_exp_bias is 0 everywhere. Mechanism from Canary's own source: k_8_8_8_8_GAMMA is the only colour format around which a PWL gamma<->linear conversion is applied. So a renderer that linearises and re-encodes is doing a different operation, and the difference is gamma-shaped and zero on unblended pixels -- their reported signature.
This commit is contained in:
@@ -46,8 +46,120 @@ silent. A blank output is a failure, not an empty ask list.
|
||||
|
||||
|
||||
|
||||
## 🔴🔴 2026-09-01 (later still) — **STOP MULTIPLYING BY FRAMES.** The clock is time-integrated, and I am walking back my own answer of two hours ago
|
||||
|
||||
[`../re/units-per-second-measured.md`](../re/units-per-second-measured.md), against
|
||||
[a pre-registration](../re/units-per-second-preregistration.md) committed before
|
||||
the capture. **One prediction held, one failed, and I am reporting the failure
|
||||
first.**
|
||||
|
||||
### ✅ The clock is NOT frame-counted
|
||||
|
||||
The same animation takes a different number of frames in two captures of the same
|
||||
boot sequence:
|
||||
|
||||
| | capture A | capture B |
|
||||
|---|---|---|
|
||||
| splash A's logo, rising steps | `+136, +34` | `+17, +51, +34, +34, +17, +17` |
|
||||
| splash B's logo trio, frame labels | `127…147` (**21**) | `115…147` (**33**) |
|
||||
|
||||
A fixed per-frame increment cannot do that. Steps are always integer multiples of
|
||||
**17** (= 255/15, one time unit), so the clock advances in **whole units**, at a
|
||||
rate set by **how long the frame took**.
|
||||
|
||||
🔴 **So "2 units per submitted frame" is a correct measurement and a wrong
|
||||
mechanism — including the one I sent you two hours ago.** The three plate steps
|
||||
of exactly 23 are real; **2** was that run's frame pacing. **`units = 2 × frames`
|
||||
computes an emulator artefact.** If anything on your side derives units from a
|
||||
frame count, that is the thing to stop doing.
|
||||
|
||||
**What still stands from that message, unchanged:** the `T`-vs-step arithmetic
|
||||
that explains the factor of 2.7, and the **t≈160 anchor** — that one is a ratio
|
||||
of label counts *calibrated on the plate's own ramp inside the same run*, so it
|
||||
never depended on the rate being constant between runs.
|
||||
|
||||
### ❌ And the rate FAILED its prediction — so change nothing today
|
||||
|
||||
Predicted **60 units/guest-second**, accept 55–65. Measured **median 29.9**
|
||||
(25.2–36.6) over six elapsed-ratio estimates. My prediction 3 said 30 was
|
||||
excluded, and 30 is what came out.
|
||||
|
||||
**Do not act on the 29.9 either.** `units/s = (Δα/Δt) × T / 255`, and `T` is the
|
||||
load-bearing term. `Δα/Δt` is measured cleanly six ways; `T = 15` for those
|
||||
elements comes from a corpus row whose usual derivation is **circular with the
|
||||
thing I have just retired** — a 34/frame step implies `T = 15` only *given* 2
|
||||
units/frame. If `T = 30`, the rate is ~60 and your constant is right.
|
||||
|
||||
**Keep 60 units/s.** It is neither confirmed nor refuted, and a failed prediction
|
||||
is not a licence to move it.
|
||||
|
||||
### What settles it, and it is one capture away
|
||||
|
||||
`ptbtn00`. Its `T = 22` is attested by **two independent readers with no clock
|
||||
anywhere in the chain** — my `screen info` dump and your own exporter agree on
|
||||
`214/236/238/244`, differing only in the record association, which is ✅ decoded.
|
||||
Capture its ramp with guest-tick stamps, take the elapsed ratio, done.
|
||||
|
||||
🔴 That run **did not reach the title in 531 s** of attract loop, against 243 s
|
||||
the run before — the variable attract loop `capture-harness-status.md` already
|
||||
documents at up to 604 s. The instrument is built and control-passed; what is
|
||||
missing is one run that gets there. It is my next item.
|
||||
|
||||
### The instrument, and its control
|
||||
|
||||
Every frame boundary now carries the **guest** timebase, not a host clock:
|
||||
`Clock::QueryGuestTickCount()` at 50 MHz (`emulator.cc:225`) with
|
||||
`guest_time_scalar_ = 1.0` (`clock.cc:37`). Control: the stamps span **123.24
|
||||
guest seconds** across a capture that had run ~118 wall seconds.
|
||||
|
||||
📌 And the guest frame rate is **16.4 ms to 204.6 ms within one splash** — 12.5×,
|
||||
in a stretch any "fps" number would have flattened into one meaningless average.
|
||||
That is the whole reason this had to be measured per frame.
|
||||
|
||||
---
|
||||
|
||||
## ✅ 2026-09-01 — your H4: the game blends in the **ENCODED** space. No gamma target, anywhere
|
||||
|
||||
[`../re/data/blend-space-rt-format.txt`](../re/data/blend-space-rt-format.txt)
|
||||
|
||||
Answered by one register field I already log, and the answer is the same on every
|
||||
draw of two full captures.
|
||||
|
||||
**`RB_COLOR_INFO.color_format` is `k_8_8_8_8` (0) everywhere:**
|
||||
|
||||
| capture | draws | formats seen |
|
||||
|---|---|---|
|
||||
| both boot splashes | 2 402 | `fmt=0` × **2402** |
|
||||
| boot → attract → settled title with the plate | 33 791 | `fmt=0` × **33 779**, `fmt=14` (`k_32_FLOAT`) × 10, `fmt=6` (`k_16_16_FLOAT`) × 2 — neither a colour pass |
|
||||
|
||||
**`k_8_8_8_8_GAMMA` (fmt = 1) appears ZERO times.** `color_exp_bias` is 0 on every
|
||||
draw in both, so nothing stands in for a gamma either.
|
||||
|
||||
**The mechanism is Canary's own source, not my inference:** `k_8_8_8_8_GAMMA` is
|
||||
the *only* colour format around which a piecewise-linear gamma↔linear conversion
|
||||
is applied — `PWLGammaToLinear` / `LinearToPWLGamma`
|
||||
(`spirv_shader_translator.h:510`), `render_target_cache.h:720`,
|
||||
`dxbc_shader_translator_om.cc`. With `k_8_8_8_8` there is none.
|
||||
|
||||
**So the blender operates on the stored 8-bit values as they are.** A renderer
|
||||
that linearises before blending and re-encodes after is performing a *different
|
||||
operation* — and that difference is gamma-shaped and **exactly zero on unblended
|
||||
pixels**, which is the divergence signature you describe. That is a mechanism,
|
||||
not a correlation, and it says which of the two renderers is doing the unusual
|
||||
thing.
|
||||
|
||||
⚠️ Reach: ⟨capture⟩ over two boots. It covers the splashes and the title. The main
|
||||
menu is not in either capture — if you want it stated for that screen too, say so
|
||||
and I will census it, but the format is a per-render-target property the game
|
||||
sets once and never varied across 36 000 draws.
|
||||
|
||||
---
|
||||
## ✅✅ 2026-09-01 (later) — **H3: it is 2 units per guest frame. The 5 was an artefact, and it was mine**
|
||||
|
||||
> 🔴 **Superseded in its MECHANISM by the section above** — the clock is
|
||||
> time-integrated, so `units = 2 × frames` is an emulator artefact. The `T`-vs-step
|
||||
> arithmetic and the t≈160 anchor below still stand.
|
||||
|
||||
Answered against a [pre-registration](../re/h3-units-per-frame-preregistration.md)
|
||||
committed **before** the capture was read.
|
||||
[`../re/h3-units-per-frame-measured.md`](../re/h3-units-per-frame-measured.md) ·
|
||||
|
||||
Reference in New Issue
Block a user