Skip to content

[Warp] Part 3/6: Capture Warp stages per term without warm-up and step like the stable environments - #6607

Draft
hujc7 wants to merge 51 commits into
isaac-sim:mainfrom
hujc7:jichuanh/warp-frontend-cleanup
Draft

hujc7 wants to merge 51 commits into
isaac-sim:mainfrom
hujc7:jichuanh/warp-frontend-cleanup

Conversation

@hujc7

@hujc7 hujc7 commented Jul 19, 2026 •

Copy link
Copy Markdown
Collaborator

Review Map

PR Status Depends on Exact changes
#6646 Part 1/6: mask-correct partial resets (draft) — —
#8783 Part 2/6: shared Warp RNG state (draft) #6646 link
📌 #6607 Part 3/6: per-term capture, stable stepping parity (draft) #8783 link
#8228 Part 4/6: Warp commands, Rough tasks, live term changes (draft) #6607 link
#6582 Part 5/6: Shadow Warp twin, Allegro twin fixes (draft) #6607 link
#7012 Part 6/6: --video on the Warp frontend (draft) — —

Summary

Warp environments step like the stable ones (physics-owned decimation, extras["final_obs"], per-step extras["log"] copies) and record their stages from the first call without an eager warm-up, bitwise equal to eager.
Capture is decided per term, so one term that cannot be recorded no longer forces its whole manager stage eager; Go2 Flat steps in 6.96 ms instead of 7.53 ms with Part 1 (8gpu L40, 4096 envs).

Description

Update (2026-10-22): now stacked on #8783 (the shared Warp RNG state, split out of #6646) and merged main 8c9b995cb95; this PR's own diff is unchanged.

Update (2026-10-20): merged #6646 and main 2dbb6146d75 (the default branch, renamed from develop; "main" below means main without this PR, measured at aa9bafef8a0). The Warp environments reach the physics backend through sim.backend_manager, since #8711 deprecated sim.physics_manager. After the merge, the experimental utils, managers and MDP parity tests (85), the frontend, scene, capture, decimation, final-obs, log and reset tests pass; Cartpole, Cartpole-Direct, Ant-Direct, Allegro-Direct and Go2 Flat Warp runs advance 16/16 RNG states, and every Cartpole and Go2 stage records one graph.

Update (2026-10-02): merged #6646 and develop 772358ac3b9, plus one review-round commit (ee9e8adbb9d): CapturedStage replaces WarpGraphCache, direct environments decide resets on the GPU, process_action takes torch actions, and a class term's reset is judged by its own annotation.

1. Changes

  1. Capture: CapturedStage, @captured and eager() replace WarpGraphCache. A stage records on its first call without a warm-up, as main's physics capture does (Capture Newton CUDA graphs without advancing simulation #8058), replays afterwards, and records again after the simulation is reset or stopped (without this: CUDA error 700 after a rebind). Recordings pause the garbage collector and collect only the youngest generation afterwards. ISAACLAB_SYNC_DEBUG=1 raises on a hidden host sync.
  2. Per-term capture: a @WarpCapturable(False) term runs eagerly at its place in the recording; @WarpCapturable(lambda params: ...) decides per configured instance. A class annotation covers the term's call; its reset is recorded unless the reset method is annotated.
  3. Stepping like stable:
    • The environments call the managers in the stable order; ActionManager.process_action takes a torch action.
    • Manager-based environments reset by mask and derive indices once per reset, only for command, curriculum or recorder terms.
    • DirectRLEnvWarp decides on the GPU whether any environment must reset (a conditional graph node, CUDA 12.4+), so a step no longer synchronizes with the host.
  4. Stateful event terms as classes (push_by_setting_velocity, apply_external_force_torque, reset_root_state_uniform, randomize_rigid_body_com): buffers allocated at creation, ranges read on every call. Fixes main's COM offsets accumulating per call and zero-range wrench events clearing permanent wrenches. An interval range replaced through EventManager.set_term_cfg now applies; main kept the old range.
  5. Stable parity (fixes on main):
    • Physics-owned decimation: main steps physics and updates the scene 4 times per Go2 environment step, so contact history, air times, undesired_contacts and base_contact differ from stable.
    • extras["final_obs"] and Same-Step autoreset metadata: main ignores compute_final_obs, which the torchrl entry point sets.
    • extras["log"] copies: main returns views, so rsl_rl logs the last reset's value for every step of an iteration.
  6. Breaking (experimental only):
    • Removed ManagerCallSwitch, ManagerCallMode, MANAGER_CALL_CONFIG, WarpGraphCache, ManagerBasedRLEnvWarp.step_warp_termination_compute and DirectRLEnvWarp.step_warp_action; direct tasks decorate their methods with @captured to keep them recorded.
    • ActionManager.process_action takes a torch tensor; SceneEntityCfg.joint_mask is renamed joint_mask_wp.
    • The Warp environments are still built from the stable task configurations (WarpFrontend.build_env swaps in the Warp MDP twins), so removing the switch drops no stable-configuration support.

2. Evidence

  • Validation at 5ad9281530f (desk RTX PRO 6000): the experimental utils, managers, MDP, frontend, configuration-conversion, scene, capture, decimation, final_obs, log and reset suites pass. The capture tests compare eager and captured runs bitwise, including a simulation rebind mid-run. Cartpole, Cartpole-Direct, Ant-Direct, Allegro-Direct and Go2 Flat each step 300 to 1000 times; on Cartpole and Go2 Flat every manager stage records one graph.

  • Step time (8gpu L40, 4096 envs, mean of 3 runs per arm, rotated across GPUs; measured on this PR before the last review fixes, which only change the reset path):

    Task [Warp] Part 1/6: Reset only the masked environments and fix manager-based Warp environment construction #6646 (ms) This PR (ms)
    Isaac-Cartpole 1.058 1.039
    Isaac-Cartpole-Direct 0.528 0.539
    Isaac-Ant 1.938 1.922
    Isaac-Velocity-Flat-UnitreeGo2 7.526 6.956
  • Direct reset decision: resetting unconditionally every step is not slower (Cartpole-Direct 0.531 vs 0.538 ms), but it changes logged metrics on steps where nothing reset (Ant's Metrics/success_rate would read 0), so resets stay conditional as in stable.

  • Decimation, Go2 Flat, 200 steps against the stable environment (earlier tip; the decimation tests pass at this tip): contact history, air times, undesired_contacts, base_contact and physics state are bitwise equal, feet_air_time within 3e-8 (reduction order).

3. Out of scope / follow-ups

  • Direct Warp tasks cache .warp handles that go stale after an explicit hard sim.reset(); training never calls it.
  • Stable-manager features that no supported Warp task uses still differ on the Warp managers: observation delay, runtime scale/clip edits, nested term-config resolution, recorder obs_buf, the GUI reset button and render_enabled.
  • Faster manager data layouts (tiled reward, termination and command resets; an unrolled reward step; one observation post-processing launch): measured on desk, planned as a separate PR near the end of the series.
  • OvPhysX on the Warp frontend ([WARP] Cleanup Part 4: Open the warp frontend to the OVPhysX backend #6580) is parked: lazily refreshed OvPhysX data is not refreshed inside recorded stages.
  • Merging the stable and Warp managers into one implementation: proposal only, not part of this chain.

4. Merge note

#7012 changes the same lines of direct_rl_env_warp.py and manager_based_env_warp.py (video recorder hooks). Whichever of the two merges second keeps both additions.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (existing functionality will not work without user modification)

Release backport

  • Backport this pull request to the active release branch after it merges into main

Screenshots

Not applicable.

Checklist

Docker and GPU tests run on demand. Push the commits you want tested, then
comment run-ci on the pull request.

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with uv run isaaclab --format
  • I have made corresponding changes to the documentation (API reference here; the capture guide is in Part 3)
  • My changes generate no new warnings
  • I have validated the changed behavior with focused coverage and applied the test-audit criteria to any test changes
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package (do not edit CHANGELOG.rst or bump package versions — CI handles that)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Jul 19, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 20, 2026
@hujc7 hujc7 changed the title Make the Warp frontend mask-first [WARP] Cleanup Part 2: Make the Warp frontend mask-first Jul 21, 2026
@hujc7
hujc7 force-pushed the jichuanh/warp-frontend-cleanup branch from c971364 to f68d03f Compare July 23, 2026 23:19
kellyguo11 added a commit that referenced this pull request Jul 24, 2026
…asks (#5504)

## Review Map

- A stacked PR’s page shows the cumulative diff of its dependency chain;
the "Exact changes" link pins that PR’s own commit range.
- SHA links can go stale after a branch update; the copy on #5504 is
refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| 📌 #5504 Part 1: frontend bridge (stable ids on the warp runtime) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/5504?label=)
| — | — |
| #6607 Part 2: mask-first frontend (draft) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6607?label=)
| #5504 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6607/changes/00ae695ac63e67ca678b91a837d3737529d2ec91..f68d03f40854b31a36063c5068f2933d32ea5db9)
|
| #6646 Part 3: scene reset mask-native + capture-ready (draft, base
rewritten — pending rebase onto #6607) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6646?label=)
| #6607 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6646/changes/4360622bde446c52c3fc85924639f9d1119d6e95..6d49e32f11e15894a4a0e49161a356ec79679ac6)
|
| #6580 Part 4: OVPhysX backend (draft) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6580?label=)
| #5504 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6580/changes/fc37fa65ad95d1ac6e3f32e721329ef715899d37..716cef20979ca6c578a6e595812291c7b1a282fc)
|
| #6611 Part 5: persistent-launch speedups (draft, absorbs #6551) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6611?label=)
| #6646 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6611/changes/6d49e32f11e15894a4a0e49161a356ec79679ac6..6e3da794215da03745a9bc8d35790e22262b099a)
|

## 1. Summary

- `--frontend {torch,warp}` on the shared RL CLI (train **and play**)
runs **stable** task ids on the warp runtime — no duplicated configs, no
parallel warp task registrations at all (end state pinned by test). The
`rlinf` integration constructs environments inside the external
framework and is not frontend-routable (known limitation).
- **1.24–1.70× faster end-to-end** than torch on the same tasks,
identical Newton physics (§3.1).
- Manager-based: `WarpFrontend` adapts the stable cfg in place; MDP
twins resolve by name on the mirrored experimental package tree —
deterministic, registration-free, missing twins reported in one
aggregated failure.
- Direct: the stable registration declares its warp class via
`warp_entry_point`; only the env class swaps, the cfg is shared.
- Stable observation-noise cfgs (constant/uniform/gaussian) swap to
warp-native twins during adaptation; cfgs without a twin (class-based
noise models, customized funcs, tensor-valued params) are a hard error
instead of silently dropping noise. The warp observation manager rejects
non-warp noise cfgs and plumbs the shared per-env RNG state.
- Plus: warp adapters for the material/mass randomization startup
events; `isaaclab_tasks_experimental` mirrors the stable `core/<task>`
layout; `Metrics/success_rate` restored under warp.

## 2. Migration map

| Retired | Replacement |
|---|---|
| `Isaac-{Cartpole,Humanoid,Ant}-Warp-v0`, `Isaac-Reach-Franka-Warp-v0`
(+`-Play`) | stable id + `--frontend warp presets=newton_mjwarp` |
| `Isaac-Velocity-Flat-<Robot>-Warp-v0` (+`-Play`), all robots | stable
id + `--frontend warp presets=newton_mjwarp` |
| `Isaac-{Cartpole,Ant,Humanoid}-Direct-Warp-v0`,
`Isaac-Reorient-Cube-Allegro-Direct-Warp-v0` | stable id + `--frontend
warp presets=newton_mjwarp` (via `warp_entry_point`) |

## 3. Test plan

- [x] Merged current `develop`; `./isaaclab.sh -f` clean on all files.
- [x] Re-merged develop (task-id catalog update #6606, entrypoints
refactor); environments catalog regenerated; conversion sweep + warp
smokes (`Isaac-Velocity-Flat-UnitreeGo2`, `Isaac-Cartpole-Direct`)
re-run green; pre-commit clean on all files.
- [x] 142 focused tests: frontend units, cfg-conversion sweep over every
covered stable id, no-warp-registrations end-state pin, shared-CLI
tests.
- [x] 5-iteration RSL-RL trainings exit clean (`Training time:` present,
no traceback): `Isaac-Cartpole` (torch); `Isaac-Cartpole`,
`Isaac-Humanoid`, `Isaac-Cartpole-Direct`, `Isaac-Ant-Direct`,
`Isaac-Velocity-Flat-AnymalD`, `Isaac-Velocity-Flat-H1` (warp;
randomization events active); `Isaac-Reorient-Cube-Allegro-Direct`
(warp). `Metrics/success_rate` reported under warp.

### 3.1 Frontend A/B benchmark

Same stable task id and cfg on both sides, `presets=newton_mjwarp` on
**both** (identical Newton physics — only `--frontend` differs); rsl_rl,
4096 envs, 300 iterations, headless, one L40 per run, single run per
cell. Metric: rsl_rl `Training time:` — learn-loop wall-clock (env
stepping + PPO update; warp includes its one-time CUDA-graph capture).
PPO-update cost is common to both, so the env-pipeline gain exceeds the
end-to-end ratio.

| Task | torch | warp | end-to-end | final reward (torch / warp) |
|---|---|---|---|---|
| `Isaac-Cartpole` | 58.2 s | 39.7 s | 1.46× | 4.95 / 4.95 |
| `Isaac-Humanoid` | 162.0 s | 110.5 s | 1.47× | 149.1 / 179.8 |
| `Isaac-Ant` | 109.8 s | 64.5 s | 1.70× | 82.1 / 77.1 |
| `Isaac-Velocity-Flat-AnymalD` | 162.4 s | 130.7 s | 1.24× | 20.3 /
21.4 |

## 4. Out of scope / follow-ups

- No video-recorder plumbing on warp envs; rough terrain blocked on Warp
`TerrainImporter` APIs; no twins for IK/OSC actions, `height_scan`, or
Digit/Spot-specific terms.
- OVPhysX support for the warp frontend prepared as a follow-up PR
(physics gate widening + backend data-parity test).
- Candidate refactor: fold the ~300 lines of converged plumbing shared
by `DirectRLEnvWarp` and stable `DirectRLEnv` into a common base.

---------

Co-authored-by: Kelly Guo <kellyguo123@hotmail.com>
matthewtrepte pushed a commit to matthewtrepte/IsaacLab that referenced this pull request Aug 4, 2026
…asks (isaac-sim#5504)

## Review Map

- A stacked PR’s page shows the cumulative diff of its dependency chain;
the "Exact changes" link pins that PR’s own commit range.
- SHA links can go stale after a branch update; the copy on isaac-sim#5504 is
refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| 📌 isaac-sim#5504 Part 1: frontend bridge (stable ids on the warp runtime) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/5504?label=)
| — | — |
| isaac-sim#6607 Part 2: mask-first frontend (draft) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6607?label=)
| isaac-sim#5504 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6607/changes/00ae695ac63e67ca678b91a837d3737529d2ec91..f68d03f40854b31a36063c5068f2933d32ea5db9)
|
| isaac-sim#6646 Part 3: scene reset mask-native + capture-ready (draft, base
rewritten — pending rebase onto isaac-sim#6607) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6646?label=)
| isaac-sim#6607 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6646/changes/4360622bde446c52c3fc85924639f9d1119d6e95..6d49e32f11e15894a4a0e49161a356ec79679ac6)
|
| isaac-sim#6580 Part 4: OVPhysX backend (draft) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6580?label=)
| isaac-sim#5504 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6580/changes/fc37fa65ad95d1ac6e3f32e721329ef715899d37..716cef20979ca6c578a6e595812291c7b1a282fc)
|
| isaac-sim#6611 Part 5: persistent-launch speedups (draft, absorbs isaac-sim#6551) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6611?label=)
| isaac-sim#6646 |
[link](https://github.com/isaac-sim/IsaacLab/pull/6611/changes/6d49e32f11e15894a4a0e49161a356ec79679ac6..6e3da794215da03745a9bc8d35790e22262b099a)
|

## 1. Summary

- `--frontend {torch,warp}` on the shared RL CLI (train **and play**)
runs **stable** task ids on the warp runtime — no duplicated configs, no
parallel warp task registrations at all (end state pinned by test). The
`rlinf` integration constructs environments inside the external
framework and is not frontend-routable (known limitation).
- **1.24–1.70× faster end-to-end** than torch on the same tasks,
identical Newton physics (§3.1).
- Manager-based: `WarpFrontend` adapts the stable cfg in place; MDP
twins resolve by name on the mirrored experimental package tree —
deterministic, registration-free, missing twins reported in one
aggregated failure.
- Direct: the stable registration declares its warp class via
`warp_entry_point`; only the env class swaps, the cfg is shared.
- Stable observation-noise cfgs (constant/uniform/gaussian) swap to
warp-native twins during adaptation; cfgs without a twin (class-based
noise models, customized funcs, tensor-valued params) are a hard error
instead of silently dropping noise. The warp observation manager rejects
non-warp noise cfgs and plumbs the shared per-env RNG state.
- Plus: warp adapters for the material/mass randomization startup
events; `isaaclab_tasks_experimental` mirrors the stable `core/<task>`
layout; `Metrics/success_rate` restored under warp.

## 2. Migration map

| Retired | Replacement |
|---|---|
| `Isaac-{Cartpole,Humanoid,Ant}-Warp-v0`, `Isaac-Reach-Franka-Warp-v0`
(+`-Play`) | stable id + `--frontend warp presets=newton_mjwarp` |
| `Isaac-Velocity-Flat-<Robot>-Warp-v0` (+`-Play`), all robots | stable
id + `--frontend warp presets=newton_mjwarp` |
| `Isaac-{Cartpole,Ant,Humanoid}-Direct-Warp-v0`,
`Isaac-Reorient-Cube-Allegro-Direct-Warp-v0` | stable id + `--frontend
warp presets=newton_mjwarp` (via `warp_entry_point`) |

## 3. Test plan

- [x] Merged current `develop`; `./isaaclab.sh -f` clean on all files.
- [x] Re-merged develop (task-id catalog update isaac-sim#6606, entrypoints
refactor); environments catalog regenerated; conversion sweep + warp
smokes (`Isaac-Velocity-Flat-UnitreeGo2`, `Isaac-Cartpole-Direct`)
re-run green; pre-commit clean on all files.
- [x] 142 focused tests: frontend units, cfg-conversion sweep over every
covered stable id, no-warp-registrations end-state pin, shared-CLI
tests.
- [x] 5-iteration RSL-RL trainings exit clean (`Training time:` present,
no traceback): `Isaac-Cartpole` (torch); `Isaac-Cartpole`,
`Isaac-Humanoid`, `Isaac-Cartpole-Direct`, `Isaac-Ant-Direct`,
`Isaac-Velocity-Flat-AnymalD`, `Isaac-Velocity-Flat-H1` (warp;
randomization events active); `Isaac-Reorient-Cube-Allegro-Direct`
(warp). `Metrics/success_rate` reported under warp.

### 3.1 Frontend A/B benchmark

Same stable task id and cfg on both sides, `presets=newton_mjwarp` on
**both** (identical Newton physics — only `--frontend` differs); rsl_rl,
4096 envs, 300 iterations, headless, one L40 per run, single run per
cell. Metric: rsl_rl `Training time:` — learn-loop wall-clock (env
stepping + PPO update; warp includes its one-time CUDA-graph capture).
PPO-update cost is common to both, so the env-pipeline gain exceeds the
end-to-end ratio.

| Task | torch | warp | end-to-end | final reward (torch / warp) |
|---|---|---|---|---|
| `Isaac-Cartpole` | 58.2 s | 39.7 s | 1.46× | 4.95 / 4.95 |
| `Isaac-Humanoid` | 162.0 s | 110.5 s | 1.47× | 149.1 / 179.8 |
| `Isaac-Ant` | 109.8 s | 64.5 s | 1.70× | 82.1 / 77.1 |
| `Isaac-Velocity-Flat-AnymalD` | 162.4 s | 130.7 s | 1.24× | 20.3 /
21.4 |

## 4. Out of scope / follow-ups

- No video-recorder plumbing on warp envs; rough terrain blocked on Warp
`TerrainImporter` APIs; no twins for IK/OSC actions, `height_scan`, or
Digit/Spot-specific terms.
- OVPhysX support for the warp frontend prepared as a follow-up PR
(physics gate widening + backend data-parity test).
- Candidate refactor: fold the ~300 lines of converged plumbing shared
by `DirectRLEnvWarp` and stable `DirectRLEnv` into a common base.

---------

Co-authored-by: Kelly Guo <kellyguo123@hotmail.com>
A mask-only Articulation.reset called ActuatorCollection.reset(None), which
cleared delay buffers, network history, and Newton-native actuator state for
every environment. Newton rigid objects and collections dropped the mask
before resetting their wrench composers, clearing every environment's
persistent wrench.

ActuatorCollection.reset now takes env_mask. Isaac Lab actuator models still
reset by index, so the collection converts the mask to indices once for all
groups, and skips the conversion when no group carries reset state. Native
actuator state resets from the mask through a new
ActuatorControl.reset_native_actuators_mask hook; Newton and OVPhysX pass the
mask to the Newton actuator adapter, and the base default converts to indices
so backends that only implement the index hook stay correct.
InteractiveSceneWarp.reset passed env_ids=None to deformable objects, surface
grippers, and sensors on a masked reset, so every environment's sensor state
was cleared on each partial reset, and it never reset cable objects.

Forward the mask to every entity family in the stable scene's order. Surface
grippers use their reset_mask method. Cable objects take env_mask like the
other scene assets, so the scene does not convert the mask for a reset that
holds no state.
RigidObjectCollection.write_body_*_to_sim_mask converted masks to indices
with torch.nonzero before delegating to the index writers, so the mask
writers synchronized the host and could not be captured in a CUDA graph,
although their docstrings name them as the graph-capable path. They now
launch masked kernels over the full environment-body grid, and body_ids
selections resolve to a mask through a preallocated scratch buffer.

BaseRayCaster.reset compacted a mask with nonzero before resampling drift.
A masked reset now resamples every environment and keeps the new values
where the mask is set; index and slice selections are unchanged.
isaac-sim#8079 added ObservationGroupCfg.history_order and taught the stable
observation manager to skip it as a group setting. The Warp manager's skip
list was not updated, so it parsed the field as a term and raised a
TypeError for every observation group, and no manager-based Warp
environment could be constructed.

Skip history_order like the other group settings. The Warp manager raises
NotImplementedError for any term with history, and history_order only
takes effect with history, so a time-ordered group cannot be silently
reordered wrong.
The fixed-tendon set_*_mask methods and
write_fixed_tendon_properties_to_sim_mask converted masks to indices with
torch.nonzero and delegated to the index writers, so they synchronized the
host and could not be captured in a CUDA graph.

Write the masked cells in-kernel instead: scalar and full data go into the
staging buffers through masked kernels, and the property writer copies the
masked cells of each staging buffer into its simulation binding. The mask
compaction helpers have no remaining callers and are removed.
A masked Articulation.reset on the Newton-native actuator path allocated a
per-DOF mask for every actuator on each call, and a masked ray-caster
reset sampled drift with torch ops and uploaded its ranges, so neither
could run inside a CUDA graph captured on Warp's stream.

NewtonActuatorAdapter preallocates its per-DOF reset masks. BaseRayCaster
resamples masked drift in a Warp kernel from per-environment random states
seeded from torch's global generator at initialization, with the ranges
passed as launch arguments; index and slice resets keep the torch path.
The Newton fixed-tendon position-target setters raised a host-side dirty
flag, and write_data_to_sim scattered the buffered targets into MuJoCo's
controls only while it was set. A setter recorded in a CUDA graph raised
the flag once, at capture time, so later replays updated the target buffer
on the device but never reached the solver.

Write the buffered targets on every step whenever the articulation has
tendon actuators, and drop the flag from the Newton setters. The write
costs about 60 us per call on Shadow Hand; gating it on a device-side flag
would need Newton's control-array mapping re-implemented in a kernel.
Replace ManagerCallSwitch with an environment-owned WarpGraphCache that
follows the Newton core capture model: a stage is recorded through
NewtonQueries.capture_graph with no eager warm-up, so the first
execution is the launch of the new graph; recording starts at the first
step; graphs are keyed by the pointers and scalar values of the stage
arguments; and every graph is dropped when the physics backend rebinds
its buffers or stops, so the next step records against the new buffers.

Managers with a non-capturable term keep their stages eager through
register_capturability. ISAACLAB_WARP_CAPTURE=0 runs every stage
eagerly and ISAACLAB_SYNC_DEBUG=1 traps hidden host synchronizations in
eager stages. The direct environment uses the same cache in place of
capture_or_replay.
The manager-based Warp environments now reset through one mask-first
pipeline: every reset selection is copied into an environment-owned mask
that the recorded reset stages read, the scene and the Warp managers
reset from that mask, and the episode-length buffer is cleared by a
masked kernel. The mask is compacted to environment indices once per
reset, and only when a stable command, curriculum or recorder manager has
active terms. ManagerBasedEnvWarp.reset accepts env_mask.

Each step makes one host check to decide whether any environment
terminated: the index compaction when a manager needs indices, otherwise
reset_buf.any(). DirectRLEnvWarp moves its reset out of the end-of-step
graph into its own stage behind the same predicate.

A static gate pins the sanctioned host synchronizations of the mask-first
path, which also removes the device read from CircularBuffer.max_length.
The Episode_Termination metric keeps averaging over every environment,
as the stable manager does.
push_by_setting_velocity, apply_external_force_torque,
reset_root_state_uniform and randomize_rigid_body_com kept scratch
arrays and parsed ranges as attributes of the module-level function. The
first call allocated them, which inside a recorded stage becomes
graph-owned memory; the parsed ranges froze the first configuration; and
the state was shared by every environment in the process.

They are now ManagerTermBase classes that allocate in __init__ and read
their ranges on every call. randomize_rigid_body_com offsets the center of
mass it finds on its first call instead of accumulating, and
apply_external_force_torque with zero ranges leaves the permanent wrench
composer untouched.

The material and mass adapters reject modes other than startup and are
marked non-capturable. Startup terms no longer keep the event stages
eager, since they never run inside one, and set_term_cfg re-resolves the
term and drops the recorded event stages.
A manager with one non-capturable term used to run every stage eagerly.
Managers now describe each stage as ordered steps, one per term plus
their own setup and finalize kernels, and WarpGraphCache.call_steps
records each run of consecutive capturable steps into one graph while
the terms marked @WarpCapturable(False) run eagerly in place.

Reward and termination terms write their own output columns and the
finalize kernel combines the columns in a fixed order, so these stages
evaluate the capturable terms first and need at most one eager group.
Observation noise and events draw from the shared per-environment random
state, and action terms are applied in order, so those stages keep the
configured term order and split into contiguous runs.

Observation terms with history run as eager steps instead of raising
inside capture. Replacing a reward term rebuilds its steps and drops the
recorded reward stages.
A term can be capture-safe for one configuration and not another: a
reward that reads a ray-caster refreshes the sensor on the host and
launches its query graph, which cannot run inside a recorded stage,
while the same reward without a sensor can.

WarpCapturable accepts a predicate over the term's parameters, and its
guard raises only for the parameters the predicate rejects. The Warp
managers resolve capturability with each term's parameters, and a class
term may set _warp_capturable in __init__ to decide per instance. The
sync gate's opt-out inventory also lists predicate annotations.
Stable environments tell the physics backend their decimation and, when the
backend runs the whole decimation loop, apply actions, step the simulation and
update the scene once per environment step. The Warp environments still looped
once per physics step, so contact sensors sampled four times as often on Go2
and the contact history, air times and the rewards and terminations reading
them differed from the stable environment with the same configuration.

Mirror the stable loop in the manager-based and direct Warp environments. The
per-physics-step loop remains for backends that do not run the decimation loop.
The stable environments honor compute_final_obs: a step that resets
environments stores the observations from before the reset in
extras["final_obs"] and declares Same-Step autoreset in the metadata. The
Warp environments ignored the flag, so torchrl, which sets it, bootstrapped
time-outs from the post-reset observation.

Compute the observations before the reset stage and keep a copy, because the
reset overwrites the persistent observation buffers. Declare Same-Step
autoreset in both Warp environment classes.
Warp managers and tasks log persistent buffers that later steps overwrite.
Loggers such as the rsl_rl logger keep extras["log"] of every step and average
it at the end of an iteration, so every entry showed the latest value. The
stable environments log fresh tensors.

The manager-based environment copies the tensor values when it builds the
reset log. The direct environment keeps the log the task writes and returns a
copy of it from every step, so task code that is recorded into a CUDA graph
keeps refreshing its own buffers.
ManagerBasedEnvWarp built its reset log from the same persistent manager
buffers as the RL environment, so a logged value changed with the next reset.
Copy the tensor values like the RL environment does.
@hujc7

hujc7 commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@github-actions github-actions Bot added asset New asset feature or request isaac-sim Related to Isaac Sim team isaac-mimic Related to Isaac Mimic team infrastructure labels Oct 2, 2026
@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 Oct 2, 2026
@hujc7

hujc7 commented Oct 4, 2026

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 Oct 4, 2026
hujc7 added 5 commits October 20, 2026 09:50
…-mask-native

# Conflicts:
#	docs/source/concepts/warp_environment_migration.rst
#	source/isaaclab_newton/isaaclab_newton/assets/articulation/actuator_control.py
#	source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation.py
#	source/isaaclab_newton/test/assets/test_articulation.py
#	source/isaaclab_newton/test/assets/test_newton_actuators_newton.py
#	source/isaaclab_newton/test/assets/test_rigid_object.py
#	source/isaaclab_newton/test/sensors/test_newton_raycast_sensor.py
@hujc7

hujc7 commented Oct 20, 2026

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 Oct 20, 2026
hujc7 added 4 commits October 22, 2026 00:10
Revert 6ac6061 and 9328d98: the process-wide WarpRng state moves to its own pull request stacked on this one. The ray caster, Warp environments, MDP terms, managers, noise models and Warp tasks keep their own RNG arrays here, as on main.
Environments initialize WarpRng once at construction and configure_seed reseeds it in place. The ray caster, experimental managers, events, noise models and Warp tasks read WarpRng.state instead of keeping their own copies; rng_state_wp is removed.

Re-applies 6ac6061 and 9328d98, split out of the masked-reset pull request.
@hujc7 hujc7 changed the title [Warp] Part 2/5: Capture Warp stages per term without warm-up and step like the stable environments [Warp] Part 3/6: Capture Warp stages per term without warm-up and step like the stable environments Oct 22, 2026
@hujc7

hujc7 commented Oct 22, 2026

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 Oct 22, 2026

This branch has not been deployed

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

Labels

asset New asset feature or request documentation Improvements or additions to documentation infrastructure isaac-lab Related to Isaac Lab team isaac-mimic Related to Isaac Mimic team isaac-sim Related to Isaac Sim team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant