Skip to content

Fix ViewerGL to handle dynamic number of transforms and points#1217

Merged
eric-heiden merged 1 commit into
newton-physics:mainfrom
Cucchi01:fix_viewergl
Dec 10, 2025
Merged

Fix ViewerGL to handle dynamic number of transforms and points#1217
eric-heiden merged 1 commit into
newton-physics:mainfrom
Cucchi01:fix_viewergl

Conversation

@Cucchi01

@Cucchi01 Cucchi01 commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

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.

  • The migration guide in docs/migration.rst is up-to date

Before your PR is "Ready for review"

  • Necessary tests have been added and new examples are tested (see newton/tests/test_examples.py)
  • Documentation is up-to-date
  • Code passes formatting and linting checks with pre-commit run -a

Summary by CodeRabbit

  • Performance
    • Optimized dynamic instance rendering by tracking and processing only active instances, reducing computational overhead.
    • Enhanced memory management with proactive capacity allocation, minimizing repeated reallocations when datasets grow and improving streaming performance.

✏️ Tip: You can customize this high-level summary in your review settings.

Signed-off-by: Cucchi01 <cucchi01centr@gmail.com>
@Cucchi01 Cucchi01 temporarily deployed to external-pr-approval December 7, 2025 11:02 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented Dec 7, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The 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

Cohort / File(s) Change Summary
MeshInstancerGL active instance tracking
newton/_src/viewer/gl/opengl.py
Introduces active_instances tracking. update_from_transforms derives active count from transforms with bounds checks. update_from_points derives active from points and only launches if active > 0. Instanced render call uses active_instances instead of full num_instances.
ViewerGL dynamic capacity management
newton/_src/viewer/viewer_gl.py
log_instances: creates instancer with capacity = max(transform_count, 1), resizes to max(transform_count, old_capacity \* 2) if demand exceeds current capacity. log_points: initializes with capacity = max(num_points, 256), resizes using same doubling strategy. Both paths update from data only if resized or not hidden.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Bounds checking logic in opengl.py: verify consistency checks between transforms, scalings, and active_instances are correct
  • Capacity calculation strategy in viewer_gl.py: confirm doubling strategy (max(count, old_capacity \* 2)) prevents excessive reallocations and handles edge cases (initial creation, dramatic size changes)
  • Active instance rendering: ensure render call properly respects active_instances bounds while buffers remain fully allocated
  • State management transitions: validate that resizing, hiding, and update paths maintain consistent state across both files

Possibly related PRs

  • newton#522: Extends the MeshInstancerGL/ViewerGL instancing implementation with active instance tracking and dynamic resizing, building directly on the same renderer pathway.

Suggested reviewers

  • eric-heiden

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: fixing ViewerGL to handle dynamic numbers of transforms and points, which directly aligns with the file changes that introduce active instance management and dynamic capacity resizing.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 case

The new active_count logic and validation (active_count <= self.num_instances and len(scalings) == active_count when provided) make the API safer and prevent silent overruns; using dim=active_count and then rendering with self.active_instances is consistent. One small refinement you might consider: when active_count == 0 and both colors and materials are None, 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 resize

The new resizing logic in both log_instances and log_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:

  1. Explicitly destroy old instancers when upsizing.
    In both methods, when you create a new MeshInstancerGL because the requested count exceeds num_instances, the old instancer is simply dropped from self.objects. Relying on GC and __del__ to free GL resources is less predictable than calling an explicit cleanup method (similar to how log_lines calls LinesGL.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 = instancer
    
  •  new_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`.
    
    
  1. Hidden flag behavior.
    Using needs_update = resized or not hidden in log_instances means 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 to log_instances won’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 the or not hidden part.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5047e63 and 9e05256.

📒 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 correct

Initializing self.active_instances to num_instances after allocate() is fine given that every creation path from ViewerGL immediately 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 correct

Switching the instanced draw call to use self.active_instances instead of self.num_instances correctly limits rendering to the active subset while keeping buffers sized to capacity. Given the checks in update_from_transforms/update_from_points, self.active_instances cannot exceed self.num_instances, so this is safe.


728-739: Verify that all callers of update_from_points perform capacity management before exceeding limits

The capacity enforcement with ValueError for active > self.num_instances is 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 expectations

For points, using an initial capacity of max(num_points, 256) and doubling when num_points exceeds num_instances is a good default and pairs correctly with the update_from_points capacity check. Always calling update_from_points (regardless of hidden) also guarantees point transforms/colors stay in sync with simulation state. No functional issues spotted here.

@eric-heiden eric-heiden left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Cucchi01, this looks good to me!

@codecov

codecov Bot commented Dec 10, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 40 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
newton/_src/viewer/viewer_gl.py 0.00% 21 Missing ⚠️
newton/_src/viewer/gl/opengl.py 0.00% 19 Missing ⚠️

📢 Thoughts on this report? Let us know!

@eric-heiden eric-heiden added this pull request to the merge queue Dec 10, 2025
Merged via the queue into newton-physics:main with commit 314be10 Dec 10, 2025
20 checks passed
eric-heiden pushed a commit to eric-heiden/newton that referenced this pull request Jan 28, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Feb 17, 2026
4 tasks
mmacklin pushed a commit to mmacklin/newton that referenced this pull request Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants