Skip to content

Commit 1d70296

Browse files
Eagerly construct OvPhysxSceneDataBackend in OvPhysxManager.initialize
SimulationContext.__init__ wires up the central SceneDataProvider with the result of physics_manager.get_scene_data_backend() — when the backend was lazy-constructed in _warmup_and_load, that capture happened before warmup and the SDP held backend=None forever, breaking NewtonManager.update_visualization_state on the first call to visualizer.initialize(). Construct the backend instance in initialize() (matches PhysX's pattern) so SimulationContext gets a real reference. setup() still runs in _warmup_and_load when the wheel and USD stage are live; the backend reports empty transform_paths until then, which create_mapping already handles (returns None). Also clear the singleton in close() so cached TensorBinding handles don't survive a physx.reset() across SimulationContext restarts. Matches Newton's lifecycle.
1 parent d4855e4 commit 1d70296

1 file changed

Lines changed: 20 additions & 4 deletions

File tree

source/isaaclab_ovphysx/isaaclab_ovphysx/physics/ovphysx_manager.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,14 @@ def initialize(cls, sim_context: SimulationContext) -> None:
258258
cls._usd_handle = None
259259
cls._stage_path = None
260260
cls._pending_clones = []
261+
# Construct the SceneDataBackend eagerly so :class:`SimulationContext`
262+
# captures a real instance (not ``None``) when it builds the central
263+
# :class:`~isaaclab.scene.scene_data_provider.SceneDataProvider` in
264+
# its own ``__init__``. Bindings stay empty until :meth:`_warmup_and_load`
265+
# calls :meth:`OvPhysxSceneDataBackend.setup`, at which point the wheel
266+
# and the USD stage are live. Matches PhysX's pattern of constructing
267+
# the backend during ``initialize()``.
268+
cls._scene_data_backend = OvPhysxSceneDataBackend()
261269

262270
@classmethod
263271
def reset(cls, soft: bool = False) -> None:
@@ -299,6 +307,11 @@ def close(cls) -> None:
299307
cls._usd_handle = None
300308
cls._stage_path = None
301309
cls._warmup_done = False
310+
# Drop the SceneDataBackend singleton: its cached ``TensorBinding`` handles
311+
# point into the wheel's prior scene which we just ``physx.reset()``-ed.
312+
# The next :class:`SimulationContext` re-creates the backend in
313+
# :meth:`initialize`. Matches Newton's lifecycle.
314+
cls._scene_data_backend = None
302315

303316
if cls._tmp_dir is not None:
304317
cls._tmp_dir.cleanup()
@@ -339,10 +352,13 @@ def get_physx_instance(cls) -> Any:
339352
def get_scene_data_backend(cls) -> SceneDataBackend:
340353
"""Return the SceneDataBackend for the central SceneDataProvider.
341354
342-
Returns ``None`` before :meth:`_warmup_and_load` has run; afterwards
343-
returns the singleton :class:`OvPhysxSceneDataBackend` initialized
344-
against the ovphysx wheel's ``PhysX`` instance and the exported USD
345-
stage.
355+
Constructed eagerly in :meth:`initialize` so :class:`SimulationContext`
356+
captures a real instance (not ``None``) when wiring up the central
357+
:class:`~isaaclab.scene.scene_data_provider.SceneDataProvider`. Bindings
358+
are empty until :meth:`_warmup_and_load` calls
359+
:meth:`OvPhysxSceneDataBackend.setup` against the live ovphysx ``PhysX``
360+
and USD stage; reads against an unsetup backend return empty data
361+
rather than raising.
346362
"""
347363
return cls._scene_data_backend
348364

0 commit comments

Comments
 (0)