Skip to content

Commit dc82943

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 dc82943

File tree

1 file changed

+33
-7
lines changed

1 file changed

+33
-7
lines changed

source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_renderer.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,11 @@ def write_output(
395395
output_name: str,
396396
output_data: torch.Tensor,
397397
) -> None:
398-
"""Copy from render_data warp buffer to output tensor."""
398+
"""Copy from render_data warp buffer to output tensor.
399+
400+
Triggers deferred tile extraction on first access after render().
401+
"""
402+
self._ensure_extraction(render_data)
399403
if output_name not in render_data.warp_buffers:
400404
return
401405
src = render_data.warp_buffers[output_name]
@@ -515,7 +519,12 @@ def _process_render_frame(self, render_data: OVRTXRenderData, frame, output_buff
515519
)
516520

517521
def render(self, render_data: OVRTXRenderData) -> None:
518-
"""Render the scene into the provided RenderData."""
522+
"""Render the scene and defer tile extraction until buffers are needed.
523+
524+
Instead of immediately extracting tiles (which stalls on rendering completion),
525+
we store the render products and defer extraction to write_output(). This allows
526+
training/physics work to overlap with rendering on the GPU.
527+
"""
519528
if not self._initialized_scene:
520529
raise RuntimeError("Scene not initialized. Call initialize() first.")
521530
if self._renderer is None or len(self._render_product_paths) == 0:
@@ -527,13 +536,30 @@ def render(self, render_data: OVRTXRenderData) -> None:
527536
)
528537
product_path = self._render_product_paths[0]
529538
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-
)
539+
# Store frame for deferred extraction instead of extracting immediately
540+
render_data._pending_frame = products[product_path].frames[0]
541+
render_data._pending_products = products
542+
render_data._extraction_done = False
543+
else:
544+
render_data._pending_frame = None
545+
render_data._pending_products = None
546+
render_data._extraction_done = True
535547
except Exception as e:
536548
logger.warning("OVRTX rendering failed: %s", e, exc_info=True)
549+
render_data._pending_frame = None
550+
render_data._pending_products = None
551+
render_data._extraction_done = True
552+
553+
def _ensure_extraction(self, render_data: OVRTXRenderData) -> None:
554+
"""Extract tiles from the pending frame if not already done."""
555+
if getattr(render_data, '_extraction_done', True):
556+
return
557+
frame = getattr(render_data, '_pending_frame', None)
558+
if frame is not None:
559+
self._process_render_frame(render_data, frame, render_data.warp_buffers)
560+
render_data._extraction_done = True
561+
render_data._pending_frame = None
562+
render_data._pending_products = None
537563

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

0 commit comments

Comments
 (0)