Specify a scene-referred pipeline (D19)

The spec missed Ansel, and with it Aurélien Pierre's argument that a
display-referred curve early in the pipeline throws away what every
later stage needs. Read against that argument, the code broke it four
ways: the base curve was flat past its last point and so clipped every
recovered highlight; the detail stage was handed curved, clipped values
while its comments promised linear ones; the edits ran in camera RGB
because the matrix had drifted to after them, against ARCH §5.2; and the
tone curve clamped to [0, 1] around a 2.2 gamma mid-chain.

D19 records the decision: unbounded scene-linear colour from the matrix
to one view transform, last, after the detail stage. FR-DEV-3j specifies
that view transform as an adjustable operation (contrast, white) with a
default fitted to where the retired default curve put middle grey.
FR-DEV-3e retires the per-body base curves, whose own file called them
hand-tuned shapes of unknown provenance. FR-DEV-3f makes a film stock
the view transform when one is chosen, instead of a rendering at order
25 that the later edits acted on. FR-DEV-2 gains the acceptance test
that holds the rule, and ARCH gains §6.14 and the corrected §5.2 order.
This commit is contained in:
2026-09-27 16:52:52 -04:00
parent 621a6b8313
commit e8898a5c38
3 changed files with 154 additions and 17 deletions
+26 -4
View File
@@ -355,11 +355,12 @@ RawImage (sensor data, CPU)
├─────────────────────┤
│ AI denoise │ optional; raw-domain, joint with demosaic where possible
├─────────────────────┤
│ camera profile │ matrices + per-body base curve (FR-DEV-3e)
│ white balance │ camera RGB: as-shot, then the operation
├─────────────────────┤
│ → working space │ linear, wide-gamut, f16
│ camera profile │ the matrix (FR-DEV-3e) — no curve (D19)
├─────────────────────┤
│ → working space │ linear, unbounded, f16
├─────────────────────┤
│ white balance │
│ exposure/contrast │
│ highlights/shadows │ ← masks apply per-op from here down
│ tone curve │
@@ -368,10 +369,11 @@ RawImage (sensor data, CPU)
│ spot removal │
│ sharpen / NR │
│ lens corrections │
│ look (HaldCLUT) │ FR-DEV-3f
├─────────────────────┤
│ geometry │ crop, straighten, rotate
├─────────────────────┤
│ view transform │ sigmoid, or the film stock (FR-DEV-3j)
├─────────────────────┤
│ output transform │ → display or export profile
└─────────────────────┘
│
@@ -381,6 +383,14 @@ RawImage (sensor data, CPU)
Working precision is f16 in a linear wide-gamut space, quantising once at the output transform.
**Scene-referred until the view transform (D19, §6.14).** Everything between the matrix and the
view transform is linear and unbounded. The view transform is the one stage allowed to compress
the scene into a display range. With a detail stage it runs as a dispatch of its own after the
detail passes, generated by the same composer as the fused pass so that it gets the mask layers,
the film tables and the grain's source position. Without one it is the fused pass's tail. Both
the view transform and the output transform (primaries, gamut clip, encode) come after
everything that reads a neighbourhood.
**A hot or dead photosite is repaired before the demosaic, not after.** Past it, one photosite of
nonsense is a coloured cross three pixels wide that no later stage can tell from detail. The pass
(`shaders/hot_pixels.wgsl`, run by `Demosaicer::run` into a second buffer) replaces a photosite that
@@ -1255,6 +1265,17 @@ differently, f16 rounding varies. Cache keys and graph hashes are computed over
state, which is exactly deterministic. Cross-platform *rendering* equality is a bounded tolerance
(R1), not a checksum.
### 6.14 Scene-referred until the view transform
Added 2026-09-27 (D19). Between the camera matrix and the view transform, values are scene-linear
and unbounded, and no operation clamps above 1.0, applies a transfer function or maps to a display
gamut. The view transform (FR-DEV-3j) is the one stage that does, and the output transform after
it clips and encodes. This is the constraint the base curve broke and ARCH §5.2 had drawn all
along: a display-referred curve in the middle of the chain throws away what every later stage,
the neighbourhood ones above all, needs. A test (`scene_referred_until_the_view`) runs every point
operation over a ramp to 16.0 so that a fragment that clips fails the build rather than the
photograph.
---
## 13. Decisions
@@ -1278,6 +1299,7 @@ Full rationale in [requirements.md §8](requirements.md). Summary:
| D13 | Face inference runtime and model licensing | **Runtime answered**, reopened for per-device backends (docs/inference.md); licensing open |
| D14 | Segmentation source for local masking | Decided — arm C (docs/segmentation.md §14) |
| D15 | Target devices — 12-inch tablet and desktop, no phone | Decided (requirements D15) |
| D19 | Scene-referred pipeline, one view transform last | Decided (requirements D19) |
---