Fix ViewerGL to handle dynamic number of transforms and points#1217
Conversation
Signed-off-by: Cucchi01 <cucchi01centr@gmail.com>
📝 WalkthroughWalkthroughThe PR introduces active instance tracking and dynamic capacity management to the mesh instancing system. MeshInstancerGL now maintains an active_instances count to render only the active subset while keeping full buffers allocated. ViewerGL's log_instances and log_points methods now implement dynamic resizing, expanding capacity by doubling when demand exceeds current allocation, rather than always allocating exactly for current size. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
newton/_src/viewer/gl/opengl.py (1)
689-707: Bounds checks and active-count-based launches are sound; consider a small guard for the zero-active caseThe new
active_countlogic and validation (active_count <= self.num_instancesandlen(scalings) == active_countwhen provided) make the API safer and prevent silent overruns; usingdim=active_countand then rendering withself.active_instancesis consistent. One small refinement you might consider: whenactive_count == 0and bothcolorsandmaterialsareNone, you could early-return instead of calling_update_vbo, avoiding an unnecessary host upload on empty updates.if active_count > 0: wp.launch( update_vbo_transforms, dim=active_count, inputs=[transforms, scalings], outputs=[self.world_xforms], device=self.device, record_tape=False, ) - self.active_instances = active_count - # Upload the full buffer; only the first `active_instances` rows are rendered - self._update_vbo(self.world_xforms, colors, materials) + self.active_instances = active_count + # Upload the full buffer; only the first `active_instances` rows are rendered + if active_count > 0 or colors is not None or materials is not None: + self._update_vbo(self.world_xforms, colors, materials)Also applies to: 711-725
newton/_src/viewer/viewer_gl.py (1)
287-303: Dynamic capacity growth is reasonable; consider explicit cleanup of old instancers on resizeThe new resizing logic in both
log_instancesandlog_points(initial capacity with headroom and doubling when exceeded) is a good fit for streaming workloads and avoids constant reallocations. Two follow‑ups worth considering:
Explicitly destroy old instancers when upsizing.
In both methods, when you create a newMeshInstancerGLbecause the requested count exceedsnum_instances, the old instancer is simply dropped fromself.objects. Relying on GC and__del__to free GL resources is less predictable than calling an explicit cleanup method (similar to howlog_linescallsLinesGL.destroy()before reallocating).A simple pattern would be:
elif transform_count > instancer.num_instances:
new_capacity = max(transform_count, instancer.num_instances * 2)instancer = MeshInstancerGL(new_capacity, self.objects[mesh])self.objects[name] = instancer
old_instancer = instancernew_capacity = max(transform_count, instancer.num_instances * 2)instancer = MeshInstancerGL(new_capacity, self.objects[mesh])self.objects[name] = instancer# If MeshInstancerGL grows a destroy() method mirroring MeshGL/LinesGL,# call it here to promptly free GL resources.if hasattr(old_instancer, "destroy"):old_instancer.destroy()and analogously in `log_points`.
- Hidden flag behavior.
Usingneeds_update = resized or not hiddeninlog_instancesmeans you still update GPU state when hidden only if capacity changed, which is a sensible trade‑off. Just keep in mind that while an instancer is hidden, calls tolog_instanceswon’t refresh transforms/colors unless a resize happens; if you ever rely on “hidden but still up‑to‑date” instance data, you’ll want to drop theor not hiddenpart.Overall the new behavior is correct; the cleanup tweak would mainly tighten resource management for long sessions.
Also applies to: 381-390
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
newton/_src/viewer/gl/opengl.py(4 hunks)newton/_src/viewer/viewer_gl.py(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: shi-eric
Repo: newton-physics/newton PR: 521
File: newton/examples/example_cloth_hanging.py:36-36
Timestamp: 2025-08-12T05:17:34.423Z
Learning: The Newton migration guide (docs/migration.rst) is specifically for documenting how to migrate existing warp.sim functionality to Newton equivalents. New Newton-only features that didn't exist in warp.sim do not need migration documentation.
🧬 Code graph analysis (1)
newton/_src/viewer/viewer_gl.py (2)
newton/_src/utils/selection.py (1)
get(122-123)newton/_src/viewer/gl/opengl.py (1)
MeshInstancerGL(543-795)
🪛 Ruff (0.14.7)
newton/_src/viewer/gl/opengl.py
702-704: Avoid specifying long messages outside the exception class
(TRY003)
706-706: Avoid specifying long messages outside the exception class
(TRY003)
735-735: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (4)
newton/_src/viewer/gl/opengl.py (3)
550-562: Active instance tracking initialization looks correctInitializing
self.active_instancestonum_instancesafterallocate()is fine given that every creation path fromViewerGLimmediately calls an update method, which will set the true active count before any render occurs. No functional issues here.
780-795: Rendering only the active subset is correctSwitching the instanced draw call to use
self.active_instancesinstead ofself.num_instancescorrectly limits rendering to the active subset while keeping buffers sized to capacity. Given the checks inupdate_from_transforms/update_from_points,self.active_instancescannot exceedself.num_instances, so this is safe.
728-739: Verify that all callers ofupdate_from_pointsperform capacity management before exceeding limitsThe capacity enforcement with
ValueErrorforactive > self.num_instancesis sound, but confirm all call sites follow the reallocation pattern. Check that no code paths rely on implicit capacity growth and that ViewerGL.log_points consistently reallocates before updating.newton/_src/viewer/viewer_gl.py (1)
381-392: Point instancing resize logic matches MeshInstancerGL expectationsFor points, using an initial capacity of
max(num_points, 256)and doubling whennum_pointsexceedsnum_instancesis a good default and pairs correctly with theupdate_from_pointscapacity check. Always callingupdate_from_points(regardless ofhidden) also guarantees point transforms/colors stay in sync with simulation state. No functional issues spotted here.
eric-heiden
left a comment
There was a problem hiding this comment.
Thanks @Cucchi01, this looks good to me!
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…n-physics#1217) Signed-off-by: Cucchi01 <cucchi01centr@gmail.com>
…n-physics#1217) Signed-off-by: Cucchi01 <cucchi01centr@gmail.com>
Description
It addresses bug #1216
Newton Migration Guide
Please ensure the migration guide for warp.sim users is up-to-date with the changes made in this PR.
docs/migration.rstis up-to dateBefore your PR is "Ready for review"
newton/tests/test_examples.py)pre-commit run -aSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.