Record what per-display colour actually cost

The status table said FR-DSP-8 was absent and §5.2 assumed Slint
reports window moves. It does not — there is no `on_moved` on any
backend — so the position is sampled instead.

§5.4 records the two trades that are worth someone finding later: a
display profile is matched to the nearest of four spaces rather than
applied through a CMM, and on Wayland the canvas follows the first
output rather than the window, because a Wayland client is never told
where its window is and the protocol's own answer needs a `wl_surface`
that Slint does not expose.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-27 19:03:24 +02:00
co-authored by Claude Opus 5
parent 3e5840e413
commit b858fc029a
3 changed files with 52 additions and 19 deletions
+33 -4
View File
@@ -26,7 +26,7 @@ and the reason is that some of the work is done and untagged.
| FR-DSP-5 zoom and pan | **Substantially done, untagged.** `Framing::view` shrinks the sampled region while the render target keeps its size, so zooming *raises* the resolution the pipeline works at. That is FR-DSP-5's requirement, arrived at without tiles. |
| FR-DSP-6 colour management | **Done.** Output space is a parameter of composition. |
| FR-DSP-7 histogram and clipping | **Done**, GPU-side, no per-frame readback. |
| FR-DSP-8 per-display colour | **Absent.** One transform, not per-display. |
| FR-DSP-8 per-display colour | **Done**, with one caveat named in §5.4. Acquisition per display server, an sRGB fallback that is visible in About, and the canvas rendered at physical pixel size. |
| FR-PLG-* | **Zero tagged.** But `ops/*.yaml` + `build.rs` is already the class-1 plugin format compiled at build time rather than loaded. |
Two of the five uncovered display requirements are therefore *measurement and tagging*, not
@@ -119,15 +119,44 @@ stated in the About page beside the other diagnostics so a photographer can see
on rather than wonder.
**5.2 Reacting to a move.** The transform is selected per the display currently showing the canvas
and updates when the window moves. Slint reports window moves; the composed output space is already
a parameter of composition (`compose_with_framing(..., output)`), so a display change is a
recomposition, not a pipeline change. This is the part the existing design makes cheap.
and updates when the window moves. The composed output space is already a parameter of composition
(`compose_with_framing(..., output)`), so a display change is a recomposition, not a pipeline
change. This is the part the existing design makes cheap.
Slint turned out *not* to report window moves — there is no `on_moved` on any backend — so the
window's position and scale factor are sampled twice a second and the platform re-surveyed only when
they differ. See §5.4 for the display server where the position itself is unavailable.
**5.3 Fractional scaling.** "Handled without resampling artefacts in the canvas" — the canvas is a
wgpu texture handed to the compositor, so the requirement is that we render at the *physical* pixel
size rather than the logical one and let the compositor present 1:1. Worth an explicit test, since
the failure is subtle: a slightly soft canvas that looks like a bad demosaic.
### 5.4 What landed, and the one thing that did not
`dr_plat::display` surveys the session's displays; `dr_ui::display_ui` decides which one is showing
the canvas and keeps `DevelopSession`'s output space pointed at it. Composition was already
parameterised on the space, so the pixel path changed by one argument.
Two things are worth recording because they are trades rather than omissions.
**A profile is matched to the nearest of four spaces, not applied.** A measured panel is none of
`Srgb`, `DisplayP3`, `AdobeRgb` or `ProPhoto`, and a general ICC engine is a much larger piece of
work — a CMM, rendering intents, LUT-based profiles, and a per-frame cost to argue about. The
profile is reduced to its D50-adapted colorants and matched against the four; a match that is merely
nearest is marked as such, and About says "nearest to Display P3" rather than "Display P3". A
LUT-based profile, which is what a hardware calibrator often writes, is declined by shape and falls
back to sRGB with that stated. An approximation the photographer can see beats a silent one.
**On Wayland the canvas follows the first output, not the window.** A Wayland client is never told
where its window is — `xdg_toplevel` carries no position, deliberately — so the "which display"
question cannot be answered by geometry there. The protocol's own answer is
`wp_color_management_surface_feedback_v1`, which hands a client the preferred image description for
*its surface* and re-sends it on a move; it needs the application's `wl_surface`, which Slint owns
and does not expose. So the profiles are read correctly for every output and the *selection* among
them is right on X11 and on any single-monitor Wayland session, which is most of them. Closing the
gap is a Slint surface handle, not a change to any of this.
---
## 6. Extensibility: the format already exists