From 3a3d2e4a84cbe3659b09340d454d70056adbfe02 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Sat, 17 Oct 2026 19:46:43 +0300 Subject: [PATCH] Viewport block caches no longer scan every object per entity A drawing with 650k entities and 21k objects stalled for 7 minutes the first time a layout viewport was drawn (#1746): building that viewport's block cache asked for each entity's layer viewport overrides, and the codec found each layer's extension dictionary by scanning every object whenever the layer had none. Codec 2646725 reads the registered link. The XCLIP check made the same scan for every nested INSERT without an extension dictionary; it now reads the INSERT's own link, which the readers and ensure_extension_dictionary always set. Cargo: codec 2646725, kernel 4e6334a, graph 2fd1d42. Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 8 ++++---- Cargo.toml | 8 ++++---- crates/ocs_plugin_api/Cargo.toml | 4 ++-- crates/ocs_save/Cargo.toml | 2 +- crates/ocs_web_worker/Cargo.toml | 2 +- docs/plugin-template-v2/Cargo.toml | 2 +- plugins/opencad-python/Cargo.lock | 2 +- src/scene/pick/xclip.rs | 19 ++++++++----------- 8 files changed, 22 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e90d41448..d9ef6abc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,7 +96,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "acadrust" version = "0.6.4" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=cf3a040#cf3a04051240cf88440f8aaf41c4841fcb01d0d1" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=2646725#264672522c1edcaed1b6c04e7a4ebb888fb6aee3" dependencies = [ "anyhow", "bitflags 2.13.1", @@ -4406,7 +4406,7 @@ dependencies = [ [[package]] name = "opencadgraph" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=800878a#800878aa14be9789568544e2e552a044ac727cae" +source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=2fd1d42#2fd1d429115e852fc46e47df723cb84499190927" dependencies = [ "opencadkernel", "serde_json", @@ -4415,7 +4415,7 @@ dependencies = [ [[package]] name = "opencadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=2659c33#2659c339d0b57f7f858881174e3e04d5ef46af2f" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=4e6334a#4e6334a118bd48dd1330c4ac0ce258e0be072c59" dependencies = [ "acadrust", "cavalier_contours", @@ -4426,7 +4426,7 @@ dependencies = [ [[package]] name = "opencadkernel-constraints" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=2659c33#2659c339d0b57f7f858881174e3e04d5ef46af2f" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=4e6334a#4e6334a118bd48dd1330c4ac0ce258e0be072c59" dependencies = [ "nalgebra", ] diff --git a/Cargo.toml b/Cargo.toml index 3e148c609..3a78d78c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,10 +37,10 @@ rfd = "0.17" clap = { version = "4", features = ["derive", "string"] } env_logger = "0.11" log = "0.4" -codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", features = ["serde"] } -kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "2659c33", features = ["acis", "offset"] } -kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "2659c33" } -graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "800878a" } +codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", features = ["serde"] } +kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "4e6334a", features = ["acis", "offset"] } +kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "4e6334a" } +graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "2fd1d42" } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } # Shared SAVE serialization dispatch + web-worker wire format: one # implementation for the inline (fallback/native) path and the worker path. diff --git a/crates/ocs_plugin_api/Cargo.toml b/crates/ocs_plugin_api/Cargo.toml index 52f9957a8..67bcf51b4 100644 --- a/crates/ocs_plugin_api/Cargo.toml +++ b/crates/ocs_plugin_api/Cargo.toml @@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true } # Pulled in only by the `host` feature, which adds the `opencadcodec`-typed # `HostApi` runtime surface. The default crate stays dependency-free so engine # crates and external tooling can depend on the manifest/ribbon contract cheaply. -codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", optional = true, features = ["serde"] } +codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", optional = true, features = ["serde"] } # Runtime IPC and serialization (host feature only). interprocess = { version = "2", optional = true } @@ -39,7 +39,7 @@ serde_json = "1" serde = { version = "1", features = ["derive"] } cargo-lock = "11" # opencadcodec is scanned at build time to generate the embedded type registry. -codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", features = ["serde"] } +codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", features = ["serde"] } [dev-dependencies] serde_json = "1" diff --git a/crates/ocs_save/Cargo.toml b/crates/ocs_save/Cargo.toml index 190a7788b..5cb7476e5 100644 --- a/crates/ocs_save/Cargo.toml +++ b/crates/ocs_save/Cargo.toml @@ -10,6 +10,6 @@ publish = false # exactly one implementation. No UI/app dependencies — only the codec + serde. [dependencies] -codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", features = ["serde"] } +codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } diff --git a/crates/ocs_web_worker/Cargo.toml b/crates/ocs_web_worker/Cargo.toml index d1a597881..52cf35731 100644 --- a/crates/ocs_web_worker/Cargo.toml +++ b/crates/ocs_web_worker/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", features = ["serde"] } +codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } console_error_panic_hook = "0.1" diff --git a/docs/plugin-template-v2/Cargo.toml b/docs/plugin-template-v2/Cargo.toml index 46d871be9..22e6c9c83 100644 --- a/docs/plugin-template-v2/Cargo.toml +++ b/docs/plugin-template-v2/Cargo.toml @@ -16,4 +16,4 @@ ocs_plugin_api = { path = "../../crates/ocs_plugin_api", features = ["host"] } # entry): the plugin's entities and the host's re-exports are the same types # only when both resolve the same revision. The registration `rustc` / # `acadrust_source` gates enforce this at load time too. -acadrust = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040" } +acadrust = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725" } diff --git a/plugins/opencad-python/Cargo.lock b/plugins/opencad-python/Cargo.lock index f9f33423d..5e3e31a26 100644 --- a/plugins/opencad-python/Cargo.lock +++ b/plugins/opencad-python/Cargo.lock @@ -5,7 +5,7 @@ version = 4 [[package]] name = "acadrust" version = "0.6.4" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=cf3a040#cf3a04051240cf88440f8aaf41c4841fcb01d0d1" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=2646725#264672522c1edcaed1b6c04e7a4ebb888fb6aee3" dependencies = [ "anyhow", "bitflags", diff --git a/src/scene/pick/xclip.rs b/src/scene/pick/xclip.rs index be143a131..1c823eb23 100644 --- a/src/scene/pick/xclip.rs +++ b/src/scene/pick/xclip.rs @@ -48,15 +48,12 @@ fn resolve_extension_dictionary(doc: &CadDocument, owner: Handle) -> Option Option { - ins.common - .xdictionary_handle - .filter(|h| !h.is_null()) - .or_else(|| doc.extension_dictionary_handle(ins.common.handle)) - .filter(|h| !h.is_null()) +/// The INSERT's extension dictionary through its own link. Render walks ask +/// this for every INSERT, so it must not fall back to a scan of every object: +/// [`CadDocument::extension_dictionary_handle`] scans for an entity without +/// a linked dictionary. Readers and `ensure_extension_dictionary` set the link. +fn linked_extension_dictionary(ins: &Insert) -> Option { + ins.common.xdictionary_handle.filter(|h| !h.is_null()) } /// Resolve the enabled XCLIP spatial filter for `ins`, if any. @@ -66,7 +63,7 @@ fn linked_extension_dictionary(doc: &CadDocument, ins: &Insert) -> Option(doc: &'a CadDocument, ins: &Insert) -> Option<&'a SpatialFilter> { - let xdict = linked_extension_dictionary(doc, ins)?; + let xdict = linked_extension_dictionary(ins)?; let acad_filter = dict_entry(doc, xdict, "ACAD_FILTER")?; let spatial = dict_entry(doc, acad_filter, "SPATIAL")?; match doc.objects.get(&spatial)? { @@ -84,7 +81,7 @@ pub fn filter_handle(doc: &CadDocument, insert: Handle) -> Option { let Some(codec::EntityType::Insert(ins)) = doc.get_entity(insert) else { return None; }; - let xdict = linked_extension_dictionary(doc, ins)?; + let xdict = linked_extension_dictionary(ins)?; let acad_filter = dict_entry(doc, xdict, "ACAD_FILTER")?; let spatial = dict_entry(doc, acad_filter, "SPATIAL")?; matches!(