Add opt-in async OVRTX rendering - #6484
Closed
pv-nvidia wants to merge 5 commits into
Closed
Conversation
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
6 times, most recently
from
July 13, 2026 19:26
83b23b3 to
926879d
Compare
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
from
July 13, 2026 21:58
926879d to
01afef6
Compare
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
from
July 15, 2026 15:29
2474442 to
5c0b779
Compare
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 15, 2026
pv-nvidia
commented
Jul 27, 2026
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
from
July 27, 2026 17:44
1c4d859 to
e818859
Compare
pv-nvidia
dismissed
r-schmitt’s stale review
July 27, 2026 18:37
affected files were reverted, features already on develop
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
from
July 29, 2026 09:59
100b503 to
589a873
Compare
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
from
July 29, 2026 17:36
3b04eaa to
67417cf
Compare
pv-nvidia
marked this pull request as draft
July 29, 2026 20:02
pv-nvidia
commented
Jul 30, 2026
Comment on lines
+892
to
+929
| # If self._object_newton_indices is not None, then Newton's the current physics backend | ||
|
|
||
| # A non-None self._object_newton_indices means Newton is the current physics backend. |
Contributor
Author
There was a problem hiding this comment.
This change was not needed
pv-nvidia
commented
Jul 30, 2026
Comment on lines
-2149
to
-2163
| product_path = self._render_product_paths[0] | ||
| if product_path in products and len(products[product_path].frames) > 0: | ||
| self._process_render_frame( | ||
| render_data, | ||
| products[product_path].frames[0], | ||
| render_data.warp_buffers, | ||
| ) | ||
|
|
||
| # Post-render PPISP: HDR scene-linear → LDR RGBA. Source/destination | ||
| # buffers are the same warp buffer map used by extraction. | ||
| if render_data.ppisp_pipeline is not None: | ||
| render_data.ppisp_pipeline.apply( | ||
| render_data.warp_buffers[str(RenderBufferKind.RGB_HDR)], | ||
| render_data.warp_buffers[str(RenderBufferKind.RGBA)], | ||
| ) |
Contributor
Author
There was a problem hiding this comment.
This code was deleted, where did it end up?
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
3 times, most recently
from
August 6, 2026 14:39
f3e3fce to
92d2ea0
Compare
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
3 times, most recently
from
August 7, 2026 22:50
319b01e to
ed0a259
Compare
pv-nvidia
marked this pull request as ready for review
August 8, 2026 07:59
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
from
August 9, 2026 05:01
95c55fa to
dccab4b
Compare
6 tasks
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
2 times, most recently
from
August 11, 2026 07:42
4aae62e to
49e3170
Compare
Rendering blocked the caller on every frame, so simulation and Python work could not overlap with the GPU. This adds an opt-in asynchronous path that pipelines render steps instead. Frame execution moves behind a render-strategy hierarchy so the renderer's call sites carry no sync/async branching. The synchronous strategy writes transforms straight into OVRTX and consumes each step inline; the asynchronous strategy submits the step, double-buffers transform staging, and consumes the products one frame later. Both the legacy and ovstage backends go through it. The path is off by default (async_rendering=False), so existing behavior is unchanged. The render queue depth is fixed at two, giving one frame of camera latency; per-frame latency control is left to a future Isaac Lab-side setting. The first frame after (re)initialization is waited on and consumed immediately. OVRTX zero-initializes its output buffers, so without this the first read returns a black frame while streaming and quality stabilization are still in flight. For tests, OVRTX_ASYNC_RENDERING overrides the config, per-environment pixel tolerances carry separate synchronous and asynchronous values resolved through a single helper, and the post-merge rendering subset runs the asynchronous cartpole cases.
Shorten comments and docstrings to describe the current behavior only, dropping rationale narrative, hypothetical justifications and forward-looking remarks. No functional change.
Rewrite the _resolve_render_strategy and _write_attribute_ovstage docstrings to state why an ovstage scene write must drain in-flight renders: OVRTX reads the stage's storage in place. Align the changelog fragment wording. Validate _SceneBackendOperation declarations in __set_name__ so an operation missing either implementation fails at class creation instead of raising AttributeError on first dispatch.
Replace the _SceneBackendOperation descriptor with the explicit if/else dispatch methods, restoring them unchanged from develop. The descriptor erased the signature of every dispatched call site and was unrelated to asynchronous rendering; ovstage becoming the default will remove the branches outright. Keep the pairing coverage: every operation must implement both backends, every pair must be listed, and each dispatch method must call the selected backend and no other.
pv-nvidia
force-pushed
the
pv/ovrtx-async-slot-buffers
branch
from
August 12, 2026 15:48
e9056a3 to
37fca6b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds an opt-in asynchronous render path to the OVRTX renderer, so rendering can overlap with simulation and Python work. It is off by default (
async_rendering=False), leaving existing behavior unchanged.What this adds
A single on/off switch,
OVRTXRendererCfg.async_rendering(defaultFalse):False: synchronous rendering.True: asynchronous rendering. Eachrender()submits the render and returns immediately, so rendering overlaps simulation and Python work; camera outputs arrive one frame later. The first frame after (re)initialization is consumed synchronously so the first camera read returns a valid frame instead of the zero-initialized buffer.Internally the renderer delegates frame execution to a
_RenderStrategypair:_SyncRenderStrategywrites transforms straight into OVRTX and consumes each step inline, while_AsyncRenderStrategypipelines steps and double-buffers transform staging. The async strategy is created only when async is enabled, so sync call sites carry no branching.Async works on both scene-ownership paths. Under ovstage the renderer borrows the stage's storage, so each ovstage scene write first settles any render still in flight.
Two environment variables support testing and benchmarking:
OVRTX_ASYNC_RENDERINGoverridesasync_rendering(0/false/no/offdisable, any other non-empty value enables). This is the only task-agnostic switch; a Hydra override such asenv.scene.base_camera.renderer_cfg.async_rendering=Truenames a camera that a given task may not define.OVRTX_NUM_BUFFERSsets the render queue depth: renders kept in flight before the oldest is drained (default2, values below2are clamped). Larger values overlap more simulation at the cost of extra frames of camera latency.Camera-output read ordering
Also improves camera-output throughput for synchronous rendering as well as asynchronous. OVRTX waits for render completion with a GPU-side wait on the CUDA default stream, which on Linux hits a driver GPU-context scheduling issue that runs most of the graphics work while the render-output copy waits. Camera outputs are now read without a GPU-side wait, with the calling thread waiting instead — roughly 30% higher throughput on a camera task on Linux, and slightly faster on Windows too.
Two variables select how the read is ordered against the render:
ISAAC_LAB_OVRTX_RENDER_VAR_SYNC_STREAMpicks the GPU-side barrier (0default/none,default, orwarp), andISAAC_LAB_OVRTX_RENDER_VAR_MAP_WAIT(default1) toggles the host-side wait. Selecting neither would race the render and is rejected.Correctness
The async path is covered by golden-image tests that reuse the synchronous goldens, since async output must match within the existing SSIM / pixel-difference tolerances:
test_rendering_cartpole_kitless.py::test_rendering_cartpole_kitless_asyncfor both kitless physics backends (ovphysx,newton). Per-env tolerances are declared as[sync, async]and resolved throughmax_different_pixels_percentage_for(), guarded bytest_rendering_tolerance_lookup.py.Unit tests cover the pieces that are hard to observe end to end:
test_ovrtx_scene_write_barrier.py— an ovstage scene write settles in-flight renders, and delivery targets the correct frame's buffers.test_ovrtx_scene_backend_binding.py— every scene operation resolves to the selected backend, with no unpaired implementation.test_ovrtx_strategy_selection.py,test_ovrtx_render_ordinal.py,test_ovrtx_strategy_drain_state.py,test_ovrtx_async_teardown.py.The
isaaclab_ovsuite passes (164 tests), including the clone-plan tests after the async-state refactor.Benchmarks
Measured with the RSL-RL training benchmark (
scripts/benchmarks/training.py) with training in the loop (real PPO updates, not just environment stepping) on the KukaAllegro lift camera task — a manipulation task with per-env RGB cameras, so representative of a real training workload rather than a rendering microbenchmark.FPS is RSL-RL
Perf/total_fps(whole training step, including the policy update); collection FPS is the rollout phase where rendering runs. Single runs with schema output — treat as throughput signals.Benchmark provenance:
0.3.0.312915Isaac-Lift-KukaAllegro-Camera, 4096 envs, seed 42, 200 iterationsphysics=newton_mjwarp renderer=ovrtx presets=rgb64KukaAllegro lift camera (RSL-RL, training in the loop)
End-to-end training throughput improves ~1.43x; the rollout phase, where rendering overlaps simulation, improves ~1.49x. A per-phase profile of this task shows rendering is ~63% of the iteration, so overlapping it with the remaining ~37% of non-render work is where the gain comes from.
Command (prefix with
OVRTX_ASYNC_RENDERING=1for async,OVRTX_ASYNC_RENDERING=0for sync):OVRTX_ASYNC_RENDERING=1 python scripts/benchmarks/training.py \ --rl_library rsl_rl \ --task Isaac-Lift-KukaAllegro-Camera \ --seed 42 \ --max_iterations 200 \ --benchmark_formatter schema \ --output_path ./results/kuka_<sync_or_async> \ --headless \ physics=newton_mjwarp renderer=ovrtx presets=rgb64Enabling async adds one frame of camera latency.
Type of change
Screenshots
Not applicable — performance/API change with no visual UI. Async RGB output is validated against the sync goldens by the correctness tests above.
Checklist
pre-commitchecks with./isaaclab.sh --formatsource/<pkg>/changelog.d/for every touched package (do not editCHANGELOG.rstor bumpextension.toml— CI handles that)CONTRIBUTORS.mdor my name already exists there