Files
ARCADIA-Studio/harness/experiments/grid-cache-20260925
..

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

  1. Rebuild each circle every draw: exact current appearance, but the measured repeated CPU cost alone is large in this development build.
  2. Batch circles into one path: keeps the same pixels in this experiment but is materially slower. grid_render_probe.rs and grid-performance-02.log retain 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.
  3. 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 DiagramCanvas with 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

The subsequent cold-construction and pan experiments compare additional approaches, including a renderer-translated cache. They preserve their own pixel differences, timing limits and adoption gates; they do not change the production implementation verified above.

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.