re: the game blends in the ENCODED space -- no gamma render target, anywhere
The Port asks whether the blend is evaluated on sRGB-encoded values or linearised and re-encoded. It is 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) on 2402/2402 splash draws and 33779/33791 draws of the boot-through-title capture; the other 12 are k_32_FLOAT and k_16_16_FLOAT and are not colour passes. k_8_8_8_8_GAMMA (1) appears ZERO times, and color_exp_bias is 0 everywhere so nothing stands in for a gamma either. The mechanism is Canary's own source, not our inference: k_8_8_8_8_GAMMA is the ONLY colour format around which a piecewise-linear gamma<->linear conversion is applied (spirv_shader_translator.h:510 PWLGammaToLinear / LinearToPWLGamma, 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 values as they are. So a renderer that linearises before blending and re-encodes after is doing a different operation -- and the difference is gamma-shaped and exactly zero on unblended pixels, which is the divergence signature the port reports. Also renamed my units-per-second pre-registration off the 'h4' prefix: the Port's BLOCKED.md numbers this blend-space question H4 and two different H4s in one corpus is how a citation goes wrong.
This commit is contained in:
80
docs/re/units-per-second-preregistration.md
Normal file
80
docs/re/units-per-second-preregistration.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Units per SECOND: is the animation clock frame-counted or time-integrated?
|
||||
|
||||
**Pre-registration. Written 2026-09-01 BEFORE the capture was taken**, per
|
||||
[`../agents/TEMPORAL-VERIFICATION.md`](../agents/TEMPORAL-VERIFICATION.md).
|
||||
Committed first so the prediction cannot be edited afterwards.
|
||||
|
||||
## The question, and why the last answer did not close it
|
||||
|
||||
[`h3-units-per-frame-measured.md`](h3-units-per-frame-measured.md) pinned **2
|
||||
declared units per guest frame**. The port needs **units per second**, and
|
||||
`units/s = (units/frame) × (frames/s)`. That is only a valid decomposition if the
|
||||
game's animation clock counts **frames**. If it integrates **elapsed time**, then
|
||||
units/second is the invariant, units/frame is an artefact of whatever rate the
|
||||
host managed, and multiplying by an assumed 30 fps is meaningless.
|
||||
|
||||
There is already evidence it is time-integrated, and it is the anomaly the last
|
||||
page had to quote as a caveat: across the empty label 5376 the plate's alpha
|
||||
moved **+82** where three adjacent labels each moved **+23**. `82 / 23 = 3.57` —
|
||||
**not an integer number of ticks**. A fixed per-frame increment cannot produce a
|
||||
fractional multiple of itself. That is suggestive and it is one observation.
|
||||
|
||||
## The instrument, and why it is not a wall clock
|
||||
|
||||
The draw logger now stamps every frame boundary with
|
||||
`Clock::QueryGuestTickCount()` and `Clock::guest_tick_frequency()` — the timebase
|
||||
the **guest** reads, 50 MHz (`emulator.cc:225`), with `guest_time_scalar_ = 1.0`
|
||||
(`clock.cc:37`, unchanged by any flag this harness passes). A duration computed
|
||||
from those is the duration **the game experienced**, which is the only one its own
|
||||
integrator could have used. No host wall clock enters the calculation.
|
||||
|
||||
⟨canary-source⟩ for the scalar and the frequency; ⟨capture⟩ for everything
|
||||
measured with them.
|
||||
|
||||
## The discriminator — within one run, no second capture needed
|
||||
|
||||
For every consecutive pair of frame labels on `ptbtn00`'s ramp, compute the
|
||||
label's **guest duration** and the **alpha step** across it. Then:
|
||||
|
||||
| if the clock is | Δα vs guest duration | what it means |
|
||||
|---|---|---|
|
||||
| **frame-counted** | **flat** — Δα ≈ 23 whatever the frame took | units/frame is the invariant; the port multiplies by an assumed fps |
|
||||
| **time-integrated** | **proportional, through the origin** | units/second is the invariant; **units/frame is not a property of the game at all** |
|
||||
|
||||
The slope of that line, if it is one, is the answer: `slope × 22 / 255` =
|
||||
**units per guest second**.
|
||||
|
||||
Frame durations under this emulator vary by a factor of several — the previous
|
||||
capture's labels ran from nominal to 3.5× nominal — so the regressor has real
|
||||
dynamic range and this is not a null test.
|
||||
|
||||
## The predictions, stated before the run
|
||||
|
||||
1. **The clock is time-integrated.** Δα correlates with guest frame duration,
|
||||
r > 0.9.
|
||||
2. **The rate is 60 units per guest second.** I accept **55–65**. This is *not*
|
||||
independent: it is what the previous capture's run-average implies (27.2
|
||||
labels/s × 2.0–2.25 units/label ≈ 54–61), so it is a consistency prediction,
|
||||
not a blind one, and I say so. What is new is that this measurement is
|
||||
per-label rather than a run average, in guest time rather than host time, and
|
||||
carries a shape test the average cannot.
|
||||
3. **120 units/s and 30 units/s are both excluded** if 1 and 2 hold.
|
||||
|
||||
**If prediction 1 fails** — Δα flat against duration — then the clock *is*
|
||||
frame-counted, `units/s` genuinely depends on the console's frame rate, and the
|
||||
+82 anomaly needs another explanation. That outcome is reportable and I will
|
||||
report it.
|
||||
|
||||
## The control that removes the test's own subject
|
||||
|
||||
The plate's ramp is short. The same regression is run **independently** on
|
||||
`ptcopyright`'s ramp in the same capture — a different element, a different
|
||||
declared segment, a different part of the screen. Two elements must give the
|
||||
**same** units/second under the time-integrated model and need not under any
|
||||
other. Disagreement between them fails the test regardless of either slope.
|
||||
|
||||
## What this still will not answer
|
||||
|
||||
The **console's** frame rate. Even a confirmed 60 units/s says nothing about
|
||||
whether the retail game ran at 30 or 60 fps; it says the port should not need to
|
||||
know, because it should drive its clock in seconds and not in frames.
|
||||
Reference in New Issue
Block a user