GUI: Handle display controls for multiple loaded technologies (Web GUI)#10348
GUI: Handle display controls for multiple loaded technologies (Web GUI)#10348openroad-ci wants to merge 13 commits into
Conversation
|
clang-tidy review says "All clean, LGTM! 👍" |
There was a problem hiding this comment.
Code Review
This pull request implements a hierarchical layer management system, enabling the web interface to display and control layers organized by chiplet instances. It includes backend serialization of the chip hierarchy and a recursive frontend implementation for the layer tree and visibility controls. Feedback highlights the need for stable layer IDs based on instance names, the removal of redundant visibility checks, and a more consistent ID construction scheme to simplify fragile matching logic in the inspector.
|
|
||
| if (hierarchyNode.instances && hierarchyNode.instances.length > 0) { | ||
| hierarchyNode.instances.forEach((inst, idx) => { | ||
| const instId = `${parentId}_inst_${idx}`; |
There was a problem hiding this comment.
Using an index-based ID (inst${idx}) makes the layer visibility state dependent on the order of instances in the JSON and breaks compatibility with the instance_path used by the inspector. It is better to use the instance name provided in the hierarchy node to ensure stable and predictable IDs.
| const instId = `${parentId}_inst_${idx}`; | |
| const instId = parentId + "/" + (inst.name || idx); |
| if (app.layerModel && layer_id) { | ||
| const nodeId = instance_path ? `layers_parent_${instance_path}_${layer_id}` : layer_id; | ||
| // Check layerModel visibility | ||
| if (app.layerModel.isVisible && !app.layerModel.isVisible(nodeId) && !app.layerModel.isVisible(`layers_parent/${instance_path}/${layer_id}`) && !app.layerModel.isVisible(`layers_parent_${instance_path}/${layer_id}`) && !app.layerModel.isVisible(`layers_parent_${instance_path}/${layer_id}`) && !app.layerModel.isVisible(instance_path ? `${instance_path}/${layer_id}` : layer_id)) { |
There was a problem hiding this comment.
This condition contains a duplicate check for layers_parent_${instance_path}/${layer_id}.
Additionally, the logic relies on multiple guesses for the layer ID format (using both _ and / as separators). This is fragile and suggests that the ID scheme is not unified across the application. It is recommended to use a consistent ID construction method (e.g., always using / as a separator) in both display-controls.js and inspector.js to avoid this complex and error-prone matching logic.
| const id = name; | ||
| layer._nodeId = id; | ||
|
|
||
| const visible = !savedHiddenLayers.has(name) && !savedHiddenLayers.has(id); |
b2bf1ca to
756c2e2
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
756c2e2 to
7e59f70
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
7e59f70 to
e982c5e
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
|
|
fix #10208 |
Resolves The-OpenROAD-Project#10208 by exposing a "Chiplets" section in the Web GUI's Display Control panel. When multiple chiplets are loaded (3DBX / multi-die designs), each dbChip / dbChipInst node appears as a checkbox; toggling propagates through CheckboxTreeModel (same pattern as the Layers section) and refreshes the Leaflet tiles so the server filters out hidden chiplets in renderTileBuffer. Single-chip designs do not show the section. Frontend: - display-controls.js: buildChipletFlatNodes() + "Chiplets" group with tri-state header checkbox; hides are persisted per design in a cookie keyed by techData.block_name ({ block_name: [paths] }) so state does not leak across designs. - main.js: app.visibleChiplets Set forwarded to tile/select requests. - websocket-tile-layer.js: single buildTileRequest() includes visible_chiplets in every tile fetch and refresh. Backend: - tile_generator.{h,cpp}: ChipletNode + collectChiplets() walks the dbChip → dbChipInst → masterChip tree depth-first, composing dbTransforms top-down via local.concat(parent_world_xfm); chiplet paths use "/" as separator (matches ODB hierarchical names); cached vector auto-invalidates on (root, total_chipinst_count) fingerprint change to catch Tcl-driven dbChipInst mutations that dbBlockCallBackObj does not surface. - TileVisibility::visible_chiplets + isChipletVisible() drive a server-side filter; tiles for hidden chiplets are skipped, not just hidden in CSS. - renderTileBuffer() loops per chiplet with an R0 fast-path and a reverse-mapping slow-path for non-R0 orientations. selectAt() maps clicks through the inverse world transform so rotated / mirrored chiplet instances pick the right object. - serializeTechResponse emits a `chiplets` array with path, name, depth, parent, master, local/world bbox, world origin, orient. - getBounds() merges chiplet die areas in multi-die designs (single- chip designs stay on dbBlock BBox to preserve render scale). - getLayers() unions routing/cut layers from every reachable tech. - search.{h,cpp}: shared_mutex for child_block_data_ with double- checked locking in getData(); setTopChip() pre-populates every chiplet master block; shapesReady() now also checks chiplet master blocks so 3DBX/HIER top chips (no top block) no longer freeze the frontend on "Loading shapes…". Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
…ntrol Bring in refinements from `feature-chiplets-section` (The-OpenROAD-Project#10208) on top of the multi-tech display-controls work (The-OpenROAD-Project#10209). Keeps the multi-tech path semantics (e.g. dot-separated chiplet paths, layer_hierarchy, PtrSet/PtrMap, getTech() wrapper, per-chiplet layer_colors) while adopting: - cookie schema keyed by techData.block_name so hides do not leak across designs - countChipInsts() fingerprint to invalidate the chiplets() cache when Tcl creates/destroys dbChipInsts - improved comments on getLayers(), getBounds() and the chiplet visibility section Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Three follow-ups to the multi-tech display-controls review: - inspector.js: drop dead hover-rect filtering. The unpacking of [x1,y1,x2,y2,layer_id,instance_path] never matched the backend payload (request_handler emits plain bboxes), so the layerModel visibility check was always skipped. Replace with a TODO that documents what the backend has to emit before this filter can be reintroduced. - display-controls.js fallback path: use the same layers_parent/<name> ID prefix as the modern layer_hierarchy path. Cookies written under one path now round-trip cleanly through the other when the backend toggles between hierarchy and flat layer lists. - display-controls.js / checkbox-tree-model.js: key chiplet nodes by their stable path string instead of an array index. The intermediate pathToId Map and the parentId >= 0 sentinel disappear; tests with parentId:-1 still land in roots because _nodeMap.has(-1) is false. - display-controls.js: skip cookie persistence entirely when techData.block_name is empty so anonymous designs do not collapse into a shared "" bucket and inherit each other's hidden state. Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Three defensive fixes surfaced by the multi-tech audit: - chiplets(): take chiplets_mutex_ before reading db_->getChip() and countChipInsts(). The previous arrangement computed the fingerprint outside the lock, opening a small TOCTOU window where the cached values could disagree with the live count. Same critical section now covers both the check and the cache write. - chiplets(): document the lifetime contract. The returned reference is only valid while eagerInit() does not run; hot-path callers (renderTileBuffer, selectAt) must not trigger eagerInit while iterating, since the cache vector clear() in eagerInit() would invalidate their iterator. - TileVisibility::parseFromJson(): clamp visible_layers and visible_chiplets to kMaxVisibilityEntries (10000) so a malformed or oversized client payload cannot pin unbounded memory or thrash later contains() checks. Real designs come nowhere near the cap. Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Two improvements for the 3D viewer DRC highlight path: - highlightDRC(): replace the per-violation Mesh hitboxes with a single THREE.InstancedMesh backed by one shared unit BoxGeometry. Per-rect width/height/depth are encoded in setMatrixAt(); a parallel _drcHitboxMarkerIds array maps instanceId back to violation.id for picking. Edges/LineSegments stay per-rect for now — instancing EdgesGeometry under non-uniform scale would distort the outlines. Net effect: 1 draw call (was N) and 1 GPU geometry (was N) for the hit-test mesh, while the visual outline is unchanged. - _pickDrcMarkerId(): switch from intersectObjects(hitbox children) to intersectObject(_drcHitboxMesh) and look up the markerId through the new instanceId map. - onDestroy(): null out _lastSceneData so a destroyed widget does not hold the last scene payload alive in SPA-style design switches. - clearHighlightDRC(): drop _drcHitboxMesh and _drcHitboxMarkerIds so a late pick after a clear cannot reach freed instance data. Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
Drop a stray double blank line in renderTileBuffer() and rewrap the getLayerColorMap declaration so it matches the project's clang-format config. Fixes the pre-commit Clang-Format check. Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
e982c5e to
31acd9d
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
fix #10209