Strike R5's tiling clauses, which the frame budget argues against

R5 asks that the application work on downscaled proxies for display, and its
criterion stated that in two parts: the display pipeline operates at viewport
resolution, and only visible tiles are computed with panning recomputing only
newly exposed ones. The first is built and pixel-equality tested. The second is
not, and should not be.

This is the same correction FR-DSP-2 already received, applied to the
requirement that FR-DSP-2's tiling clause traces back to. frame-budget.md
measured the case tiling exists for: recomputing the whole 4K viewport costs
4.5 ms of a 16 ms budget, so a perfect tile cache could save at most 4.5 ms in
exchange for a cache keyed by (VersionId, tile, zoom, graph_hash_prefix) that
must stay correct across every parameter change in the graph.

For the one stage that does exceed the budget it is worse than useless. That
stage is a convolution, and a tiled convolution reads a halo per tile: at the
52 px radius measured at 4K, 256 px tiles read (256+104)² taps instead of 256².

The intent is not removed — a display path that does work proportional to the
source image is still forbidden, and that is what the remaining clause says.
What is removed is a mechanism written in as though it were the only way to
get there, and which measurement says is the wrong one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-30 10:21:06 +02:00
co-authored by Claude Opus 5
parent 99563b33f7
commit 99f9b5b7c5
+26 -1
View File
@@ -55,7 +55,7 @@ These are the user's stated requirements, restated as testable criteria.
| **R2** | Efficient display of huge RAW libraries | A 50,000-image catalog scrolls at 60fps sustained, with a stated prefetch margin and cache-hit rate sufficient that no cell renders as a placeholder at a scroll velocity of *(figure TBD)* rows/second. Catalog opens in under 2s. |
| **R3** | Make a RAW beautiful at 8-bit output | Full non-destructive develop chain at high internal precision, with camera input profiles (FR-DEV-3e) and a colour-managed path to 8/16-bit export. |
| **R4** | HW acceleration and parallelism | All per-pixel work runs on GPU compute. CPU work (decode, I/O) is parallelised across cores. The UI executor never blocks on image work (NFR-ARCH-1). |
| **R5** | Work on downscaled proxies for display | Display pipeline operates at viewport resolution, not source resolution. Only visible tiles are computed; panning recomputes only newly exposed tiles. |
| **R5** | Work on downscaled proxies for display | Display pipeline operates at viewport resolution, not source resolution. The tiling clauses this criterion used to carry have been struck — see below. |
| **R6** | Nextcloud integration | Browse, download, and upload images and edit metadata against a Nextcloud instance, offline-capable. |
**On R1's tolerance.** An earlier draft required output to be *bit-identical* across platforms.
@@ -72,6 +72,31 @@ Where genuine bit-identity is required — cache keys, edit-graph hashing (§5.2
applies to *integer* operations on CPU-side state, which are deterministic, never to GPU float
results.
**On R5's tiling.** An earlier draft added two clauses to R5's criterion: *"only visible tiles are
computed; panning recomputes only newly exposed tiles"*. They have been struck, and the reason is
the same one that FR-DSP-2 was rewritten for rather than implemented — [frame-budget.md](frame-budget.md)
measured it.
R5's actual demand is met and tested. The display pipeline works at viewport resolution:
`Framing::view` shrinks the sampled region while the render target keeps its size, so zooming raises
the resolution the pipeline works at rather than magnifying pixels already drawn, and
`core/dr-gpu/tests/zoom_resolution.rs` establishes it as a pixel equality rather than an impression
of sharpness.
Tiling is a different claim, and it was written in as though it were the mechanism by which the
first one is achieved. It is not. Recomputing the *entire* 4K viewport costs 4.5 ms of a 16 ms
budget, so a perfect tile cache saves at most that, in exchange for a cache keyed by
`(VersionId, tile, zoom, graph_hash_prefix)` that has to stay correct across every parameter change
in the graph — a large correctness surface bought with a small number. And for the one stage that
does miss the budget, tiling makes it worse: that stage is a convolution, and a tiled convolution
reads a halo per tile, so at the 52 px radius measured at 4K a 256 px tile would read (256+104)²
taps instead of 256², very nearly twice the work.
The intent behind the struck clauses — that the display path must not do work proportional to the
source image — survives in the clause that remains, which is the honest statement of it. Tiling
stays where FR-DSP-2 puts it: a scheduling concern for export and thumbnailing, both of which
already run off the frame path.
---
## 3. Functional requirements