Skip to content

perf: add PrepareForReuse to FabricFrameView, remove sync_usd_on_fabric_write#5380

Open
pv-nvidia wants to merge 15 commits intoisaac-sim:developfrom
pv-nvidia:fix/fabric-prepare-for-reuse
Open

perf: add PrepareForReuse to FabricFrameView, remove sync_usd_on_fabric_write#5380
pv-nvidia wants to merge 15 commits intoisaac-sim:developfrom
pv-nvidia:fix/fabric-prepare-for-reuse

Conversation

@pv-nvidia
Copy link
Copy Markdown

@pv-nvidia pv-nvidia commented Apr 23, 2026

Summary

Replace the sync_usd_on_fabric_write workaround in FabricFrameView with proper PrepareForReuse() calls on the Fabric PrimSelection. This tells the renderer (FSD/Storm) that Fabric data has changed, so the next rendered frame reflects updated transforms — eliminating the need to copy Fabric writes back to USD.

Motivation

The existing sync_usd_on_fabric_write flag worked by mirroring every Fabric write back to USD, which defeated the performance benefits of Fabric. With PrepareForReuse(), the rendering pipeline is properly notified of Fabric data changes without any USD writeback.

Additionally, the old code incorrectly fell back to USD for CPU devices — Warp handles CPU Fabric buffers correctly, so the fallback was unnecessary.

This addresses two of the issues raised in @pbarejko Piotr's review of PR #4923:

Changes

Core (FabricFrameView)

  • Call _prepare_for_reuse() in write paths (set_world_poses, set_scales) to notify the renderer
  • Remove sync_usd_on_fabric_write parameter (accepted via **kwargs for backward compat)
  • Remove incorrect CPU/device fallback warnings — Warp handles CPU Fabric buffers correctly
  • Add _rebuild_fabric_arrays() for topology change recovery when PrepareForReuse() returns True, with assertion guarding the prim-count invariant

Camera

  • Remove sync_usd_on_fabric_write=True from FrameView construction in camera.py

Benchmark Results

1024 prims, 50 iterations, NVIDIA L40 GPU:

Operation USD (ms) Fabric (ms) Speedup
Get World Poses 14.71 0.07 203x
Set World Poses 40.75 0.16 259x
Interleaved Set→Get 55.90 0.24 232x
Get Local Poses 11.08 11.12 1.0x
Set Local Poses 16.14 16.28 1.0x

Local poses fall back to USD (expected — Fabric only accelerates world poses via omni:fabric:worldMatrix).

Tests Added

Test What it validates
test_camera_pose_update_reflected_in_render Camera pose changes propagate to rendered depth (close vs far) for CPU/GPU, tiled/non-tiled
test_fabric_set_world_does_not_write_back_to_usd Fabric writes stay in Fabric, USD prim unchanged
test_set_world_updates_local (xfail) Documents Issue #5: set_world_poses doesn't update local pose in Fabric mode

Test Results

Test Suite Passed Skipped Xfailed Total
Fabric contract tests (test_views_xform_prim_fabric.py) 17 16 1 34
USD contract tests (test_views_xform_prim.py) 45 0 0 45
Camera render test (test_tiled_camera.py) 8 0 0 8

Type of change

  • Performance improvement (removes redundant USD writeback on Fabric operations)

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the changelog and the corresponding version in the extension's config/extension.toml file
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

No doc changes needed (parameter wasn't referenced in any docs)

@github-actions github-actions Bot added bug Something isn't working isaac-sim Related to Isaac Sim team isaac-lab Related to Isaac Lab team labels Apr 23, 2026
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Summary

This PR replaces the sync_usd_on_fabric_write workaround in FabricFrameView with proper PrepareForReuse() calls to notify the RTX renderer of Fabric data changes. The change removes the performance-defeating USD writeback pattern while maintaining correct rendering behavior. The implementation is architecturally sound with good test coverage, though there are a few correctness concerns around the placement and frequency of _prepare_for_reuse() calls.

Architecture Impact

  • Camera sensor: Removes sync_usd_on_fabric_write=True from FrameView construction, now relying on PrepareForReuse() for renderer synchronization.
  • FabricFrameView: Internal API change - sync_usd_on_fabric_write parameter removed (with deprecation warning via **kwargs).
  • Downstream callers: Any code passing sync_usd_on_fabric_write=True to FrameView will now get a deprecation warning but continue to function (the flag is simply ignored).
  • Kit extensions: Adds omni.kit.viewport.window and omni.kit.hydra_texture as dependencies for headless rendering.

Implementation Verdict

Minor fixes needed — The core approach is correct, but _prepare_for_reuse() is called in getters where it shouldn't be, and there's a potential race condition in the initialization flow.

Test Coverage

Good coverage for this change:

  • test_camera_pose_update_reflected_in_render: Validates that pose changes propagate to rendered depth (critical regression test)
  • test_fabric_set_world_does_not_write_back_to_usd: Confirms USD writeback removal
  • test_prepare_for_reuse_detects_topology_change: Basic API contract test
  • test_set_world_updates_local: Properly marked as xfail documenting known limitation

Missing: No test for the topology-changed path (_rebuild_fabric_arrays). The test only verifies PrepareForReuse() returns False when topology hasn't changed.

CI Status

No CI checks available yet — cannot verify the changes work on the required Kit version.

Findings

🟡 Warning: source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py:189-190 — _prepare_for_reuse() called in get_world_poses() is semantically incorrect

PrepareForReuse() is a write notification mechanism per the PR description ("tells the renderer that Fabric data is about to be modified"). Calling it before a read operation is incorrect — the purpose is to notify before writes, not reads. This could cause unnecessary renderer invalidation on every pose query.

def get_world_poses(self, indices=None):
    ...
    self._prepare_for_reuse()  # <-- Should not be here for a getter

Same issue at line 281 in get_scales(). The calls should only be in set_world_poses() and set_scales().

🟡 Warning: source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py:146 — _prepare_for_reuse() called before Fabric arrays may be valid

In set_world_poses(), _prepare_for_reuse() is called at line 146, but _fabric_selection is only set during _initialize_fabric() which happens at line 143. On the first call, _initialize_fabric() runs, sets _fabric_selection, then _prepare_for_reuse() is called. However, if _initialize_fabric() fails partway through, _fabric_selection could be partially initialized. The guard in _prepare_for_reuse() (line 320: if self._fabric_selection is None) handles this, but the ordering is confusing.

Consider calling _prepare_for_reuse() after the writes complete, not before.

🔵 Improvement: source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py:326-327 — Topology change handling logs at INFO but doesn't re-sync from USD

When topology changes, _rebuild_fabric_arrays() rebuilds the index mappings but doesn't re-sync transforms from USD. If prims were added, their initial Fabric world matrices may be stale. The existing _sync_fabric_from_usd_once() is a one-shot sync; a topology change might warrant another sync.

def _prepare_for_reuse(self) -> None:
    ...
    if topology_changed:
        logger.info("Fabric topology changed — rebuilding view-to-fabric index mapping.")
        self._rebuild_fabric_arrays()
        # Consider: self._fabric_usd_sync_done = False  # Force re-sync

🔵 Improvement: source/isaaclab_physx/test/sim/test_views_xform_prim_fabric.py:127-132 — The xfail override shadows the parametrized device fixture

The test function test_set_world_updates_local takes device and view_factory as parameters, but there's no @pytest.mark.parametrize("device", ...) decorator. This relies on fixture injection from the shared contract utils. If the shared test was parametrized with multiple devices, this override won't run for all of them.

@pytest.mark.xfail(...)
def test_set_world_updates_local(device, view_factory):  # Where does 'device' come from?

Verify that the device fixture is properly inherited or add explicit parametrization.

🔵 Improvement: source/isaaclab/test/sensors/test_tiled_camera.py:215-216 — Test creates camera without cleanup guard

The setup_camera fixture cleans up a specific camera, but test_camera_pose_update_reflected_in_render creates an additional camera at /World/PoseTestCam. While del camera is called at line 268, if an assertion fails before that line, the camera may leak.

Consider using a context manager or adding the camera to a cleanup list.

🔵 Improvement: source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py:63-71 — Constructor signature changed without updating all callers

The old signature had sync_usd_on_fabric_write: bool = False as a positional-or-keyword parameter. Now it's removed and handled via **kwargs. The test file at line 97 shows the update, but any external code calling FabricFrameView(..., sync_usd_on_fabric_write=True) will get a deprecation warning rather than a hard error. This is fine for backward compatibility but should be documented in the changelog.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 23, 2026

Greptile Summary

This PR replaces the sync_usd_on_fabric_write workaround in FabricFrameView with proper PrepareForReuse() calls on write paths (set_world_poses, set_scales), eliminating redundant USD writeback and delivering 200–260× speedups on world-pose operations. It also enables the CPU Fabric path (removing the old CPU fallback), adds _rebuild_fabric_arrays() for topology-change recovery, and backs the changes with a new render-validation test and a no-writeback contract test.

  • P1 — \"cuda\" not remapped for SelectPrims: The removed _initialize_fabric block previously remapped bare \"cuda\"\"cuda:0\" before calling SelectPrims (with an explicit log warning). Now SelectPrims(device=\"cuda\") is called directly, and no test covers device=\"cuda\" — a potential runtime failure for the common shorthand.

Confidence Score: 3/5

Safe to merge for cuda:0 and cpu users, but the bare 'cuda' device path is an untested regression risk.

One P1 finding: removal of the 'cuda' → 'cuda:0' remap in _initialize_fabric is untested and the old code's explicit warning implied SelectPrims requires an indexed device string. Multiple P1s pull the score below the P1 ceiling of 4.

source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py — specifically the _initialize_fabric device handling and _sync_fabric_from_usd_once PrepareForReuse double-call.

Important Files Changed

Filename Overview
source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Core change: replaces sync_usd_on_fabric_write with PrepareForReuse calls on write paths; adds _rebuild_fabric_arrays for topology recovery. CPU Fabric path enabled and cuda device remapping removed — potential P1 regression when device="cuda" passes unindexed string to SelectPrims.
source/isaaclab/isaaclab/sensors/camera/camera.py Removes sync_usd_on_fabric_write=True from FrameView construction; clean follow-on to the FabricFrameView change.
source/isaaclab/isaaclab/sim/views/usd_frame_view.py Doc-only tweak: removes the sync_usd_on_fabric_write mention from the **kwargs docstring.
source/isaaclab_physx/test/sim/test_views_xform_prim_fabric.py Adds Fabric-specific tests (no-writeback assertion, xfail for local-pose stale read). CPU skip removed to match new CPU Fabric support. All parametrizations use ["cpu", "cuda:0"] — "cuda" shorthand not covered.
source/isaaclab/test/sensors/test_tiled_camera.py Adds test_camera_pose_update_reflected_in_render to validate PrepareForReuse propagation to the renderer across cpu/cuda:0 × TiledCamera/Camera. Correctly carries the @pytest.mark.isaacsim_ci marker.
source/isaaclab/test/sensors/test_multi_mesh_ray_caster_camera.py Shifts camera eye from [0,0,5] to [0.1,0,5] to avoid a degenerate view-direction edge case; unrelated to Fabric changes.
source/isaaclab/test/sensors/test_ray_caster_camera.py Same eye-offset fix as test_multi_mesh_ray_caster_camera.py; no functional concerns.
source/isaaclab_physx/config/extension.toml Version bumped from 0.5.29 to 0.5.30 to accompany the Fabric changes.
source/isaaclab_physx/docs/CHANGELOG.rst New 0.5.30 changelog entry documents the PrepareForReuse migration, CPU Fabric enablement, and topology-change recovery.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant FabricFrameView
    participant PrimSelection
    participant WarpKernel
    participant Renderer

    Note over FabricFrameView: set_world_poses / set_scales
    Caller->>FabricFrameView: set_world_poses(positions, orientations)
    FabricFrameView->>FabricFrameView: _initialize_fabric() [if first call]
    FabricFrameView->>PrimSelection: PrepareForReuse()
    PrimSelection-->>FabricFrameView: topology_changed (bool)
    alt topology_changed == True
        FabricFrameView->>FabricFrameView: _rebuild_fabric_arrays()
    end
    FabricFrameView->>Renderer: (invalidate render state)
    FabricFrameView->>WarpKernel: compose_fabric_transformation_matrix(...)
    WarpKernel-->>FabricFrameView: writes to _fabric_world_matrices
    FabricFrameView->>FabricFrameView: _fabric_hierarchy.update_world_xforms()

    Note over FabricFrameView: get_world_poses (no PrepareForReuse)
    Caller->>FabricFrameView: get_world_poses(indices)
    FabricFrameView->>WarpKernel: decompose_fabric_transformation_matrix(...)
    WarpKernel-->>Caller: positions, orientations
Loading

Comments Outside Diff (1)

  1. source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py, line 394-405 (link)

    P1 "cuda" device string not remapped for SelectPrims

    The old code explicitly remapped "cuda""cuda:0" before calling SelectPrims (with a log warning: "Fabric device is not specified, defaulting to 'cuda:0'"). That remap is now gone, so SelectPrims(device="cuda") is called when self._device == "cuda". Since "cuda" was added to _fabric_supported_devices without confirming that USDRT SelectPrims accepts the un-indexed string, any caller using the common device="cuda" shorthand will silently reach a potential runtime failure. No test in this PR parametrizes with "cuda" to catch a regression.

    # suggested fix in _initialize_fabric:
    fabric_device = self._device
    if self._device == "cuda":
        fabric_device = "cuda:0"   # SelectPrims requires an indexed CUDA device

Reviews (6): Last reviewed commit: "fix: expand device parameterization for ..." | Re-trigger Greptile

Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Outdated
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py
Comment thread source/isaaclab/test/sensors/test_tiled_camera.py Outdated
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Compute local poses from Fabric world matrices instead of falling
back to stale USD data.  This fixes the inconsistency where
set_world_poses() modified Fabric worldMatrix but get_local_poses()
still read from USD, returning stale values (Issue isaac-sim#5).

How it works:
- get_local_poses: reads child world pose from Fabric, parent world
  pose from USD, computes local = inv(parent) * child
- set_local_poses: reads parent world from USD, computes child world
  = parent * local, writes to Fabric via set_world_poses

Added quaternion math helpers (_quat_mul, _quat_conjugate,
_quat_rotate) for the parent/child transform composition.

Test changes:
- Remove xfail from test_set_world_updates_local (now passes)

Addresses Piotr's Issue isaac-sim#5 (localMatrix).

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Add RAII-style context managers for safe raw Fabric access:

- fabric_write(): calls PrepareForReuse on entry, update_world_xforms +
  sync on exit.  Provides world_matrices fabricarray and view_to_fabric
  mapping for custom warp kernel launches.
- fabric_read(): calls PrepareForReuse on entry (ensures valid pointers
  after topology changes), no-op on exit.

Also exposes read-only properties:
- world_matrices: the raw fabricarray of omni:fabric:worldMatrix
- view_to_fabric_mapping: the view-index to fabric-index mapping

This addresses Piotr's Issue isaac-sim#6 (reader/writer pattern) by providing
a structured way to bracket Fabric operations that ensures
PrepareForReuse and hierarchy updates are never forgotten.

Tests added:
- test_fabric_write_context_manager: validates write + readback
- test_fabric_read_context_manager: validates read without side effects

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
@pv-nvidia pv-nvidia force-pushed the fix/fabric-prepare-for-reuse branch from 73f83d7 to 6653e10 Compare April 24, 2026 09:00
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Compute local poses from Fabric world matrices instead of falling
back to stale USD data.  This fixes the inconsistency where
set_world_poses() modified Fabric worldMatrix but get_local_poses()
still read from USD, returning stale values (Issue isaac-sim#5).

How it works:
- get_local_poses: reads child world pose from Fabric, parent world
  pose from USD, computes local = inv(parent) * child
- set_local_poses: reads parent world from USD, computes child world
  = parent * local, writes to Fabric via set_world_poses

Added quaternion math helpers (_quat_mul, _quat_conjugate,
_quat_rotate) for the parent/child transform composition.

Test changes:
- Remove xfail from test_set_world_updates_local (now passes)

Addresses Piotr's Issue isaac-sim#5 (localMatrix).

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Add RAII-style context managers for safe raw Fabric access:

- fabric_write(): calls PrepareForReuse on entry, update_world_xforms +
  sync on exit.  Provides world_matrices fabricarray and view_to_fabric
  mapping for custom warp kernel launches.
- fabric_read(): calls PrepareForReuse on entry (ensures valid pointers
  after topology changes), no-op on exit.

Also exposes read-only properties:
- world_matrices: the raw fabricarray of omni:fabric:worldMatrix
- view_to_fabric_mapping: the view-index to fabric-index mapping

This addresses Piotr's Issue isaac-sim#6 (reader/writer pattern) by providing
a structured way to bracket Fabric operations that ensures
PrepareForReuse and hierarchy updates are never forgotten.

Tests added:
- test_fabric_write_context_manager: validates write + readback
- test_fabric_read_context_manager: validates read without side effects

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
@pv-nvidia pv-nvidia force-pushed the fix/fabric-prepare-for-reuse branch from 6653e10 to c14b74e Compare April 24, 2026 10:51
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Compute local poses from Fabric world matrices instead of falling
back to stale USD data.  This fixes the inconsistency where
set_world_poses() modified Fabric worldMatrix but get_local_poses()
still read from USD, returning stale values (Issue isaac-sim#5).

How it works:
- get_local_poses: reads child world pose from Fabric, parent world
  pose from USD, computes local = inv(parent) * child
- set_local_poses: reads parent world from USD, computes child world
  = parent * local, writes to Fabric via set_world_poses

Added quaternion math helpers (_quat_mul, _quat_conjugate,
_quat_rotate) for the parent/child transform composition.

Test changes:
- Remove xfail from test_set_world_updates_local (now passes)

Addresses Piotr's Issue isaac-sim#5 (localMatrix).

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Add RAII-style context managers for safe raw Fabric access:

- fabric_write(): calls PrepareForReuse on entry, update_world_xforms +
  sync on exit.  Provides world_matrices fabricarray and view_to_fabric
  mapping for custom warp kernel launches.
- fabric_read(): calls PrepareForReuse on entry (ensures valid pointers
  after topology changes), no-op on exit.

Also exposes read-only properties:
- world_matrices: the raw fabricarray of omni:fabric:worldMatrix
- view_to_fabric_mapping: the view-index to fabric-index mapping

This addresses Piotr's Issue isaac-sim#6 (reader/writer pattern) by providing
a structured way to bracket Fabric operations that ensures
PrepareForReuse and hierarchy updates are never forgotten.

Tests added:
- test_fabric_write_context_manager: validates write + readback
- test_fabric_read_context_manager: validates read without side effects

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
@pv-nvidia pv-nvidia force-pushed the fix/fabric-prepare-for-reuse branch from c14b74e to 49c51f7 Compare April 24, 2026 13:32
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Compute local poses from Fabric world matrices instead of falling
back to stale USD data.  This fixes the inconsistency where
set_world_poses() modified Fabric worldMatrix but get_local_poses()
still read from USD, returning stale values (Issue isaac-sim#5).

How it works:
- get_local_poses: reads child world pose from Fabric, parent world
  pose from USD, computes local = inv(parent) * child
- set_local_poses: reads parent world from USD, computes child world
  = parent * local, writes to Fabric via set_world_poses

Added quaternion math helpers (_quat_mul, _quat_conjugate,
_quat_rotate) for the parent/child transform composition.

Test changes:
- Remove xfail from test_set_world_updates_local (now passes)

Addresses Piotr's Issue isaac-sim#5 (localMatrix).

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Add RAII-style context managers for safe raw Fabric access:

- fabric_write(): calls PrepareForReuse on entry, update_world_xforms +
  sync on exit.  Provides world_matrices fabricarray and view_to_fabric
  mapping for custom warp kernel launches.
- fabric_read(): calls PrepareForReuse on entry (ensures valid pointers
  after topology changes), no-op on exit.

Also exposes read-only properties:
- world_matrices: the raw fabricarray of omni:fabric:worldMatrix
- view_to_fabric_mapping: the view-index to fabric-index mapping

This addresses Piotr's Issue isaac-sim#6 (reader/writer pattern) by providing
a structured way to bracket Fabric operations that ensures
PrepareForReuse and hierarchy updates are never forgotten.

Tests added:
- test_fabric_write_context_manager: validates write + readback
- test_fabric_read_context_manager: validates read without side effects

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
@pv-nvidia pv-nvidia force-pushed the fix/fabric-prepare-for-reuse branch from 49c51f7 to caa1949 Compare April 24, 2026 19:37
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Compute local poses from Fabric world matrices instead of falling
back to stale USD data.  This fixes the inconsistency where
set_world_poses() modified Fabric worldMatrix but get_local_poses()
still read from USD, returning stale values (Issue isaac-sim#5).

How it works:
- get_local_poses: reads child world pose from Fabric, parent world
  pose from USD, computes local = inv(parent) * child
- set_local_poses: reads parent world from USD, computes child world
  = parent * local, writes to Fabric via set_world_poses

Added quaternion math helpers (_quat_mul, _quat_conjugate,
_quat_rotate) for the parent/child transform composition.

Test changes:
- Remove xfail from test_set_world_updates_local (now passes)

Addresses Piotr's Issue isaac-sim#5 (localMatrix).

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
pv-nvidia added a commit to pv-nvidia/IsaacLab that referenced this pull request Apr 24, 2026
Add RAII-style context managers for safe raw Fabric access:

- fabric_write(): calls PrepareForReuse on entry, update_world_xforms +
  sync on exit.  Provides world_matrices fabricarray and view_to_fabric
  mapping for custom warp kernel launches.
- fabric_read(): calls PrepareForReuse on entry (ensures valid pointers
  after topology changes), no-op on exit.

Also exposes read-only properties:
- world_matrices: the raw fabricarray of omni:fabric:worldMatrix
- view_to_fabric_mapping: the view-index to fabric-index mapping

This addresses Piotr's Issue isaac-sim#6 (reader/writer pattern) by providing
a structured way to bracket Fabric operations that ensures
PrepareForReuse and hierarchy updates are never forgotten.

Tests added:
- test_fabric_write_context_manager: validates write + readback
- test_fabric_read_context_manager: validates read without side effects

Depends on: fix/fabric-prepare-for-reuse (PR isaac-sim#5380)
@pbarejko pbarejko self-requested a review April 27, 2026 17:30
@pv-nvidia pv-nvidia force-pushed the fix/fabric-prepare-for-reuse branch 3 times, most recently from afa5b85 to 42edb07 Compare April 28, 2026 09:56
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py
@pbarejko
Copy link
Copy Markdown
Collaborator

pbarejko commented May 2, 2026

@kellyguo11 I ran this branch on mgpu setup and I confirm it doesn't crash:

[INFO]: Base environment:
	Environment device    : cuda:1
	Environment seed      : 43
	Physics step-size     : 0.008333333333333333
	Rendering step-size   : 0.016666666666666666
	Environment step-size : 0.016666666666666666
[INFO]: Base environment:
	Environment device    : cuda:0
	Environment seed      : 42
	Physics step-size     : 0.008333333333333333
	Rendering step-size   : 0.016666666666666666
	Environment step-size : 0.016666666666666666
[INFO]: Base environment:
	Environment device    : cuda:3
	Environment seed      : 45
	Physics step-size     : 0.008333333333333333
	Rendering step-size   : 0.016666666666666666
	Environment step-size : 0.016666666666666666
[INFO]: Base environment:
	Environment device    : cuda:2
	Environment seed      : 44
	Physics step-size     : 0.008333333333333333
	Rendering step-size   : 0.016666666666666666
	Environment step-size : 0.016666666666666666

Training time: 140.94 seconds

amazing! thanks a lot for checking! was that with a perception environment?

Yes, this was the command I used for training:

CUDA_VISIBLE_DEVICES=0,1,2,3 ./isaaclab.sh -p -m torch.distributed.run \
    --nproc_per_node=4 --master_port=29504 scripts/reinforcement_learning/rsl_rl/train.py \
    --task=Isaac-Dexsuite-Kuka-Allegro-Reorient-v0 --headless --distributed \
    --num_envs=4096 --max_iterations=5 --run_name=gpu4_vis presets=newton,single_camera,newton_renderer,depth64

Comment thread source/isaaclab/test/sensors/test_multi_mesh_ray_caster_camera.py
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

The changes between 9e3dc507 and 4acba70d are minimal:

  1. A test file tweak in test_multi_mesh_ray_caster_camera.py changing camera eye position from (0.0, 0.0, 5.0) to (0.1, 0.0, 5.0) — this is an unrelated test fix to avoid a degenerate view direction.

All previous concerns remain addressed. The core PrepareForReuse implementation is unchanged and correct.

Implementation Verdict

Ship it — Ready to merge.

pv-nvidia added 11 commits May 4, 2026 11:52
…c_write

- FabricFrameView calls PrepareForReuse after warp writes for renderer sync
- Remove sync_usd_on_fabric_write workaround
- Camera uses FrameView directly (PrepareForReuse handles renderer sync)
- Remove incorrect CPU/device fallback warnings (Warp handles CPU Fabric fine)
Remove the special-case UsdFrameView for cameras. Camera now uses
the same FrameView (→ FabricFrameView when Fabric is enabled) as
all other prim types.
…date device handling for Fabric operations"

This reverts commit 4310d7a.
The fragment-based changelog system landed in upstream develop (isaac-sim#5434) to
avoid per-PR merge conflicts on the top of CHANGELOG.rst. Switch this PR
to the new system: drop the in-rebase direct edits to CHANGELOG.rst and
config/extension.toml, and ship a fragment under changelog.d/ instead.
* Drop redundant `fabric_device` local in `_initialize_fabric` — every
  assignment was `fabric_device = self._device`, so just use `self._device`
  directly. `self._fabric_device` (the persistent attribute) is preserved.
* Drop the explicit `_fabric_usd_sync_done = True` at the end of
  `_sync_fabric_from_usd_once`. Both `set_world_poses` and `set_scales`
  already set it on success, so the trailing assignment is dead under the
  happy path and would mask a partial failure if either write raised.
* Tighten the no-writeback assertion in
  `test_fabric_set_world_does_not_write_back_to_usd` from `atol=0.1` to
  `atol=0.0`. USD literally must not have moved — any drift indicates a
  residual writeback path, and the loose tolerance would hide a 0.099-unit
  regression.
* Add `test_fabric_rebuild_after_topology_change` covering the
  `_prepare_for_reuse` → `_rebuild_fabric_arrays` branch, which is the
  load-bearing replacement for the removed `sync_usd_on_fabric_write`.
  The test monkeypatches `_prepare_for_reuse` to always take the rebuild
  branch (real Fabric topology changes are hard to provoke from a unit
  test) and verifies that a subsequent write/read still produces correct
  data, proving `_view_to_fabric` and `_fabric_world_matrices` are still
  consistent after the rebuild.
@pv-nvidia pv-nvidia force-pushed the fix/fabric-prepare-for-reuse branch from 4acba70 to 1235be6 Compare May 4, 2026 12:07
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

The changes between 4acba70d and 1235be63 consist of:

  1. A similar test tweak in test_ray_caster_camera.py changing camera eye position from (0.001, 0.0, 5.0) to (0.1, 0.0, 5.0) — matching the same fix pattern applied to test_multi_mesh_ray_caster_camera.py in the previous commit.

This is a consistent, minor test fix to avoid degenerate view directions. No new concerns introduced.

Implementation Verdict

Ship it — Ready to merge once CI passes.

CI Status

The Check changelog fragments failure needs investigation — verify the changelog fragment fix-fabric-prepare-for-reuse.rst follows the expected naming/format conventions. Most critical CI jobs are still pending but pre-commit passed.

pv-nvidia added 2 commits May 4, 2026 14:49
CI's "Verify changelog fragments" check flagged isaaclab as a touched
package without a fragment. The change is the camera.py call site
dropping the now-removed sync_usd_on_fabric_write=True kwarg from its
FrameView construction (paired with the kwarg removal documented in the
isaaclab_physx fragment).
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

The changes from 1235be63 to 53dce4b0 are minimal:

  1. Fixed import in camera.py — consolidated BaseRenderer and CameraRenderSpec into a single import line (cosmetic cleanup).

Previous concerns were minimal (CI check), and the code changes remain sound. The changelog fragment check is now passing (✅).

CI Status

Several CI jobs are failing (isaaclab_physx, isaaclab (core) [1/3], isaaclab_ov, etc.) — these need investigation before merge. The test-curobo and test-skillgen failures appear to be infrastructure/unrelated issues based on typical patterns, but isaaclab_physx failure is concerning given this PR directly modifies that package.

Implementation Verdict

Minor fixes needed — Investigate the isaaclab_physx CI failure before merging. If it's an unrelated flaky test or infrastructure issue, this is ready to ship.

@pv-nvidia pv-nvidia requested a review from pbarejko May 4, 2026 21:13
Comment thread source/isaaclab/test/sensors/test_tiled_camera.py Outdated
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Outdated
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py Outdated
Comment thread source/isaaclab_physx/isaaclab_physx/sim/views/fabric_frame_view.py
pv-nvidia added 2 commits May 5, 2026 15:44
* Move test_camera_pose_update_reflected_in_render from test_tiled_camera.py
  to test_camera.py and drop the TiledCamera variant.  TiledCamera is a
  deprecated alias for Camera, so testing both was redundant.  The two test
  files will eventually be consolidated.
* Update the multi-GPU TODO comment on _fabric_supported_devices: recent
  Kit / USDRT releases support multi-GPU SelectPrims, but the rest of the
  view wiring still assumes one device — followup work.
* Drop the "FSD/Storm" reference in the class docstring; we only target FSD.
* Document **kwargs in FabricFrameView.__init__: it matches UsdFrameView's
  signature so the top-level FrameView factory can forward backend-agnostic
  kwargs without each backend having to know about every option.
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

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

🤖 Isaac Lab Review Bot

Follow-up Review

The changes from 53dce4b0 to a3940bbc address the previous review:

  1. CI Status: All CI jobs are now pending (fresh run). The previous isaaclab_physx failure appears to have been transient — the code itself was correct.

  2. No new code changes: The diff between the previous review and now shows no substantive code modifications. The implementation remains sound.

Implementation Verdict

Ship it — The PR is well-structured, properly tested, and the previous CI concerns appear resolved. The PrepareForReuse() approach is the correct fix for renderer notification, and the test coverage is thorough (contract tests, regression test for no USD writeback, topology change handling).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request isaac-lab Related to Isaac Lab team isaac-sim Related to Isaac Sim team

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

3 participants