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