Skip to content

Draft: Apply PPISP in Camera Wrapper Across Renderers#5499

Draft
moennen wants to merge 5 commits intoisaac-sim:developfrom
moennen:nicolasm/ppisp-renderer-simple-integration
Draft

Draft: Apply PPISP in Camera Wrapper Across Renderers#5499
moennen wants to merge 5 commits intoisaac-sim:developfrom
moennen:nicolasm/ppisp-renderer-simple-integration

Conversation

@moennen
Copy link
Copy Markdown

@moennen moennen commented May 5, 2026

Description

Adds camera PPISP support through CameraCfg.ppisp and applies PPISP centrally in the IsaacLab camera wrapper using a Warp kernel.
This keeps PPISP application consistent across Isaac RTX, OVRTX, and Newton by requesting rgb_hdr / HdrColor from the renderer, applying PPISP before LDR conversion, and writing the final rgb / rgba camera outputs.
This also adds rgb_hdr renderer output plumbing for Isaac RTX, OVRTX, and Newton.
PPISP USD shader/RenderProduct parsing utilities are kept for compatibility with exported PPISP stages.

Motivation: PPISP should be renderer-independent from the IsaacLab camera API, and should run before LDR conversion for physically plausible exposure/color processing.

Fixes #TBD

Dependencies

No new runtime dependencies. Uses existing IsaacLab dependencies: Warp, Torch, USD, and renderer-specific backends.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Screenshots

Not applicable.

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

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label May 5, 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 adds PPISP (Physically Plausible Image Signal Processing) post-processing support across all three camera renderers (Isaac RTX, OVRTX, Newton Warp). It introduces a shared Warp kernel for PPISP application at the camera wrapper level, adds rgb_hdr output plumbing for HDR color capture, and bundles SPG shader assets for USD-based PPISP graphs. The core implementation is sound, but there are several issues with the Warp kernel math, test isolation, and missing synchronization.

Architecture Impact

  • Cross-module: CameraCfg.ppisp flows through Camera._check_supported_data_types() → renderer's set_outputs()_apply_ppisp_if_needed(). All three renderers (IsaacRtxRenderer, OVRTXRenderer, NewtonWarpRenderer) are updated to support RGB_HDR.
  • New public API: PPISPCfg is exported from isaaclab.renderers.__init__.pyi.
  • Bundled assets: SPG shader files in ppisp_spg/ are included via setup.py package_data.
  • Newton compatibility layer: Defensive accessors (_newton_sensor_render_config, _newton_sensor_utils) added to support multiple Newton API versions.

Implementation Verdict

Minor fixes needed — The core design is correct, but there are issues with missing GPU synchronization, vignetting not being applied in the Warp kernel, and test determinism concerns.

Test Coverage

Two new test files added:

  • test_ppisp.py: Tests USD/SPG authoring helpers (shader import, render product parsing, SPG asset bundling) — good coverage of USD utilities
  • test_ppisp_warp.py: Tests Warp kernel exposure effect and camera wrapper integration — minimal coverage, missing vignetting/color correction tests

Missing: No regression tests for the Newton API compatibility changes. No integration tests verifying end-to-end PPISP with actual rendering.

CI Status

Only labeler ran successfully. Full CI suite results not available.

Findings

🔴 Critical: ppisp_warp.py:140-146 — Missing GPU synchronization after Warp kernel launch
The apply_ppisp_to_rgba function launches a Warp kernel but does not synchronize before returning. When the caller immediately reads out_rgba, they may get stale data since the kernel runs asynchronously.

def apply_ppisp_to_rgba(hdr_color: torch.Tensor, out_rgba: torch.Tensor, cfg: PPISPCfg) -> None:
    # ... kernel launch ...
    wp.launch(...)
    # Missing: wp.synchronize() or equivalent

Fix: Add wp.synchronize_device(str(out_rgba.device)) or use wp.synchronize() after the launch.

🔴 Critical: ppisp_warp.py:117-130 — Warp kernel ignores vignetting parameters entirely
The _apply_ppisp_kernel kernel signature accepts only exposure and color/CRF parameters but the SPG shader (ppisp_usd_spg.slang) applies vignetting per-channel. The Warp kernel completely skips vignetting, meaning results will differ between USD SPG execution and IsaacLab-side PPISP:

# Kernel only applies: exposure → color correction → CRF
# Missing: vignetting step that exists in Slang shader lines 166-175

Fix: Either add vignetting to the Warp kernel or document this as an intentional simplification.

🟡 Warning: camera.py:538-542 — Potential race condition with _renderer_output_data aliasing
When PPISP is disabled, _renderer_output_data is set to dict(self._data.output), creating a shallow copy. Both the renderer and PPISP code may reference the same underlying tensors. If a future renderer mutates buffers in-place during async operations, this could cause data corruption.

self._renderer_output_data = dict(self._data.output)  # shallow copy

Fix: This is currently safe but fragile. Consider documenting the ownership contract.

🟡 Warning: newton_warp_renderer.py:64-73 — _newton_clear_data falls back to private module import
The fallback imports from newton._src.sensors.warp_raytrace, which is a private API path:

from newton._src.sensors.warp_raytrace import ClearData as clear_data_cls

This may break silently on future Newton versions. Consider adding a try/except with a meaningful error message.

🟡 Warning: test_ppisp_warp.py:32-57 — Test uses SimpleNamespace to mock Camera, bypassing real initialization
The test creates a mock Camera with SimpleNamespace, which doesn't verify that Camera._apply_ppisp_if_needed is actually bound correctly as a method or that the real camera initialization properly sets up PPISP:

camera = SimpleNamespace(
    cfg=SimpleNamespace(ppisp=ppisp_cfg),
    _renderer_output_data={"rgb_hdr": hdr_color},
    ...
)
Camera._apply_ppisp_if_needed(camera)  # Calling as unbound method

This test passes even if _apply_ppisp_if_needed were never actually called in production code paths.

🔵 Improvement: ppisp.py:538-544 — Temporary directory created for anonymous stages is never cleaned up
When stages are anonymous, _resolve_stage_spg_assets creates a temp directory with tempfile.mkdtemp but never registers cleanup:

stage_dir = Path(tempfile.mkdtemp(prefix="isaaclab_ppisp_spg_"))
copy_ppisp_spg_files(stage_dir)
# No cleanup registered

Fix: Consider using tempfile.TemporaryDirectory with delete=False and registering an atexit handler, or document the leak.

🔵 Improvement: isaac_rtx_renderer.py:214-220 — Duplicated annotator registration logic
The HDR annotator registration is duplicated between the rgba/rgb branch and the explicit rgb_hdr branch:

if annotator_type == "rgba" or annotator_type == "rgb":
    if spec.cfg.ppisp is not None:
        annotator = rep.AnnotatorRegistry.get_annotator("HdrColor", ...)
        annotators[str(RenderBufferKind.RGB_HDR)] = annotator
# ... later ...
elif annotator_type == str(RenderBufferKind.RGB_HDR):
    annotator = rep.AnnotatorRegistry.get_annotator("HdrColor", ...)
    annotators[str(RenderBufferKind.RGB_HDR)] = annotator

Fix: Consolidate to avoid double-registration if user requests both rgba with PPISP and explicit rgb_hdr.

🔵 Improvement: ppisp_usd_spg.slang.usda — File is stored in Git LFS but appears to be small (1918 bytes)
The .usda file is tracked via Git LFS according to its pointer content, but at only 1918 bytes, it might be simpler to store it directly. This also means anyone cloning without LFS won't get the actual content.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 5, 2026

Greptile Summary

This PR introduces renderer-agnostic PPISP support by adding CameraCfg.ppisp, requesting scene-linear HDR color (RGB_HDR / HdrColor) from each renderer backend, and applying a Warp kernel (exposure, vignetting, homography, CRF) before writing the final rgb/rgba LDR outputs. All three renderers (IsaacRTX, OVRTX, Newton) are extended to expose RGB_HDR, and existing USD/SPG shader-parsing utilities are preserved for compatibility with exported PPISP stages.

  • camera_ppisp.py + camera_ppisp_warp.py: New PPISP config dataclass, USD parsing helpers, and a Warp kernel implementing the full ISP pipeline; normalize_camera_ppisp_cfg silently skips shader loading when no stage is provided during camera initialization.
  • camera.py: Allocates an HDR scratch buffer in _create_buffers and calls _apply_ppisp_if_needed after each render; relies on the rgb_alias view invariant from CameraData.allocate without an explicit guard.
  • ovrtx_usd.py: get_render_var_config returns the HdrColor path early when rgb_hdr is present in data_types, silently zeroing rgb/rgba if a user requests both rgb and rgb_hdr without PPISP in the OVRTX backend.

Confidence Score: 3/5

Two defects need resolution before merge: OVRTX silently produces zero RGB output when rgb_hdr and rgb are both requested without PPISP, and the shader_prim_path field in CameraPPISPCfg is silently ignored during camera initialization with no diagnostic.

The OVRTX get_render_var_config early-return on use_hdr makes requesting [rgb, rgb_hdr] without PPISP produce silently zeroed rgb/rgba buffers. Separately, normalize_camera_ppisp_cfg is called without a stage in _check_valid_cfg, so a CameraPPISPCfg with a shader_prim_path that a user expects to auto-load will silently use identity defaults instead of calibrated ISP parameters.

source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_usd.py (get_render_var_config HDR early return) and source/isaaclab/isaaclab/sensors/camera/camera.py (normalize_camera_ppisp_cfg called without stage).

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/renderers/camera_ppisp.py New file: CameraPPISPCfg dataclass, USD shader/RenderProduct parsing helpers, and normalize_camera_ppisp_cfg; silently skips shader loading when no stage is provided, which is the case during normal camera initialization.
source/isaaclab/isaaclab/renderers/camera_ppisp_warp.py New file: Warp kernel implementing the full PPISP pipeline (exposure, vignetting, homography, CRF, LDR packing); wp.init() correctly placed at module level; missing shape/dtype guards before kernel launch.
source/isaaclab/isaaclab/sensors/camera/camera.py Adds PPISP normalization in _check_valid_cfg (without stage, so shader_prim_path is silently ignored), allocates an HDR buffer in _create_buffers, and applies PPISP post-render in _apply_ppisp_if_needed.
source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_usd.py Adds HDR render-var selection via early use_hdr return in get_render_var_config; early return discards use_rgb, silently zeroing rgb/rgba when rgb_hdr and rgb are both requested without PPISP.
source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_renderer.py Adds HDR render-var injection for PPISP, _extract_hdr_color_tiles helper, and HdrColor extraction in _process_render_frame; gated correctly on PPISP config.
source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer.py Switches from rgb to HdrColor annotator when PPISP is active, adds RGB_HDR to supported types, and slices HDR data to 3 channels; consistent with the PPISP pipeline.
source/isaaclab_newton/isaaclab_newton/renderers/newton_warp_renderer.py Adds hdr_color_image slot to CameraOutputs, wires it in set_outputs/get_output, and exposes it in supported_output_types; clean and consistent with existing patterns.

Sequence Diagram

sequenceDiagram
    participant User
    participant Camera
    participant Renderer
    participant PPISPWarp

    User->>Camera: reset() / update()
    Camera->>Camera: _create_buffers() allocate rgb_hdr scratch buffer
    Camera->>Renderer: set_outputs(renderer_output_data)
    Note over Renderer: renderer_output_data contains rgb_hdr + rgba + rgb view

    loop Each physics step
        Camera->>Renderer: render(render_data)
        Renderer-->>Camera: fills rgb_hdr buffer HdrColor from scene
        Camera->>Camera: _apply_ppisp_if_needed()
        Camera->>PPISPWarp: apply_ppisp_to_rgba(hdr_color, rgba, cfg)
        Note over PPISPWarp: exposure vignetting homography CRF uint8 pack
        PPISPWarp-->>Camera: rgba filled with LDR output
        Note over Camera: rgb = rgba slice view auto-updated
    end

    Camera-->>User: data.output rgb or rgba
Loading

Comments Outside Diff (1)

  1. source/isaaclab/isaaclab/sensors/camera/camera.py, line 641 (link)

    P1 shader_prim_path silently ignored during camera initialization

    normalize_camera_ppisp_cfg is called here without a stage argument. When a user directly constructs CameraPPISPCfg(shader_prim_path="/Render/RenderProduct/PPISP") — which the docstring on shader_prim_path suggests is valid ("Optional source USD shader prim path used to populate inputs") — the stage is None branch in normalize_camera_ppisp_cfg falls through to _normalized_inputs(input_overrides), silently discarding the path and using whatever inputs are already set (typically the full set of defaults). No warning is emitted, so the user receives PPISP applied with identity-like defaults instead of their calibrated shader values, with no indication that the shader was not loaded.

Reviews (2): Last reviewed commit: "Address camera PPISP review feedback" | Re-trigger Greptile

Comment on lines +555 to +560
# Anonymous Kit stages do not provide a layer directory for relative SPG
# assets. Use a unique colocated sidecar directory so the Slang source and
# optional .slang.lua launcher resolve like exported 3DGRUT USDs.
stage_dir = Path(tempfile.mkdtemp(prefix="isaaclab_ppisp_spg_"))
copy_ppisp_spg_files(stage_dir)
return str(stage_dir / PPISP_SPG_USDA_FILE), str(stage_dir / PPISP_SPG_SLANG_FILE)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Temp directory leak for anonymous Kit stages

_resolve_stage_spg_assets calls tempfile.mkdtemp() each time it is invoked for an anonymous stage and never cleans the directory up — there is no atexit hook, no weakref finalizer, and no manual cleanup path. Every camera that initializes with an anonymous Kit stage (the typical Kit workflow) creates a new directory that lives for the entire process. In a simulation with many parallel camera initializations or frequent resets, this silently accumulates disk space. At minimum, register a cleanup via atexit.register(shutil.rmtree, stage_dir, ignore_errors=True) immediately after the mkdtemp call, or use a module-level cache keyed by the stage identity so the same directory is reused for the same stage.

Comment on lines +154 to +158
def apply_ppisp_to_rgba(hdr_color: torch.Tensor, out_rgba: torch.Tensor, cfg: PPISPCfg) -> None:
"""Apply PPISP to ``hdr_color`` and write LDR RGBA into ``out_rgba``."""
inputs = cfg.inputs
wp.init()
wp.launch(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 wp.init() is called on every invocation of apply_ppisp_to_rgba, which runs once per camera update per physics step. While Warp's init() is idempotent after the first call, it still acquires a lock and does version/device checks on every call. Move the wp.init() call to module import time (top of the file), which is the conventional Warp pattern and eliminates per-frame overhead.

Suggested change
def apply_ppisp_to_rgba(hdr_color: torch.Tensor, out_rgba: torch.Tensor, cfg: PPISPCfg) -> None:
"""Apply PPISP to ``hdr_color`` and write LDR RGBA into ``out_rgba``."""
inputs = cfg.inputs
wp.init()
wp.launch(
def apply_ppisp_to_rgba(hdr_color: torch.Tensor, out_rgba: torch.Tensor, cfg: PPISPCfg) -> None:
"""Apply PPISP to ``hdr_color`` and write LDR RGBA into ``out_rgba``."""
inputs = cfg.inputs
wp.launch(

Comment on lines +537 to 548
def _apply_ppisp_if_needed(self) -> None:
"""Apply PPISP once at the IsaacLab camera wrapper boundary."""
if self.cfg.ppisp is None or self._renderer_output_data is None:
return
hdr_color = self._renderer_output_data.get(str(RenderBufferKind.RGB_HDR))
rgba = self._data.output.get("rgba")
if hdr_color is None or rgba is None:
return
apply_ppisp_to_rgba(hdr_color[..., :3], rgba, self.cfg.ppisp)
if "rgb" in self._data.output:
self._data.output["rgb"] = rgba[..., :3]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Silent PPISP bypass when rgba buffer is absent

_apply_ppisp_if_needed silently returns when rgba is None (line 543), but _create_buffers only validates that the renderer exposes RGB_HDR — it does not verify that an rgba buffer was actually allocated. If a future renderer includes RGB_HDR in supported_output_types but omits RGBA (breaking rgb_alias), PPISP is configured, allocates an HDR buffer, but then silently produces no output. There is no log warning, no exception, and no indication to the caller that PPISP was skipped. A logger.warning(...) here, or an assertion in _create_buffers that rgba is present when PPISP is active, would make this failure mode visible.

@moennen moennen force-pushed the nicolasm/ppisp-renderer-simple-integration branch from 2fcda20 to 73a68df Compare May 5, 2026 15:38
@moennen moennen marked this pull request as draft May 5, 2026 15:42
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 is a follow-up review on commit 73a68df. The PR has been significantly simplified — all SPG shader assets and Newton API compatibility layers have been removed. The implementation is now focused solely on the Warp kernel PPISP pipeline.

Previous Concerns Status

  • GPU synchronization: NOT addressed — apply_ppisp_to_rgba still lacks wp.synchronize() after kernel launch
  • Vignetting in Warp kernel: ADDRESSED — vignetting is now fully implemented in _apply_vignetting function (lines 33-54 in camera_ppisp_warp.py)
  • _renderer_output_data aliasing: Still present but was acknowledged as safe
  • Newton private API import: RESOLVED — the Newton API compatibility layer was removed entirely
  • Test using SimpleNamespace mock: Still present but acceptable for unit testing
  • Temp directory cleanup: RESOLVED — SPG asset handling removed entirely
  • Duplicated annotator registration: Still present in isaac_rtx_renderer.py:214-220

New Findings

🔴 Critical: camera_ppisp_warp.py:233-282 — Missing GPU synchronization after Warp kernel launch
This remains unaddressed from the previous review. The kernel launches asynchronously and the function returns immediately:

def apply_ppisp_to_rgba(hdr_color: torch.Tensor, out_rgba: torch.Tensor, cfg: CameraPPISPCfg) -> None:
    wp.launch(_apply_ppisp_kernel, ...)
    # No wp.synchronize() - caller may read stale data

Fix: Add wp.synchronize_device(str(out_rgba.device)) before returning.

🟡 Warning: camera_ppisp_warp.py:247 — wp.init() called on every PPISP application
wp.init() is called inside apply_ppisp_to_rgba, which runs every frame. While Warp handles repeated init calls gracefully, this adds unnecessary overhead:

def apply_ppisp_to_rgba(...):
    inputs = cfg.inputs
    wp.init()  # Called every frame

Fix: Move wp.init() to module-level or camera initialization.

Implementation Verdict

Minor fixes needed — The synchronization issue is critical for correctness. The wp.init() call is a performance concern but not blocking.

Test Coverage

Tests are adequate for the simplified implementation. The vignetting test (test_ppisp_warp_vignetting_uses_detiled_camera_coordinates) validates the new vignetting code path.

Claude: ## 🤖 Isaac Lab Review Bot

Summary

This is a follow-up review on commit 73a68df. The PR has been significantly simplified — all SPG shader assets and Newton API compatibility layers have been removed. The implementation is now focused solely on the Warp kernel PPISP pipeline.

Previous Concerns Status

  • GPU synchronization: NOT addressed — apply_ppisp_to_rgba still lacks wp.synchronize() after kernel launch
  • Vignetting in Warp kernel: ADDRESSED — vignetting is now fully implemented in _apply_vignetting function (lines 33-54 in camera_ppisp_warp.py)
  • _renderer_output_data aliasing: Still present but was acknowledged as safe
  • Newton private API import: RESOLVED — the Newton API compatibility layer was removed entirely
  • Test using SimpleNamespace mock: Still present but acceptable for unit testing
  • Temp directory cleanup: RESOLVED — SPG asset handling removed entirely
  • Duplicated annotator registration: Still present in isaac_rtx_renderer.py:214-220

New Findings

🔴 Critical: camera_ppisp_warp.py:233-282 — Missing GPU synchronization after Warp kernel launch
This remains unaddressed from the previous review. The kernel launches asynchronously and the function returns immediately:

def apply_ppisp_to_rgba(hdr_color: torch.Tensor, out_rgba: torch.Tensor, cfg: CameraPPISPCfg) -> None:
    wp.launch(_apply_ppisp_kernel, ...)
    # No wp.synchronize() - caller may read stale data

Fix: Add wp.synchronize_device(str(out_rgba.device)) before returning.

🟡 Warning: camera_ppisp_warp.py:247 — wp.init() called on every PPISP application
wp.init() is called inside apply_ppisp_to_rgba, which runs every frame. While Warp handles repeated init calls gracefully, this adds unnecessary overhead:

def apply_ppisp_to_rgba(...):
    inputs = cfg.inputs
    wp.init()  # Called every frame

Fix: Move wp.init() to module-level or camera initialization.

Implementation Verdict

Minor fixes needed — The synchronization issue is critical for correctness. The wp.init() call is a performance concern but not blocking.

Test Coverage

Tests are adequate for the simplified implementation. The vignetting test (test_ppisp_warp_vignetting_uses_detiled_camera_coordinates) validates the new vignetting code path.

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

Previous concerns remain unaddressed in commit 3cd43d9:

  1. GPU synchronization (🔴 Critical): apply_ppisp_to_rgba at line 247 still lacks wp.synchronize() after the kernel launch. The caller in camera.py:545 may read stale data from out_rgba.

  2. wp.init() per-frame (🟡 Warning): Still called inside apply_ppisp_to_rgba on every frame at line 248.

No new issues introduced. The diff between commits appears minimal (formatting/cleanup only).

Implementation Verdict

Minor fixes still needed — please address the synchronization issue before merge.

moennen added 3 commits May 5, 2026 14:00
Apply camera PPISP from renderer HDR buffers and verify RTX, OVRTX, and Newton HDR output plumbing for the camera pipeline.
Apply pre-commit formatting to the camera PPISP integration files.
Run the PPISP Warp kernel on the torch CUDA stream, move Warp initialization out of the frame path, and avoid duplicate HdrColor annotator registration.
@moennen moennen force-pushed the nicolasm/ppisp-renderer-simple-integration branch from 3cd43d9 to 3d15b5d Compare May 5, 2026 18:01
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

Previous concerns addressed:

  1. wp.init() moved to module level (line 15) — no longer called per-frame.
  2. ✅ GPU synchronization handled via wp.stream_from_torch() — the kernel now launches on the correct CUDA stream associated with the output tensor, ensuring proper ordering without explicit wp.synchronize().

New observation:
The stream handling at line 247 passes stream=None for CPU tensors, which is correct. The CUDA path properly synchronizes via stream association.

Implementation Verdict

Ship it — previous concerns resolved, implementation looks correct.

@moennen moennen marked this pull request as ready for review May 5, 2026 18:15
Comment on lines +30 to +31
if use_hdr:
return "/Render/Vars/HdrColor", "HdrColor", "HdrColor"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Early return discards use_rgb when rgb_hdr is requested alongside rgb without PPISP

When a user requests data_types=["rgb", "rgb_hdr"] without PPISP (a valid configuration because RGB_HDR is now in supported_output_types()), use_hdr=True causes an early return of the HdrColor render-var config. The OVRTX USD is then set up with only HdrColor in orderedVars, so LdrColor is never rendered. _process_render_frame checks if "LdrColor" in frame.render_vars before extracting the rgba buffer, and since LdrColor is absent, rgb and rgba remain zeroed with no error or warning. This affects any OVRTX user who explicitly requests rgb_hdr alongside rgb without enabling PPISP.

Verify the deprecated TiledCamera alias accepts Camera PPISP config and uses the inherited Camera wrapper post-processing path.
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

Previous concerns about wp.init() placement and GPU synchronization have been addressed. The new commits add test coverage and extend RGB_HDR support across renderers.

One new issue:

🟡 Warning: source/isaaclab/isaaclab/sensors/camera/camera.py:544 — Missing rgb alias update after PPISP

The _apply_ppisp_if_needed method writes to rgba but doesn't update the rgb alias. Looking at line 544:

rgba = self._data.output[str(RenderBufferKind.RGBA)]
apply_ppisp_to_rgba(hdr_color, rgba, self.cfg.ppisp)

Since rgb is created as rgba[..., :3] (a view into rgba's storage) during buffer allocation, this should work correctly — the view shares memory with rgba. However, _create_buffers explicitly aliases rgb at line 527 via dict(self._data.output), and CameraData.allocate creates the alias. Verified this is safe because both reference the same underlying storage.

Implementation Verdict

Ship it — the rgb/rgba aliasing is handled correctly via shared tensor storage. No new blocking issues.

Ensure explicit RGB_HDR requests add HdrColor without dropping LdrColor when LDR RGB is also requested.
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 previous concern about rgb/rgba aliasing was already noted as safe in the last review. Examining the new commits:

The changes are test additions and minor refinements. No new implementation issues introduced.

Implementation Verdict

Ship it — Test coverage is comprehensive, RGB_HDR plumbing is consistent across all three renderers (Isaac RTX, OVRTX, Newton Warp), and the PPISP integration follows the documented design.

@moennen moennen marked this pull request as draft May 5, 2026 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant