Architecture background geometry cache
Scope: issue 44.
Production/test candidate: 636093aae67aa48fa1d35e403a205227e81d04de, based on
c0908f101ac376afb8021e60e454e2a176e49d45. The base includes the separately
unaccepted outgoing-drag contribution for issue 40. This is a contribution
experiment and repair, not an integrated release or full FPS acceptance.
Question and evidence
The preceding core probe measured approximately 4.26ms median for preparation/projection/routing in an eight-card approximation. It did not reproduce the reported severe slowdown. Source review then identified repeated grid construction on every canvas redraw, despite the grid's independence from model edits, selection and pointer position.
The standalone headless Iced probe copies the former grid loop: background fill,
then one radius-0.65 circle per grid point, with the same spacing, pan remainder
and colors. It measures geometry construction independently from offscreen
rendering/readback, using the actual compiled development-profile Iced renderer.
It creates no desktop window and sends no input. Three warmups precede 20 samples
per phase. The timer includes construction and returning geometry; returned
geometry destruction occurs afterwards. Sorted index ceil((n-1)*p) supplies
reported percentiles. Renderer startup is outside the timed phases.
grid-performance-01.log, produced by grid_render_probe_v1.rs, records:
| Canvas, zoom | Dots | Fresh geometry p50 ms | Cache retrieval p50 ms |
|---|---|---|---|
| 1900x660, 1.0 | 2,240 | 67.8095 | 0.0001 |
| 1900x660, 0.5 | 6,528 | 192.5581 | 0.0001 |
| 1440x900, 1.0 | 2,318 | 66.2206 | 0.0002 |
| 1440x900, 0.5 | 6,695 | 219.1771 | 0.0002 |
Cold and warm cached grid pixels equal the uncached result byte for byte in all four cases. Cache misses remain comparable to fresh construction; caching does not improve continuously changing camera inputs. Offscreen screenshot/readback cost remains substantial and variable. It must not be converted to native FPS.
Candidate comparison and chosen change
- Rebuild each circle every draw: exact current appearance, but the measured repeated CPU cost alone is large in this development build.
- Batch circles into one path: keeps the same pixels in this experiment but is
materially slower.
grid_render_probe.rsandgrid-performance-02.logretain this rejected candidate. Its construction medians range from 274.66ms to 1,225.53ms, versus 63.82–178.24ms for the original loop in the same run. - Cache background geometry while camera and size stay identical: selected. It preserves the original painter and removes its repeated construction from stationary-camera interactions. It adds a small local cache, not a second geometry implementation or a model-level cache.
diagram/grid.rs owns an Iced geometry cache and an exact raw (zoom, pan) key.
Iced's cache checks exact frame size. Camera changes explicitly clear it. The
colors and dot radius remain compile-time constants; future runtime styling
must invalidate this cache too. The conservative key rebuilds after a whole
grid-period pan and after zoom changes within the minimum-spacing clamp. No
fractional coordinates are rounded or tolerance-compared.
Drawing order becomes [cached background and dots, live diagram, warnings].
The opaque background is in the first geometry, so it cannot cover the dots.
Existing pan/zoom transforms still apply only to the live model geometry.
The cache lives in the retained canvas State; model revisions and selections
do not invalidate it. Existing focus/suspension tree resets cause a safe cold
rebuild. No routing, model semantics, hit testing or gesture admission changes.
production_grid_probe.rs imports the actual candidate cache. Its exploratory
run 03 was performed before the source commit and formatting; the raw log is
retained as local precommit evidence, not relabeled as a binary from the commit.
The same source is supplied for reproduction at the identified candidate.
The separately recompiled run 04 imports the committed 636093aa cache and ran
after the full desktop test process exited, before Clippy/build compilation.
grid-performance-04.log records exact baseline/cached pixels and these medians:
| Canvas, zoom | Fresh geometry ms | Production cache hit ms | Changing-pan rebuild ms |
|---|---|---|---|
| 1900x660, 1.0 | 61.8281 | 0.0002 | 59.2995 |
| 1900x660, 0.5 | 158.8603 | 0.0002 | 163.4359 |
| 1440x900, 1.0 | 50.5385 | 0.0002 | 53.5840 |
| 1440x900, 0.5 | 168.4092 | 0.0002 | 175.2457 |
These results support the same bounded conclusion as the exploratory trials. The run record preserves linked-library, driver and log hashes; timing noise and screenshot readback remain explicit limitations. Run 04 directly compares the production cache's cold pixels; its generic cold-and-warm marker refers to the Iced-cache control. Warm production-cache pixel parity is established separately by the committed grid tests.
Verification and boundaries
Three committed headless tests check:
- Cache construction count through 18 exact camera/size changes, including negative/fractional pan, zero-pan zoom changes, the minimum-spacing transition, independent width/height resizing and return to previous dimensions.
- Exact RGBA equality against an independent copy of the legacy loop and unsplit geometry. The scenes contain opaque cards, crossing edges, text, translucent overdraw, selection handles and a warning overlay. Foreground edits must visibly change pixels while retaining the background cache.
- The actual
DiagramCanvaswith one retained State: selection and model revision changes must alter rendered pixels without rebuilding the grid; pan and resize must rebuild it. This is drawing/scene-invalidation evidence, not an event-driven native gesture test.
Fresh read-only independent review found no concrete cache-key, lifetime,
ordering or test-oracle defect. It checked the corresponding Iced 0.14 cache
and mesh-layer implementations. This review does not establish execution.
At 636093aa, grid-tests-01.log passes all three targeted tests in 2.97s.
grid-desktop-01.log passes the full desktop suite in 362.14s: 1,543 passed,
zero failed, seven existing manual/diagnostic tests ignored, none filtered out.
All 1,550 distinct test names were counted; context.json lists the seven
ignored cases and records raw log hashes. This is desktop regression evidence;
it does not relabel the ignored checks as passing or establish native FPS.
The independent review states its exact scope.
The initial strict Clippy run (grid-clippy-01.log) failed on two uses of
chunks_exact(4) in the new test helper. Test-only successor
336720559bcec511949caa8a42bee8a55c3822da uses as_chunks::<4>(); it leaves
production inputs unchanged. The original full-suite result remains associated
with 636093aa, not relabeled as execution at the successor.
At the successor, strict all-target Clippy passes in 2m01s
(grid-clippy-02.log) and the three affected grid tests pass again in 4.13s
(grid-tests-02.log). No warning suppression or test exclusion was introduced.
The normal Windows GUI build at 33672055 also passes in 2m15s
(desktop-build-02.log). The executable and required libunwind.dll are staged
locally for later native verification, but this candidate has not been launched.
The executable SHA-256 is
78548e93d4b57130ed507ed0f29eddbdbafb4721b38b0cd6d06101d5324114dd;
context.json records both staged file hashes. Staging is not publication of a
new runnable release or native acceptance.
Remaining limits: the user's exact saved scene is unavailable; these results do not establish end-to-end native FPS. Continuous pan/zoom still pays the cold construction cost. Native desktop verification remains paused after user Escape. Neither issue 40 nor issue 44 is closed by this headless experiment. Linux/WSL remains deferred by the user. No published release has been replaced.
Environment and reproduction
Windows 10.0.26200, Rust 1.98.1, x86_64-pc-windows-gnullvm, development profile
with debug information disabled. The exposed CPU is Intel Core i7-10870H with
4 cores/threads; Windows reports VMware SVGA 3D, driver 9.17.11.4. The headless
renderer identifies itself as wgpu; the probe does not identify its selected
adapter or equate it with the desktop presenter's adapter. Other OS workloads
were not controlled, so measured outliers are preserved.
At the candidate source, the normal gates are:
cargo test --locked --offline -p oa-desktop diagram::grid::tests -- --test-threads=1
cargo test --locked --offline -p oa-desktop -- --test-threads=1
cargo clippy --locked --offline -p oa-desktop --all-targets -- -D warnings
cargo build --locked --offline -p oa-desktop --bin arcadia-studio
For the standalone probes, first build the desktop dependencies in that profile.
Compile with rustc --edition=2024 -C opt-level=0, supplying --extern iced=...
and --extern tokio=... for the matching rlibs, plus -L dependency=... for
their directory. On this toolchain the link also needs -C linker=clang.exe
and -L native=.../windows_x86_64_gnullvm-0.52.6/lib. The original inputs were
libiced-594f7d417d69ed72.rlib and libtokio-5e0ca96735e3073a.rlib from
target/debug/deps. Run the resulting executable with argument 20.
The production probe's relative module path requires compiling it at its
versioned location. Keep linker and runtime DLLs on PATH.
The first experimental compile failed because the configured futures crate
lacked its executor feature and an inherent screenshot method shadowed the
Headless trait method. Using the existing Tokio runtime and explicitly calling
Headless::screenshot corrected those driver errors. A second link failed for
the Windows import library search path; grid-build-02.log retains that failure.
Adding the native library path allowed subsequent probes to run. These failures
occurred in the experimental driver, before execution; they are not passing
application checks.