Skip to content

Commit 8bb4cc0

Browse files
committed
perf(ovrtx): deferred tile extraction - extract on write_output not render
Move tile extraction from render() to write_output() via lazy _ensure_extraction(). render() now only calls _renderer.step() and stores the frame reference. Extraction happens on first write_output() call. This separates the render kick from buffer consumption, allowing future overlap opportunities.
1 parent 9ef9417 commit 8bb4cc0

File tree

1 file changed

+33
-9
lines changed

1 file changed

+33
-9
lines changed

source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_renderer.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@
4848
create_camera_transforms_kernel,
4949
extract_all_depth_tiles_kernel,
5050
extract_all_rgba_tiles_kernel,
51-
extract_depth_tile_from_tiled_buffer_kernel,
52-
extract_tile_from_tiled_buffer_kernel,
5351
generate_random_colors_from_ids_kernel,
5452
sync_newton_transforms_kernel,
5553
)
@@ -395,7 +393,11 @@ def write_output(
395393
output_name: str,
396394
output_data: torch.Tensor,
397395
) -> None:
398-
"""Copy from render_data warp buffer to output tensor."""
396+
"""Copy from render_data warp buffer to output tensor.
397+
398+
Triggers deferred tile extraction on first access after render().
399+
"""
400+
self._ensure_extraction(render_data)
399401
if output_name not in render_data.warp_buffers:
400402
return
401403
src = render_data.warp_buffers[output_name]
@@ -515,7 +517,12 @@ def _process_render_frame(self, render_data: OVRTXRenderData, frame, output_buff
515517
)
516518

517519
def render(self, render_data: OVRTXRenderData) -> None:
518-
"""Render the scene into the provided RenderData."""
520+
"""Render the scene and defer tile extraction until buffers are needed.
521+
522+
Instead of immediately extracting tiles (which stalls on rendering completion),
523+
we store the render products and defer extraction to write_output(). This allows
524+
training/physics work to overlap with rendering on the GPU.
525+
"""
519526
if not self._initialized_scene:
520527
raise RuntimeError("Scene not initialized. Call initialize() first.")
521528
if self._renderer is None or len(self._render_product_paths) == 0:
@@ -527,13 +534,30 @@ def render(self, render_data: OVRTXRenderData) -> None:
527534
)
528535
product_path = self._render_product_paths[0]
529536
if product_path in products and len(products[product_path].frames) > 0:
530-
self._process_render_frame(
531-
render_data,
532-
products[product_path].frames[0],
533-
render_data.warp_buffers,
534-
)
537+
# Store frame for deferred extraction instead of extracting immediately
538+
render_data._pending_frame = products[product_path].frames[0]
539+
render_data._pending_products = products
540+
render_data._extraction_done = False
541+
else:
542+
render_data._pending_frame = None
543+
render_data._pending_products = None
544+
render_data._extraction_done = True
535545
except Exception as e:
536546
logger.warning("OVRTX rendering failed: %s", e, exc_info=True)
547+
render_data._pending_frame = None
548+
render_data._pending_products = None
549+
render_data._extraction_done = True
550+
551+
def _ensure_extraction(self, render_data: OVRTXRenderData) -> None:
552+
"""Extract tiles from the pending frame if not already done."""
553+
if getattr(render_data, "_extraction_done", True):
554+
return
555+
frame = getattr(render_data, "_pending_frame", None)
556+
if frame is not None:
557+
self._process_render_frame(render_data, frame, render_data.warp_buffers)
558+
render_data._extraction_done = True
559+
render_data._pending_frame = None
560+
render_data._pending_products = None
537561

538562
def cleanup(self, render_data: OVRTXRenderData | None) -> None:
539563
"""Release renderer resources. See :meth:`~isaaclab.renderers.base_renderer.BaseRenderer.cleanup`."""

0 commit comments

Comments
 (0)