Show a bounded native-cache preview before authoritative reconstruction (#463)
Refs #303. file.save / file.save_as can store a warm native geometry cache (cache: true, off by default) keyed to the document hash, app version and adapter revision. Opening shows a bounded preview from it until the rebuilt session replaces it. Any cache failure counts as a miss.
This commit is contained in:
1 parent
1abd989a67
commit
913583bfee
20 files changed
+943
-84
No files matched your search
@@ -47,8 +47,11 @@ Containers deduplicate identical STEP, mesh and image payloads. Mesh coordinates
|
||||
their original double precision; this is not a conversion to STL. Geometry still rebuilds
|
||||
from the timeline when opening. When a saved display preview is available, desktop Open
|
||||
shows it while checking geometry; editing starts after the complete rebuild. Cancelling
|
||||
keeps the current design. Previews cannot be edited or measured. This experimental option
|
||||
requires `preview: true` in an engine Save/Save As call; ordinary saves omit display caches.
|
||||
keeps the current design. Previews cannot be edited or measured. Scripts can opt in to a disposable geometry
|
||||
cache with `cache: true` on warm saves; saving never rebuilds cold geometry just to
|
||||
create one. Ordinary saves and browser downloads default to `cache: false`. An additional display-mesh cache remains opt-in
|
||||
with `preview: true`. Unsupported or mismatched caches are ignored. Browser opening
|
||||
still rebuilds synchronously.
|
||||
The repository's `docs/design-container.md` describes limits and encoding details.
|
||||
|
||||
Current designs use format 16, including the font of sketch text, sheet metal corner relief shapes, sketch face anchors on cylinder caps, sketch axis
|
||||
|
||||
+51
-14
@@ -60,7 +60,7 @@ use the same container reader/writer; JSON export and Save As remain available.
|
||||
Experimental engine saves with `preview: true` can include `cache/preview.json` and
|
||||
`cache/preview.bin` when the evaluated
|
||||
world display meshes are already warm. Ordinary saves omit this redundant display data
|
||||
to avoid extra save work; it is not the proposed evaluated B-rep cache. Saving never triangulates a cold body for this
|
||||
to avoid extra save work; it is separate from the native B-rep cache below. Saving never triangulates a cold body for this
|
||||
cache. Pending occurrence moves, active sketch edits, feature errors and oversized
|
||||
previews omit it. The cache is bounded to 8 MiB, 1,024 bodies and 100,000 triangles;
|
||||
its manifest is at most 64 KiB. Body names/colours and contiguous binary mesh slices
|
||||
@@ -86,9 +86,9 @@ geometry, used for measurements, or used to seed evaluated model state. The orig
|
||||
design remains intact until the complete rebuilt session is ready. Cancellation or
|
||||
any change of active document/revision discards both preview and completion.
|
||||
|
||||
Normal design reading, CLI and browser opening still rebuild authoritatively; no
|
||||
evaluated B-rep is deserialized or adopted. Portable evaluated B-rep/state restoration
|
||||
and interactive cached viewport navigation remain further work in #303.
|
||||
Normal design reading, CLI and browser opening still rebuild authoritatively.
|
||||
Native B-rep caches can supply provisional display as described below; they never
|
||||
supply evaluated session state. The saved picture is not an interactive viewport.
|
||||
|
||||
## Seekable reader (phase 2, first increment)
|
||||
|
||||
@@ -98,16 +98,51 @@ headers, then `preview()` reads the optional display entries and document metada
|
||||
`read_document()` consumes the reader and resolves and validates the required
|
||||
source blobs through the same archive. No complete archive buffer is required.
|
||||
The existing byte-based readers use this implementation too; JSON keeps its existing
|
||||
reader. This increment provides the IO API; desktop and browser integration remain
|
||||
separate. It does not yet change application opening times or saving behavior.
|
||||
reader. `read_design_file` integrates it with desktop Open using one file handle,
|
||||
without buffering the complete container. Browser VFS uses a memory cursor.
|
||||
|
||||
The source must remain unchanged for the lifetime of the reader. A file handle is
|
||||
not an immutable snapshot of concurrent in-place writes: application integration
|
||||
must address that before publishing a cached view. Optional preview success never
|
||||
validates source blobs or makes a document editable. An invalid required blob still
|
||||
Metadata used to validate a provisional cache is retained in an immutable buffer
|
||||
and reused for authoritative reconstruction. Concurrent in-place writes therefore
|
||||
either retain that document or fail required-part CRC/hash validation. Optional
|
||||
preview success never validates source blobs or makes a document editable. An invalid required blob still
|
||||
fails the later document read. ZIP directory scans can touch a bounded suffix of a
|
||||
stored blob; deferral means not loading or decoding the complete payload, not zero
|
||||
physical reads of its byte range. Metadata retains the existing part-size budget.
|
||||
physical reads of its byte range. Optional cache metadata is capped at 16 MiB;
|
||||
larger metadata misses the cache and uses the normal authoritative part-size budget.
|
||||
|
||||
## Native evaluated cache
|
||||
|
||||
Engine Save/Save As can include `cache/key.json` and `cache/brep.bin` when
|
||||
explicitly requested with `cache: true` and geometry is warm. The default is
|
||||
`cache: false`, including browser downloads, to avoid extra save time and file size.
|
||||
JSON and recovery/autosave
|
||||
remain independent of the native cache. Saving never forces cold placement,
|
||||
evaluation or tessellation. Active sketches, uncaptured moves, errors, mesh bodies,
|
||||
unsupported adapter representations and exceeded budgets omit the cache.
|
||||
|
||||
The manifest records `solidcraft-brep-cache/1`, the package version, the explicit
|
||||
producer revision `solidcraft-truck-adapter/2`, exact document/payload SHA-256 hashes
|
||||
and contiguous named body slices. The producer revision is deliberately maintained
|
||||
when adapter semantics change; it is not a source-tree fingerprint or build script.
|
||||
The binary data uses [SolidCraft's portable B-rep schema and codec](native-brep.md),
|
||||
including topology, curves/surfaces, face-source certificates, appearances and
|
||||
operation history. Truck's serialized structures are never stored. A different
|
||||
kernel can implement the same schema; until its adapter is tested it conservatively
|
||||
misses this producer's cache and rebuilds the authoritative document.
|
||||
|
||||
Native caches cap 4,096 bodies, 100,000 total faces, a 1 MiB manifest and 64 MiB
|
||||
binary payload. Individual bodies have the schema/codec's additional limits.
|
||||
The reader validates metadata, manifest, slices and bodies before requesting a
|
||||
bounded provisional mesh. Original STEP/image/mesh blobs are resolved afterwards.
|
||||
No redundant display mesh is stored by default: `preview: true` remains a separate
|
||||
opt-in for already warm display meshes, which take precedence when present.
|
||||
|
||||
Every failure in the optional cache is a miss. Even a checksum-valid forged body
|
||||
never becomes editable state: Open builds a fresh session from the document and
|
||||
original blobs, then replaces the provisional picture. Picking, measurements,
|
||||
persistent names and subsequent modelling use that rebuilt session. Existing
|
||||
cancellation/document-revision guards also apply. The web build retains synchronous
|
||||
authoritative rebuilding; portability does not imply background web evaluation.
|
||||
|
||||
A counting-reader regression uses a 2.6 MB stored source blob and obtains the saved
|
||||
preview with fewer than 256 KiB read, then verifies the authoritative document is
|
||||
@@ -115,9 +150,10 @@ identical after resolving its source. Corrupt-source and preview-miss regression
|
||||
and truncation/seeded mutations through the combined reader, protect the boundary.
|
||||
This is an IO-volume test, not a geometry or first-frame benchmark.
|
||||
|
||||
## Remaining #303 increments and kernel independence
|
||||
## Review increments and kernel independence
|
||||
|
||||
Keep each increment independently reviewable after the phase-one container PR:
|
||||
The implementation is split into the following review increments after the
|
||||
phase-one container PR (#327):
|
||||
|
||||
1. Seekable IO and its read-volume/hostile-input tests (the API above).
|
||||
2. A versioned SolidCraft-owned B-rep schema and bounded binary codec, tested without
|
||||
@@ -128,7 +164,8 @@ Keep each increment independently reviewable after the phase-one container PR:
|
||||
No truck serialized structs, memory layouts, pointers or opaque kernel blobs
|
||||
form part of the persisted contract. No evaluated STEP round trip is a substitute.
|
||||
3. Separate adapters between the neutral schema and supported kernels. Unsupported
|
||||
geometry or provenance is a cache miss, never a lossy approximation. A neutral
|
||||
geometry or provenance is a cache miss. Explicitly fitted intersection splines
|
||||
carry their fitting target and remain provisional display geometry. A neutral
|
||||
file schema alone does not prove interoperability: each adapter needs round-trip,
|
||||
modelling and naming tests; compatibility with a second kernel is unverified
|
||||
until that adapter exists. Kernel/version information belongs in producer and
|
||||
|
||||
+20
-2
@@ -4,7 +4,8 @@ This is SolidCraft's geometry interchange data model in `solidcraft_geom::brep`.
|
||||
It has no modelling-backend dependency. It is the basis for #303's disposable
|
||||
native cache; it is not an editable-session snapshot or a STEP replacement for
|
||||
external interchange. The container reader, binary codec and kernel adapters are
|
||||
separate layers. The schema is not yet emitted by application saves.
|
||||
separate layers. Warm application saves can emit it as the optional native cache
|
||||
described in [the container format](design-container.md#native-evaluated-cache).
|
||||
|
||||
## Geometry and topology
|
||||
|
||||
@@ -127,7 +128,8 @@ intersection annotation. This approximation is suitable only for the provisional
|
||||
cache, never authoritative modelling state.
|
||||
|
||||
Decoded bodies remain provisional; the application must never use an untrusted
|
||||
cache as its editable model. Application cache integration is separate. A second
|
||||
cache as its editable model. Application integration keeps it provisional while
|
||||
rebuilding the document and original sources. A second
|
||||
backend needs its own tested adapter before cross-kernel interoperability can be
|
||||
claimed.
|
||||
|
||||
@@ -136,3 +138,19 @@ field names, tags, topology, geometry and metadata. Integer and structural value
|
||||
are exact; floating coefficients allow 1e-10 relative/absolute platform rounding.
|
||||
The signature is asserted separately. This protects the wire contract against
|
||||
accidental runtime-refactor changes.
|
||||
|
||||
## Bounded provisional display
|
||||
|
||||
`native_preview_mesh` samples at most 32 points along each curved edge, caps each
|
||||
face's boundary at 4,096 points, and bounds spline controls and nested surfaces
|
||||
before parameter searches. Searches use at most 16 refinement trials. Revolution
|
||||
profiles involving procedural intersections are refused in this display path.
|
||||
The separate mesher uses a fixed grid of at most 16 subdivisions per direction
|
||||
and fixed periodic-seam connections; it never invokes adaptive edge, surface or
|
||||
aspect-ratio refinement. Planes use a single grid cell.
|
||||
|
||||
Before projection, the caller reserves a conservative triangle bound covering
|
||||
duplicated projected boundary points, periodic seams and the grid for the complete
|
||||
body. Output is checked against that reservation and for finite coordinates.
|
||||
Missing faces or exceeded budgets cause a cache miss. This mesh is approximate,
|
||||
read-only display; normal modelling/export tessellation is unchanged.
|
||||
+109
-5
@@ -109,14 +109,14 @@ See [the versioned container format](design-container.md) for layout and bounds.
|
||||
|
||||
This phase does not restore evaluated B-reps, skip STEP import, or make cold geometry
|
||||
rebuilds instant. A matching cache key is not enough to trust unvalidated geometry.
|
||||
Evaluated B-rep/state restoration remains further work in #303. The provisional saved
|
||||
display described below is separate from #287's import parallelism.
|
||||
The native B-rep increment described below supplies provisional display, not editable
|
||||
session restoration. It is separate from #287's import parallelism.
|
||||
|
||||
## Provisional saved display (#303)
|
||||
## Opt-in mesh preview measurements (#303, phase one)
|
||||
|
||||
Desktop Open can show an experimental saved picture while the existing file worker rebuilds geometry.
|
||||
The phase-one desktop implementation can show an experimental saved picture while the file worker rebuilds geometry.
|
||||
It requires an explicit `preview: true` engine Save/Save As call. Ordinary saves omit
|
||||
display caches to avoid the measured overhead; native evaluated B-rep caching remains open.
|
||||
display meshes to avoid the measured overhead; these measurements predate native B-rep caching.
|
||||
The cache contains only already warm evaluated display meshes, capped at 8 MiB, 1,024
|
||||
bodies and 100,000 triangles. Larger or cold models save without it. Cached geometry is
|
||||
never used for editing, measurements or picking. Source/document fingerprints and
|
||||
@@ -151,6 +151,110 @@ For actual desktop opening phases, launch with `SOLIDCRAFT_PROFILE_OPEN=1`: `rea
|
||||
reports saved-picture preparation, while the normal phase log reports reconstruction,
|
||||
display warmup and thumbnail completion. Neither log measures the exact GPU first frame.
|
||||
|
||||
## Native cache opening (#303)
|
||||
|
||||
The portable native B-rep cache is opt-in with `cache: true` on warm container
|
||||
saves, without duplicating display meshes. Ordinary saves and browser downloads
|
||||
default to `cache: false`: the measurements below do not justify imposing the
|
||||
additional save time and file size on every design. Desktop Open reads metadata and
|
||||
optional geometry through a seekable file, produces a bounded provisional picture,
|
||||
then resolves original sources and reconstructs the complete session before editing.
|
||||
This improves the opportunity for early display, not the cost of authoritative feature
|
||||
evaluation. An absent, invalid or incompatible cache uses the original reconstruction.
|
||||
Browser OPFS/downloads share the format; browser opening still rebuilds synchronously.
|
||||
|
||||
The reproducible engine benchmarks separate atomic saving, provisional mesh readiness,
|
||||
reconstruction and final display-mesh readiness:
|
||||
|
||||
```sh
|
||||
cargo test -p solidcraft-io --profile ci benchmark_step_storage -- --ignored --nocapture --test-threads=1
|
||||
cargo test -p solidcraft-engine --profile ci benchmark_native_cache_save -- --ignored --nocapture --test-threads=1
|
||||
cargo test -p solidcraft-engine --profile ci benchmark_native_cache_open -- --ignored --nocapture --test-threads=1
|
||||
```
|
||||
|
||||
Use an absolute `CARGO_TARGET_DIR`. The save benchmark defaults to the generated
|
||||
512-box STEP document and accepts `SOLIDCRAFT_BENCH_FILE` for another public design.
|
||||
It alternates nine saves of each encoding, including flush/replacement/backup, and
|
||||
verifies document identity and native-cache presence. It never times initial fixture
|
||||
evaluation as save work. Open runs once per process; `SOLIDCRAFT_BENCH_ENCODING`
|
||||
selects 0=JSON, 1=container without cache, 2=native cache, 3=compact native cache.
|
||||
Changing only `cache/key.json`'s application version provides a cache-miss control.
|
||||
Fresh processes do not imply a cold operating-system file cache. The engine callback
|
||||
time is provisional mesh readiness, not a rendered desktop frame; use the desktop
|
||||
profile log and actual screenshots to check the saved picture and completed model.
|
||||
|
||||
Measured 2026-10-13 on Windows 11, Ryzen AI MAX+ 395 (16 cores/32 threads), `ci`
|
||||
profile, with the neutral codec revision `75381fa`, envelope `SCBREP03`, producer
|
||||
`solidcraft-truck-adapter/2`, and opening integration revision `3243422` on upstream `2880525`
|
||||
(0.6.0). These replace the earlier prototype measurements. They compare encodings
|
||||
on the same code and do not attribute upstream modelling improvements to the cache.
|
||||
Runs started after local builds and the complete CI suite finished; ordinary
|
||||
desktop activity remained. Save values are medians of nine alternating atomic
|
||||
saves. Open values are medians of five fresh processes per encoding, alternating
|
||||
forward/reverse order. Memory is each process's peak working set from Windows
|
||||
`GetProcessMemoryInfo`, sampled every 10 ms, then the median across those five
|
||||
processes; it excludes a desktop window/GPU.
|
||||
|
||||
The original STEP fixture is a 32 by 16 array of 10 mm cubes, 12 mm apart, exported
|
||||
by SolidCraft: 512 bodies and 6,144 final triangles. Its JSON embeds about 2 MB of
|
||||
STEP. Every encoding reopens without feature errors and with those same counts.
|
||||
|
||||
| STEP encoding | Bytes | Atomic save, ms |
|
||||
|---|---:|---:|
|
||||
| JSON | 1,998,826 | 12.616 |
|
||||
| Container, no cache | 1,950,084 | 10.516 |
|
||||
| Native cache, fast | 4,694,035 | 47.755 |
|
||||
| Native cache, compact | 837,067 | 44.015 |
|
||||
|
||||
| STEP encoding | Provisional mesh, ms | Reconstructed, ms | Final meshes, ms | Peak working set, MiB |
|
||||
|---|---:|---:|---:|---:|
|
||||
| JSON | none | 175.842 | 748.911 | 40.102 |
|
||||
| Container, no cache | none | 175.885 | 722.306 | 40.504 |
|
||||
| Native cache, fast | 62.099 | 228.794 | 747.976 | 40.883 |
|
||||
| Native cache, compact | 65.981 | 235.403 | 762.120 | 40.918 |
|
||||
| Native cache miss | none | 169.039 | 647.617 | 40.453 |
|
||||
|
||||
The public `examples/acceptance/sensor_enclosure.json` script, saved as a JSON
|
||||
design, has 21 features, two bodies and 4,364 final triangles on this revision.
|
||||
|
||||
| Sensor enclosure encoding | Bytes | Atomic save, ms |
|
||||
|---|---:|---:|
|
||||
| JSON | 52,281 | 5.243 |
|
||||
| Container, no cache | 5,545 | 4.969 |
|
||||
| Native cache, fast | 379,095 | 12.646 |
|
||||
| Native cache, compact | 72,603 | 14.111 |
|
||||
|
||||
| Sensor enclosure encoding | Provisional mesh, ms | Reconstructed, ms | Final meshes, ms | Peak working set, MiB |
|
||||
|---|---:|---:|---:|---:|
|
||||
| JSON | none | 3,979.063 | 3,984.593 | 70.438 |
|
||||
| Container, no cache | none | 4,038.127 | 4,042.006 | 71.789 |
|
||||
| Native cache, fast | 241.541 | 4,269.124 | 4,274.272 | 70.465 |
|
||||
| Native cache, compact | 236.739 | 4,271.254 | 4,275.159 | 70.148 |
|
||||
| Native cache miss | none | 4,136.517 | 4,140.903 | 69.941 |
|
||||
|
||||
Native display is available earlier, at the cost of encoding, file size and work
|
||||
before reconstruction. It does not make the full design editable earlier, and
|
||||
these results do not establish a memory reduction. Final-mesh readiness varied
|
||||
from 611 to 856 ms for STEP and 3.84 to 4.60 s for the enclosure; small differences
|
||||
in full-opening medians should not be read as modelling speedups. Compact storage
|
||||
reduces this STEP example's size and atomic-save time, but costs slightly more save
|
||||
time on the enclosure. The default `cache: false` retains the phase-one save path;
|
||||
`compression: "compact"` is an explicit space/CPU choice. Larger or unsupported
|
||||
geometry can exceed the documented budgets and reopen without a provisional image.
|
||||
|
||||
A separate desktop check used a fresh 0.6.0 application process for each enclosure
|
||||
encoding, with no local compilation or test suite running. The native cache's
|
||||
provisional picture was prepared at 429 ms and captured visibly during opening;
|
||||
the completed model was adopted in 6.48 s. JSON had no provisional picture and
|
||||
completed in 6.08 s. These are single visual checks, not repeated timing medians;
|
||||
the worker reported 6.10/5.66 s respectively, and external observations include
|
||||
UI scheduling and screenshot requests. During native opening, 94 control-channel
|
||||
inspections had a median round trip of 20.8 ms and a maximum of 106.5 ms (JSON:
|
||||
95 inspections, 20.3/36.9 ms). The provisional picture is explicitly labelled as
|
||||
being checked before editing; the final frame shows the rebuilt Case and Lid and
|
||||
their editable feature timeline. This demonstrates early feedback, not faster
|
||||
completion of feature evaluation or a worst-case UI-latency guarantee.
|
||||
|
||||
## Analytic extrusion source preparation
|
||||
|
||||
New-body extrusion certificates now prepare the sketch's bounded analytic segments once
|
||||
|
||||
Reference in new issue
Block a user