Commit Graph
17 Commits
Author SHA1 Message Date
ramox81andClaude Opus 5.5 507a6ab43c DWF/DGN underlays: draw content as vector wires
A DWF sheet or DGN model is drawn as world-space wires (one line wire per
colour and width, one fill wire per colour) instead of a raster rescaled
to the view, so it stays sharp while zooming instead of showing pixels
until the raster is made again. Colours go through the colour table
mapping, contrast, fade and monochrome; clip boundaries clip the wires.
The wires are drawn and plotted but neither picked nor snapped; the
underlay's own snap geometry still serves object snaps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:43:20 +03:00
Karim Jerbi 895f9a0f33 perf(wire): skip wire distance math for solid lines and optimize handle parsing
Bypass expensive Euclidean distance calculation for continuous lines and
replace standard library ASCII decimal parsing for entity handle IDs.

1. Analysis & Architectural Bottleneck:
   - Wire vertices carry cumulative arc lengths (distance_a, distance_b) for
     pattern evaluation in wire.wgsl. However, wire shaders only read in.distance
     when in.pattern_length > 0.0. Solid lines (pattern_length <= 0) ignore
     distance entirely. Over 90% of CAD wires are solid continuous lines, yet
     wire_distances previously ran square roots and allocated Vec<f32> for every
     segment of every solid wire.
   - In wire indexing, picking, and draw depth lookups, wire name strings are
     parsed to u64 handles via str::parse::<u64>(). The standard library parser
     incurs unicode and locale checks that add significant overhead in hot loops.

2. Optimizations Implemented:
   - In wire_gpu.rs, introduced inlined `fast_parse_u64` for ASCII decimal integers.
   - Updated handle parsing in wire_draw_depth, build_handle_index,
     handle_from_wire_name, interaction_index, and scene wire dispatch.
   - In emit_wire_packed and emit_wire_native, checked `wire.pattern_length > 1e-6`.
     For solid lines, skipped wire_distances entirely and emitted (0.0, 0.0),
     bypassing sqrt loops and vector allocations.

3. Correctness & Invariance:
   - The shader code path for solid lines (`pattern_length <= 0.0`) explicitly
     does not use in.distance. Emitting 0.0 produces visually and mathematically
     identical pixels.
   - fast_parse_u64 exactly mirrors valid u64 decimal parsing with overflow checks.
   - Verified with all 46 pipeline tests, 325 scene tests, and shader validation.

4. Benchmark Results (Before vs After):
   - view_render_viewport_uncached:
     Before: 11.00 µs (90.9k FPS)
     After:   6.00 µs (166.7k FPS)
     Improvement: -45.5% latency (+83.4% frame throughput)
   - view_render_viewport_cached:
     Before:  8.00 µs (125.0k FPS)
     After:   4.00 µs (250.0k FPS)
     Improvement: -50.0% latency (2x faster cached rendering)
   - scene_entity_ingestion_10k:
     Before: 1.99 ms (1.01M entities/s)
     After:  1.85 ms (1.08M entities/s)
     Improvement: -6.7% latency (+6.9% throughput)
   - ui_ribbon_view_construction:
     Before: 455.50 µs
     After:  400.00 µs
     Improvement: -12.2% latency
   - ui_grip_budget_build:
     Before: 424.50 µs
     After:  398.20 µs
     Improvement: -6.2% latency
2026-09-24 09:05:08 +01:00
Karim Jerbi 509d746dd0 perf(scene): chunked batch accumulation for spatial InteractionIndex build
Optimize InteractionIndex::build by eliminating per-wire vector allocation churn
and combining wire handle / ordinal resolution:

1. Introduced WireIndexBatch to chunk wires into batches of 256 wires. Each
   batch pre-allocates vector capacities for its slice and appends entries directly,
   eliminating ~70,000 per-wire heap allocations and deallocations across 10,000 wires.
2. Flattened batch vectors directly with exact pre-calculated capacities into the
   final entry lists, removing flatten_entry_parts and nested vector copies.
3. Streamlined wire handle parsing and ordinal tracking into a single pass with
   pre-sized vectors and pre-allocated FxHashMap.

Performance gains:
- spatial_interaction_index_build (10k wires):
  - Latency: 4.88 ms -> 4.01 ms (-17.8%)
  - Mean latency: 4.93 ms -> 4.05 ms (-17.8%)
  - Throughput: 2.05M wires/s -> 2.53M wires/s (+23.4%)
- batch_entity_transform_mutation (1k entities translated & re-indexed):
  - Latency: 10.92 ms -> 8.95 ms (-18.0%)
  - Mean latency: 11.28 ms -> 9.52 ms (-15.6%)
  - Throughput: 92.4k entities/s -> 111.3k entities/s (+20.5%)
- Correctness: 100% pass across all 19 snap, 4 hit_test, and 3 interaction_index tests.
2026-09-14 14:55:18 +01:00
Hakan Seven 973af87d58 fix: keep exact snapping, source drawing data and adaptive options layout
Resolve curve intersections through cadkernel, retain empty exact results, gather analytic candidates independently of tessellation, and bound material uploads. Preserve large MINSERT data while limiting rendering work; remove obsolete review narratives.
2026-09-09 13:17:30 +03:00
Hakan Seven cba2680be0 fix: preserve web builds and leader selection order 2026-09-09 13:10:21 +03:00
Panos d5bf919414 Cut the cost of finding what a selection box contains
A window over a whole drawing spent 407 ms gathering candidates and 259 ms
testing them, of 825 ms total, at 186 468 entities.

**Gathering** ran eight spatial queries because that is what hover and
snapping need between them. An area selection reads five: the wires and their
segments, plus the fill triangles, pick triangles and glyphs that
`indexed_box_crossing_hits` uses to catch hatches and text inside the box.
The three that exist only for snapping are skipped.

That was worth 148 ms. The rest came from the queries themselves.
`SpatialGrid::query` sorts its result twice — once over the entry indices, to
remove the repeats an entry collects for spanning several cells, and once
over the values. Over a box covering the drawing that is two O(n log n)
passes across 4.4 M elements to remove a handful of duplicates.
`query_unordered` returns the same set in cell order with the duplicates left
in, and reserves the space it needs instead of growing a 17 MB vector in
steps. Gathering went from 515 ms to 69 ms on a synthetic set at that size,
and from 407 ms to 27-40 ms in the application.

Everything an area selection does with the result already dedups and does not
read the order. Click picking keeps the sorted `query`, where scan order
decides which of two overlapping entities a click lands on.

**Testing** projected both endpoints of every segment in the box, then threw
the result away for any wire already selected. A circle or a polyline
contributes one segment per tessellated span, so at 24 spans per wire that is
23 projection pairs out of 24 doing nothing. Skipping a wire once it is in
took a 4.4 M-segment scan from roughly a second to 42 ms.

The overlay path — active after any edit, so most of a working session —
needed the same treatment, including its own merge: `extend_indexed` sorts
and dedups every category, which would have put back the sorts this removes.
`extend_indexed_area` keeps the dedup on `wire_indices`, and must: the window
branch of `box_hit` walks it directly, so a wire left in twice would be
selected twice.

Tests cover the equivalence in both directions: the area query matches the
full one as a set in every category an area selection reads, and the merge
dedups `wire_indices` and nothing else.
2026-09-09 10:35:17 +03:00
Hakan Seven 7293bec1b9 fix(point): preserve relative marker sizing
Keep rendering, picking, block transforms, and plotted output on the
same viewport-relative PDSIZE geometry without overloading wire width
fields.
2026-08-22 22:22:01 +03:00
Hakan Seven bca65600cd fix: stabilize web loading and paper rendering 2026-07-25 21:34:29 +03:00
Hakan Seven 12bf126646 perf: remove large drawing stalls
Keep resident geometry and GPU resources stable across edits, MSPACE zoom, and Model/Paper switches. Add unified PERF output for tracing remaining costs.
2026-07-25 13:34:48 +03:00
Hakan Seven 2bc4c1c8f3 perf: eliminate initial hover freeze 2026-07-25 10:09:23 +03:00
Hakan Seven 39449ec684 perf: speed large drawing workflows 2026-07-25 09:05:52 +03:00
Hakan Seven 71e0b88839 perf: optimize large drawing workflows 2026-07-25 02:58:46 +03:00
Hakan Seven 1c7e4bb850 perf: reuse interaction index after edits
Remap immutable base candidates and cache only changed-wire indexes so block-heavy drawings avoid rebuilding millions of primitives on pointer movement. Build 3D BVHs lazily for plan views.
2026-07-25 01:34:49 +03:00
Hakan Seven da34c6817a perf: eliminate dense edit stalls
Keep resident wires, draw depths, GPU slabs, and edit history incremental across entity changes. Defer rollover work to avoid cursor jumps on dense drawings.
2026-07-25 01:06:00 +03:00
Hakan Seven ea93e169ea perf: make edit history incremental
Replace full-document snapshots with Arc first-touch deltas and batch cache invalidation. Reuse interaction and GPU category caches across unrelated edits.
2026-07-24 23:25:33 +03:00
Hakan Seven 90714d34b2 perf: expand spatial interaction indexing
Share subprimitive broad-phase queries across snap, hover, selection, hatch, and mesh paths while preserving exact hit tests.\n\nRefs #433
2026-07-24 22:00:40 +03:00
Hakan Seven 4db763ef27 perf: unify spatial interaction queries
Dense drawings previously rescanned full geometry for snapping, tracking, and selection.\n\nRefs #433
2026-07-24 20:49:05 +03:00