perf(segmentation): defer projection-heavy renders and merge only modified slices during labelmap edits#2797
Conversation
…ified slices during labelmap edits
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughSegmentation modification rendering now defers projection-heavy viewport updates, while combined labelmap representations process modified slices incrementally and restore mapper and actor state during removal. ChangesSegmentation rendering and labelmap lifecycle
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant SegmentationEventListener
participant SegmentationRenderingEngine
participant ProjectionHeavyViewport
participant CombinedLabelmap
SegmentationEventListener->>SegmentationRenderingEngine: triggerSegmentationRenderForModified(segmentationId)
SegmentationRenderingEngine->>ProjectionHeavyViewport: schedule coalesced delayed render
SegmentationEventListener->>CombinedLabelmap: modifiedSlicesToUse
CombinedLabelmap->>CombinedLabelmap: update touched slices
CombinedLabelmap-->>ProjectionHeavyViewport: render updated representation
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
known flaky test at ohif |
Context
Editing a segmentation that is displayed in a projection-heavy viewport was effectively unusable. Every
SEGMENTATION_DATA_MODIFIEDevent (brush strokes fire many per second) re-rendered every viewport showing the segmentation, and for viewports that re-march a slab per fragment (legacy volume viewports inLABELMAP_EDGE_PROJECTION_BLEND, or generic planar viewports with a slab presentation) each of those renders is expensive enough to freeze the UI for seconds. On top of that, the legacy independent-components path (addVolumesAsIndependentComponents, used by the labelmap-over-MIP example) re-merged the whole segmentation volume on the CPU with a per-voxelgetAtIndexloop on every event, and had several lifecycle bugs around removing and re-adding the representation.These changes are independent of the new generic-viewport labelmap-over-MIP capability (which depends on an unreleased vtk.js change) and can merge on their own; the generic feature is split out into #2784.
Changes & Results
Deferred rendering for projection-heavy viewports
triggerSegmentationRenderForModified: onSEGMENTATION_DATA_MODIFIED, cheap viewports render live while projection-heavy viewports (legacy edge-projection blend, or generic viewports with slab presentations) are re-rendered on a 240 ms trailing debounce, once the edit stream goes quiet. Projection viewports do not need to update in real time while drawing.Legacy independent-components path (
addVolumesAsIndependentComponents)modifiedSlicesToUsewith direct per-slice typed-array copies instead of a full-volumegetAtIndexloop, keeping the CPU cost proportional to the edit instead of the volume.representationUID; the plan's reconcile step otherwise tore down the combined actor (which is also the viewport's base volume actor) on the next render.vtkImageDatascalars (the injected CPU array misconfigured the shared streaming mapper) and the label-outline property state (the plain MIP otherwise kept rendering through the label-outline shader).removeEventListenerDebounced; the plainremoveEventListenerleaked the debounce wrapper, which kept merging into the detached image data after every delete/re-add cycle.Measured on the
labelmapMIPexample (PET volume, Apple Silicon): a brush stroke costs ~1.3 ms of main thread per pointer move, and the projection viewport refreshes ~240 ms after the stroke ends.Testing
pnpm run example labelmapMIP(stock vtk.js): click "Add Labelmap Representation", draw on the left viewport with the brush - drawing stays responsive and the MIP viewport updates shortly after the stroke ends. Delete and re-add the representation: after deleting, the MIP viewport should render the plain MIP without posterized/white artifacts, and repeated delete/re-add cycles should not slow editing down.Checklist
PR
semantic-release format and guidelines.
Code
etc.)
Public Documentation Updates
additions or removals.
Tested Environment
Summary by CodeRabbit
Performance
Bug Fixes