Mark what is in focus, so a frame can be judged without zooming to 100%

FR-CULL-3's focus peaking. One compute dispatch measures local contrast
in WGSL and writes an overlay texture; on desktop it reaches Slint
through the same zero-copy wgpu import the canvas uses, so nothing
per-pixel touches the CPU on the frame path.

With peaking off the cost is zero and structurally so: focus_overlay
opens with `let settings = self.peaking?;` before the frame is touched,
and clearing drops both overlay textures, so no VRAM is held either.

NFR-P14 is met by construction rather than by measurement -- one
dispatch, no second render, no pipeline compile after session open, and
a test asserting allocations stay at 2 over eight frames. The budget
test asserts 50ms at 4K rather than a tight bound, deliberately: a tight
bound fails on a loaded machine and gets deleted, which is worse than a
loose one that still catches the regression that matters.

TD-1 is amended rather than joined by a TD-6: on Android the overlay
rides the readback that already exists there, roughly doubling that
transfer while peaking is on, and TD-1's own "Done when" removes both
because both are the same missing capability.

Verified: cargo fmt clean; clippy --workspace --all-targets -D warnings
green, which also compiles peaking.slint through dr-ui's build.rs; 11
focus GPU tests and 79 baseline dr-gpu tests pass; 511 dr-ui tests pass.
Not verified: the cfg(target_os = "android") arm, which the host-target
clippy never compiled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-29 21:43:08 +02:00
co-authored by Claude Opus 5
parent 5133e53bc8
commit 2168cdd1c4
9 changed files with 1781 additions and 1 deletions
+21
View File
@@ -55,6 +55,27 @@ readback is at viewport resolution, not sensor resolution. The 7.43 ms at 4K in
not the bill. **It has not been measured on the device**, which is the first thing to do if the
develop view feels heavy on the tablet; do not assume this is the cause without a number.
### And a second transfer, while focus peaking is on
Added 2026-08-29 with FR-CULL-3. The focus-peaking overlay is a compute pass writing its own
`Rgba8Unorm` texture, which on desktop reaches the compositor with no copy — but on Android there is
no more a path for *that* texture than for the frame it belongs to, and an overlay that stayed on
the device while the picture underneath it did not would simply never be seen. So
`FocusPeakPass::read_overlay` follows the frame back through memory, and the Android frame path
carries **two** full-resolution `copy_texture_to_buffer` transfers instead of one.
This is recorded under TD-1 rather than as its own entry because it is not an independent choice.
It exists only because TD-1 exists, it is bounded by the same thing — `render` fits the pass to the
canvas, so both transfers are at viewport resolution — and TD-1's "Done when" already covers it:
whichever of the three fixes above lands removes the readback for the frame and the overlay
together, because both are the same missing capability.
Two things worth saying plainly. The doubling is **reasoned, not measured on the device** — the same
gap TD-1 admits about its own cost, and the reason neither number should be quoted as a measurement.
And it is paid only while the photographer has the overlay switched on: `DevelopSession::focus_overlay`
returns on its first line when peaking is off, so with it off there is no dispatch and no transfer,
and the Android frame path is exactly what it was before this feature existed.
### Paying it off
Any one of these removes it: