Skip to content

Commit 50d93ff

Browse files
committed
Index tiled image buffer in 3D instead of flattening to 1D
Addresses review feedback on #7500. render() flattened each annotator's tiled buffer into a single 1D Warp array, whose length is num_envs * tile pixels * channels. That product can exceed the maximum size of a single Warp array dimension, so large environment counts / camera resolutions failed with: ValueError: Array shapes must not exceed the maximum representable value of a signed 32-bit integer, got 2621440000 in dimension 0 Refactor reshape_tiled_image to index the tiled buffer as a 3D array (num_tiles_y * image_height, num_tiles_x * image_width, num_channels) and update the overloads to ndim=3, so each dimension is bounded individually rather than by their product. Single-channel annotators return a 2D buffer, so the renderer adds the trailing channel dimension before launching. This removes the need for the preflight size check added earlier in this PR, which is dropped along with the hardcoded Warp dimension limit: per review, that limit is a Warp implementation detail rather than a contract, and the check also assumed 4 elements per pixel for every camera, wrongly rejecting valid single-channel configurations. Verified against Warp 1.9.1 on GPU: the refactored kernel is numerically identical to the previous implementation across RGBA, depth, normals and ragged-grid cases; a (25600, 25600, 4) buffer -- the exact geometry from the reported failure -- still raises on .flatten() but launches successfully through the 3D path.
1 parent df441d6 commit 50d93ff

4 files changed

Lines changed: 38 additions & 46 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Changed
2+
^^^^^^^
3+
4+
* Changed the ``reshape_tiled_image`` Warp kernel to index the tiled image buffer as a 3D array
5+
of shape (num_tiles_y * image_height, num_tiles_x * image_width, num_channels) instead of a
6+
flattened 1D array. This keeps every array dimension within Warp's per-dimension size limit, so
7+
large environment counts and camera resolutions no longer overflow a single flattened dimension.

source/isaaclab/isaaclab/utils/warp/kernels.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,14 @@ def reshape_tiled_image(
344344
is assumed to be tiled in the x and y directions. The output image is a batch of images with the
345345
specified height, width, and number of channels.
346346
347+
The tiled buffer is indexed as a 3D array rather than flattened to 1D so that the number of
348+
cameras and the camera resolution are bounded per dimension instead of by their product. A
349+
flattened view of a large tiled buffer can exceed the maximum size of a single Warp array
350+
dimension, see https://nvidia.github.io/warp/stable/user_guide/limitations.html#arrays.
351+
347352
Args:
348-
tiled_image_buffer: The input image buffer. Shape is (height * width * num_channels * num_cameras,).
353+
tiled_image_buffer: The input image buffer. Shape is
354+
(num_tiles_y * image_height, num_tiles_x * image_width, num_channels).
349355
batched_image: The output image. Shape is (num_cameras, height, width, num_channels).
350356
image_width: The width of the image.
351357
image_height: The height of the image.
@@ -358,32 +364,29 @@ def reshape_tiled_image(
358364
# resolve the tile indices
359365
tile_x_id = camera_id % num_tiles_x
360366
tile_y_id = camera_id // num_tiles_x
361-
# compute the start index of the pixel in the tiled image buffer
362-
pixel_start = (
363-
num_channels * num_tiles_x * image_width * (image_height * tile_y_id + height_id)
364-
+ num_channels * tile_x_id * image_width
365-
+ num_channels * width_id
366-
)
367+
# resolve the pixel position within the tiled image buffer
368+
row = image_height * tile_y_id + height_id
369+
col = image_width * tile_x_id + width_id
367370

368371
# copy the pixel values into the batched image
369372
for i in range(num_channels):
370-
batched_image[camera_id, height_id, width_id, i] = batched_image.dtype(tiled_image_buffer[pixel_start + i])
373+
batched_image[camera_id, height_id, width_id, i] = batched_image.dtype(tiled_image_buffer[row, col, i])
371374

372375

373376
# uint32 -> int32 conversion is required for non-colored segmentation annotators
374377
wp.overload(
375378
reshape_tiled_image,
376-
{"tiled_image_buffer": wp.array(dtype=wp.uint32), "batched_image": wp.array(dtype=wp.uint32, ndim=4)},
379+
{"tiled_image_buffer": wp.array(dtype=wp.uint32, ndim=3), "batched_image": wp.array(dtype=wp.uint32, ndim=4)},
377380
)
378381
# uint8 is used for 4 channel annotators
379382
wp.overload(
380383
reshape_tiled_image,
381-
{"tiled_image_buffer": wp.array(dtype=wp.uint8), "batched_image": wp.array(dtype=wp.uint8, ndim=4)},
384+
{"tiled_image_buffer": wp.array(dtype=wp.uint8, ndim=3), "batched_image": wp.array(dtype=wp.uint8, ndim=4)},
382385
)
383386
# float32 is used for single channel annotators
384387
wp.overload(
385388
reshape_tiled_image,
386-
{"tiled_image_buffer": wp.array(dtype=wp.float32), "batched_image": wp.array(dtype=wp.float32, ndim=4)},
389+
{"tiled_image_buffer": wp.array(dtype=wp.float32, ndim=3), "batched_image": wp.array(dtype=wp.float32, ndim=4)},
387390
)
388391

389392
##

source/isaaclab_physx/changelog.d/shauryad-bug-fixes.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ Fixed
44
* Fixed ``IsaacRtxRenderer.render()`` crashing with ``RuntimeError: Invalid indexing in slice``
55
when an annotator's channel buffer has not warmed up yet (e.g. right after attach, at env
66
creation) for the ``motion_vectors``, ``normals``, simple-shading, and RGB HDR data types.
7-
* Added a pre-flight check in ``IsaacRtxRenderer.create_render_data()`` that raises a clear,
8-
actionable error when the requested ``num_envs``/camera resolution would overflow Warp's
9-
signed-32-bit-representable array shape limit, instead of an opaque ``ValueError`` raised deep
10-
inside ``render()``.
7+
8+
Changed
9+
^^^^^^^
10+
11+
* Changed ``IsaacRtxRenderer.render()`` to pass the tiled annotator buffer to
12+
``reshape_tiled_image`` as a 3D array instead of flattening it to 1D. Large environment counts
13+
and camera resolutions no longer overflow the maximum size of a single Warp array dimension.

source/isaaclab_physx/isaaclab_physx/renderers/isaac_rtx_renderer.py

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -83,32 +83,6 @@ def _raise_missing_ppisp_error(exc: ModuleNotFoundError) -> NoReturn:
8383
}
8484
SIMPLE_SHADING_MODE_SETTING = "/rtx/minimal/mode"
8585

86-
# Warp arrays require every dimension to fit in a signed 32-bit int (see
87-
# ``warp.types.array.__getitem__``/``check_array_shape``). ``render()`` flattens the whole
88-
# tiled buffer (all environments' camera tiles concatenated) into one Warp array per data
89-
# type, so this bounds how large ``num_envs * tile pixels`` can get before that call raises.
90-
_WARP_MAX_ARRAY_DIM = 2_147_483_647
91-
92-
93-
def _validate_tiled_buffer_size(spec: CameraRenderSpec) -> None:
94-
"""Raise a clear error if this camera's tiled buffer would overflow Warp's array shape limit.
95-
96-
Worst case is 4 elements per pixel: RGBA/HDR annotators return 4 channels directly, and
97-
colorized segmentation annotators reinterpret a uint32 id as 4 uint8 channels.
98-
"""
99-
num_tile_cols = math.ceil(math.sqrt(spec.view_count))
100-
num_tile_rows = math.ceil(spec.view_count / num_tile_cols)
101-
tiled_pixels = (num_tile_cols * spec.cfg.width) * (num_tile_rows * spec.cfg.height)
102-
max_elements_per_pixel = 4
103-
if tiled_pixels * max_elements_per_pixel > _WARP_MAX_ARRAY_DIM:
104-
raise ValueError(
105-
f"Camera '{spec.cfg.prim_path}' would allocate a tiled render buffer of up to"
106-
f" {tiled_pixels * max_elements_per_pixel} elements ({spec.view_count} environments tiled into a"
107-
f" {num_tile_cols}x{num_tile_rows} grid at {spec.cfg.width}x{spec.cfg.height} resolution), which"
108-
f" exceeds Warp's signed-32-bit-representable array shape limit ({_WARP_MAX_ARRAY_DIM})."
109-
" Reduce the number of environments (--num_envs) or the camera resolution for this task."
110-
)
111-
11286

11387
def _camera_semantic_filter_predicate(semantic_filter: str | list[str]) -> str:
11488
"""Build the instance-mapping semantics predicate from :attr:`isaaclab.sensors.camera.CameraCfg.semantic_filter`.
@@ -276,10 +250,6 @@ def prepare_stage(self, stage: Usd.Stage, num_envs: int) -> None:
276250
def create_render_data(self, spec: CameraRenderSpec) -> IsaacRtxRenderData:
277251
"""Create render product and annotators for the tiled camera.
278252
See :meth:`~isaaclab.renderers.base_renderer.BaseRenderer.create_render_data`."""
279-
# Fail fast with an actionable error instead of a cryptic Warp ``ValueError`` raised deep
280-
# inside render()'s ``.flatten()`` call once the annotators are already attached.
281-
_validate_tiled_buffer_size(spec)
282-
283253
import omni.replicator.core as rep
284254
from omni.syntheticdata import SyntheticData
285255
from pxr import UsdGeom
@@ -617,11 +587,20 @@ def tiling_grid_shape():
617587
buf_wp = render_data._hdr_scratch_wp
618588
else:
619589
buf_wp = output_data[data_type].warp
590+
591+
# ``reshape_tiled_image`` indexes the tiled buffer as (rows, cols, channels). Single-channel
592+
# annotators (e.g. depth, non-colorized segmentation) hand back a 2D buffer, so add the
593+
# trailing channel dimension. Passing the buffer in 3D rather than flattening it keeps every
594+
# dimension well inside Warp's per-dimension array size limit, so large environment counts and
595+
# camera resolutions no longer overflow a single flattened dimension.
596+
if tiled_data_buffer.ndim == 2:
597+
tiled_data_buffer = tiled_data_buffer.reshape((*tiled_data_buffer.shape, 1))
598+
620599
wp.launch(
621600
kernel=reshape_tiled_image,
622601
dim=(view_count, cfg.height, cfg.width),
623602
inputs=[
624-
tiled_data_buffer.flatten(),
603+
tiled_data_buffer,
625604
buf_wp,
626605
*list(buf_wp.shape[1:]),
627606
num_tiles_x,

0 commit comments

Comments
 (0)