Skip to content

[4C/10] Route rigid rendering transforms through SDP - #7941

Merged
ooctipus merged 17 commits into
isaac-sim:developfrom
ooctipus:refactor/pr4c-sdp-transport
Sep 24, 2026
Merged

ooctipus merged 17 commits into
isaac-sim:developfrom
ooctipus:refactor/pr4c-sdp-transport

Conversation

@ooctipus

@ooctipus ooctipus commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Route rigid-body transforms from physics to renderers through SceneDataProvider (SDP). Physics publishes its native buffer and increments its version after changes. SDP binds that buffer when format and ordering match, or converts it once per requested layout and reuses the result until the next change. Readers never reset the producer's version.

What changes

  • OVRTX: converts physics poses directly into its matrix format, without first copying them into a Newton render state.
  • Newton rendering: borrows SDP's transform buffer instead of copying into a second buffer. Newton physics and rendering continue sharing their existing model/state.
  • Isaac RTX: shares one registry-owned Fabric binding with Kit, preserves authored scale, and updates the transform hierarchy on GPU. PhysX publishes its native Fabric matrices without fetching packed poses.
  • Ownership: physics refreshes native data; SDP borrows or converts arrays. One FabricBackend in isaaclab_physx owns the stage/hierarchy handles and shared transform bindings, identified by stage/device. Consumers pass SDP explicitly to updates; it is not part of backend identity. Core RenderContext has no Fabric methods or state. FabricMatrix44 contains only matrix storage.
  • Rendering updates: removes repeated renderer-driven physics refreshes. Writes made between physics steps remain visible on the next render.

For Newton → Isaac RTX, cached bindings and GPU hierarchy updates replace repeated binding setup and the CPU hierarchy fallback. This is the main runtime saving measured below.

Particle/deformable transport is outside this change. OVRTX retains its existing Newton geometry bridge.

Transform movement

Counts are SDP output-writing passes, not total SDK-internal copies. Conversion, reordering, and scale are combined in one pass; unchanged data reuses the result.

Physics Renderer Published → requested format SDP passes
Newton Newton Warp Transform → Transform 0
Newton OVRTX Transform → TransposedMatrix44d 1
Newton Isaac RTX Transform → FabricMatrix44 1
OVPhysX Newton Warp Transform → Transform 0 if ordering matches; otherwise 1
OVPhysX OVRTX Transform → TransposedMatrix44d 1
Isaac PhysX Newton Warp Transform → Transform 0 if ordering matches; otherwise 1
Isaac PhysX Isaac RTX Native Fabric → borrowed Fabric 0 with use_fabric=True

OVPhysX and OVRTX cannot run with Kit. Fabric hierarchy propagation and OVRTX's native attribute write happen after the SDP pass and are not included in these counts.

Performance

Kuka Allegro Camera, 4096 environments, 64×64 RGB, Newton MJWarp → Isaac RTX, RTX 5090, no interactive visualizer. Two warm-cache runs per revision; runtime excludes 25 warmup steps and measures 200 synchronized full environment steps, including rendering and observations.

Metric PR Develop
Warm startup 135.47 s 133.19 s
Runtime step 172.32 ms 554.49 ms
Environment frames/s 23,770 7,387

The measured step time was 68.9% lower (3.22× throughput). No startup improvement was measured. All 4096 camera images were finite and nonconstant.

Measured revisions: PR 257e54d5f and develop 53a7f1c0a, with identical dependencies. Subsequent cleanup has not been rebenchmarked.

Migration

Custom scene-data backends must initialize transforms_version=0 and increment it after native pose writes or buffer swaps. The consumer-facing get_transforms(output) API binds shared, read-only arrays, including converted outputs. Pass allow_passthrough=False for caller-owned writable or preallocated arrays; conversion writes directly into them. Single-format backends keep their existing transforms property; the base get_transforms(output_format) delegates to it. Multi-format backends may override that method and native_transform_formats.

Validation

  • Focused CPU tests and GPU 0 Newton/PhysX Fabric tests cover pointer sharing, publication versions, transform formats, ordering, authored scale, buffer reallocation, same-step writes, and resets. The existing cache regression now also checks that independent SDP readers cannot hide producer changes from one another.
  • All 11 native Newton/Fabric tests and the native PhysX Fabric test passed after moving bindings out of core. They also check one shared RTX/Kit resource and explicit Newton-to-Fabric updates without an RTX camera or Kit viewer.
  • Removed obsolete synchronization tests and duplicate mock-only checks; native and numerical regressions remain.
  • Native OVPhysX → OVRTX rendered scale, pose changes, and camera calibration passed for both legacy and ovstage APIs. Matched OVRTX timings have not been collected.

Type of change

  • Refactor and bug fixes
  • Breaking custom scene-data backend interface change, with migration above

Release backport

  • Backport to the active release branch

Checklist

  • Contribution guidelines reviewed
  • Changelog fragments and migration documentation updated
  • Retained focused tests and formatting checks passed after test cleanup
  • Full GPU CI passed for the latest revision
  • Native OVPhysX → OVRTX rendering validated

@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team labels Sep 22, 2026
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 22, 2026
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 22, 2026
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 22, 2026
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 22, 2026
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 22, 2026
@ooctipus
ooctipus force-pushed the refactor/pr4c-sdp-transport branch from 1bb98da to 257e54d Compare September 23, 2026 05:34
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 23, 2026
@ooctipus
ooctipus marked this pull request as ready for review September 23, 2026 06:47
@ooctipus
ooctipus requested a review from a team September 23, 2026 06:47
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 23, 2026
@StafaH StafaH self-assigned this Sep 23, 2026
@StafaH

StafaH commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

Thanks Octi!

Looking through it at a high level, I noticed a couple of _dirty that is in different places. This might turn into a problem of whack-a-mole with dirty flags. What if we maybe did something like:

  • Producers do backend.transforms_version += 1 after a write or pointer swap, and nothing resets it. Each consumer compares against the last version it saw.
  • Then we can remove all the _dirty and SceneDatProvider.transform_generator

Second is that for request_transforms, maybe we should set-up in a way that does all the setup once, and then in the future it is just a call.

There could be 2 ways to do it:

Functional:

  read = sdp.transform_reader(SceneDataFormat.TransposedMatrix44d, scales=scales)  # validate, allocate, pick kernel once
  transforms, version = read()  # converts at most once per version

  publish = sdp.fabric_sink(stage, device)  # replaces _prepare_fabric + FabricMatrix44
  publish()
  Wrong arguments now fail at setup instead of mid-render. The Fabric path no longer needs private fields on the provider, and
  FabricMatrix44 goes away since every caller discarded its return value.

Or slightly less functional but maybe more user friendly:

  view = sdp.transform_view(SceneDataFormat.TransposedMatrix44d, scales=scales)  # validate, allocate, pick kernel once
  transforms, version = view.read()                                              # converts at most once per version

  publisher = sdp.fabric_publisher(stage, device)  # replaces _prepare_fabric + FabricMatrix44
  publisher.publish()

"_prepared_renderer_ids",
"_prepared_num_envs",
"_last_scene_state_step",
"_last_geometry_step",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

_last_geometry_step is a bit odd of a term, reading this first time I would now know what it refers to

True if transforms are available in ``output``, False if no transforms are published
or the format conversion is unsupported.
"""
output_format = output._cls

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There is alot of usage of this output._cls, complex to read

############################
## Example

if __name__ == "__main__":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should we remove the main function here?

width=16,
data_types=["rgb"],
spawn=sim_utils.PinholeCameraCfg(),
renderer_cfg=IsaacRtxRendererCfg(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should have the test use ovrtx preferable, as that path matters more to us

Comment thread AGENTS.md Outdated
- For file-spawned fixtures that must only tune existing physics bodies, use explicit fragment
target mappings. A bare fragment or list may create a missing body and change the fixture's validity.

## Scene-data ownership

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's remove this from AGENTS.md, if such a note is required, leave it near the implementation of SDP refresh publication and agents will naturally pick up the rule when they write code requiring it.

@ooctipus

Copy link
Copy Markdown
Collaborator Author

@StafaH Agreed on producer-owned versions. Replaced the transform dirty latches and SDP generation counter with backend.transforms_version. Readers never reset it. PhysX retains separate last-read versions for packed poses and native Fabric, since either representation can be requested independently.

This fixed a concrete stale-data case: with two SDP readers, the first previously consumed the flag before the second refreshed its converted buffer. The existing regression now covers both readers. Pending FK flags remain because they represent work that still needs execution, not publication freshness.

The Fabric part has changed since your example: RenderContext now owns its bindings and hierarchy updates, while SDP only borrows or converts array storage. Moving a Fabric publisher back into SDP would undo that ownership correction.

I kept the single get_transforms consumer API for this update. Buffers and mappings are reused, and unchanged conversions now skip kernel lookup too, but this is not yet a setup-once reader factory. That proposal should replace the existing API coherently, not add a second interface alongside it.

Also merged latest develop and resolved the conflict.

Addressed the inline cleanup too: removed the embedded __main__ demo and the SDP-specific AGENTS.md section, renamed the geometry cadence field to _last_geometry_update_step, and named Warp's descriptors source_format / output_format instead of repeatedly reading _cls.

For the test comment, the cited test asserts actual Kit/Fabric matrices, so it needs Isaac RTX; OVRTX cannot run with Kit. I also ran the existing native OVPhysX → OVRTX image tests on GPU 0: both legacy and ovstage passed, checking scale, pose changes, and camera calibration. The 5 PhysX publication checks and 4 Newton/Fabric integration cases also passed, including captured writes followed by rendering without a physics step.

@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 24, 2026
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 24, 2026
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 24, 2026
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 24, 2026
@ooctipus
ooctipus merged commit 22bfa0d into isaac-sim:develop Sep 24, 2026
53 checks passed
StafaH added a commit that referenced this pull request Sep 24, 2026
…#7941, #7977, #7983, #7991, #8003) (#8002)

## Description

Backports the rendering changes and related release fixes:

- #7941 — routes rigid rendering transforms through `SceneDataProvider`
and preserves shared Fabric bindings.
- #7977 — batches due camera captures by renderer and fixes moving and
cloned camera updates. This supersedes #8001.
- #7983 — removes `CameraRenderSpec.camera_path_relative_to_env_0` and
derives and validates the OVRTX source camera path from
`camera_prim_paths`. The rendering changes were developed with this
interface, so it is required by their OVRTX tests.
- #7991 — fixes Newton's deprecated joint friction writers and the PhysX
rigid object collection `body_mask` writer signatures.
- #8003 — consolidates redundant Newton tests to shorten the Newton CI
job without changing runtime code.

#7941 required conflict resolution in the OVRTX legacy and OvStage
transform binding functions: the release branch's Newton model path
collection was replaced by SDP-published paths. #7983 was then
integrated with those SDP paths. Each added commit records its source
commit.

Custom scene-data backends must follow the `transforms_version`
publication contract described in the included migration documentation.
Direct callers of `BaseRenderer.render()` must pass a sequence, for
example `render([data])`. Callers constructing `CameraRenderSpec` must
remove the `camera_path_relative_to_env_0` argument; OVRTX now derives
it from `camera_prim_paths`.

## Validation

- Rendering and scene-data focused tests from the original backport
passed locally: 27 renderer tests and 50 scene-data / PhysX renderer
tests. OVRTX runtime cases were skipped locally because the optional
`ovrtx` module is unavailable.
- #7991: the Newton deprecated friction writer test passed, and 72 rigid
object collection mask writer cases passed. The new friction test fails
without the fix and passes with it.
- #8003: all 8 revised contact lifecycle cases passed. Kit-based Newton
asset tests remain for CI.
- `uv run isaaclab -f` passed after all additions with the changelog
base set to `release/3.0.0`, as did `git diff --check`.
- The original backport's documentation build passed with warnings
treated as errors. Full GPU and Kit CI is running on the updated PR.

## Type of change

- Rendering bug fixes and performance improvement
- Backend API bug fixes and breaking renderer / scene-data interface
changes with migration guidance
- Newton test consolidation
- Documentation and changelog fragments for affected source packages

## Release backport

This PR targets `release/3.0.0`; no further backport is needed.

## Checklist

- [x] Contribution guidance reviewed
- [x] Focused local tests and formatting checks passed
- [x] Public documentation and package changelog fragments included
- [ ] Full GPU and Kit CI passed

---------

Co-authored-by: ooctipus <zhengyuz@nvidia.com>
Co-authored-by: Piotr Barejko <pbarejko@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants