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:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user