Skip to content

Commit 1efbab5

Browse files
committed
Cleanup rendering context state update.
1 parent 676c791 commit 1efbab5

File tree

6 files changed

+57
-57
lines changed

6 files changed

+57
-57
lines changed

genesis/ext/pyrender/jit_render.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,10 @@ def update_normal(self, node, vertices):
826826
return self._update_normal_flat(vertices.reshape((-1, 3, 3)))
827827

828828
def update_buffer(self, buffer_updates):
829+
# Early return if nothing to do
830+
if not buffer_updates:
831+
return
832+
829833
updates = np.zeros((len(buffer_updates), 3), dtype=np.int64)
830834
buffers = []
831835
for idx, (id, data) in enumerate(buffer_updates.items()):

genesis/ext/pyrender/viewer.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,6 @@ def __init__(
400400
self.pending_offscreen_camera = None
401401
self.offscreen_result = None
402402

403-
self.pending_buffer_updates = {}
404-
405403
# Starting the viewer would raise an exception if the OpenGL context is invalid for some reason. This exception
406404
# must be caught in order to implement some fallback mechanism. One may want to start the viewer from the main
407405
# thread while the running loop would be running on a background thread. However, this approach is not possible
@@ -655,10 +653,6 @@ def render_offscreen(self, camera_node, render_target, depth=False, seg=False, n
655653
self.render_flags["depth"] = False
656654
return self.offscreen_result
657655

658-
def update_buffers(self):
659-
self._renderer.jit.update_buffer(self.pending_buffer_updates)
660-
self.pending_buffer_updates.clear()
661-
662656
def wait_until_initialized(self):
663657
self._initialized_event.wait()
664658

@@ -671,7 +665,10 @@ def draw_offscreen(self):
671665

672666
# Make OpenGL context current
673667
self.switch_to()
674-
self.update_buffers()
668+
669+
# Update context
670+
self._renderer.jit.update_buffer(self.gs_context.buffer)
671+
self.gs_context.buffer.clear()
675672

676673
self.offscreen_results = []
677674
self.render_flags["offscreen"] = True
@@ -696,7 +693,10 @@ def on_draw(self):
696693

697694
# Make OpenGL context current
698695
self.switch_to()
699-
self.update_buffers()
696+
697+
# Update context
698+
self._renderer.jit.update_buffer(self.gs_context.buffer)
699+
self.gs_context.buffer.clear()
700700

701701
# Render the scene
702702
self.clear()

genesis/vis/rasterizer.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,9 @@ def render_camera(self, camera, rgb=True, depth=False, segmentation=False, norma
6464
# Set the context
6565
self._renderer.make_current()
6666

67-
# Update the buffers
68-
if self._buffer_updates is None:
69-
gs.raise_exception("Buffers were not set before rendering. Please call 'update_scene' method.")
70-
71-
self._context.jit.update_buffer(self._buffer_updates)
67+
# Update the context
68+
self._context.jit.update_buffer(self._context.buffer)
69+
self._context.buffer.clear()
7270

7371
# Render
7472
if rgb or depth or normal:
@@ -97,42 +95,40 @@ def render_camera(self, camera, rgb=True, depth=False, segmentation=False, norma
9795
seg=True,
9896
)
9997

100-
# Unset the context
98+
# Unset the context if necessary
10199
self._renderer.make_uncurrent()
102100
else:
103-
# Update the buffers
104-
self._context.jit.update_buffer(self._buffer_updates)
105-
106101
# Render
107102
if rgb or depth or normal:
108-
retval = self._viewer._pyrender_viewer.render_offscreen(
103+
retval = self._viewer.render_offscreen(
109104
self._camera_nodes[camera.uid],
110105
self._camera_targets[camera.uid],
111106
depth=depth,
112107
normal=normal,
113108
)
114109

115110
if segmentation:
116-
seg_idxc_rgb_arr, _ = self._viewer._pyrender_viewer.render_offscreen(
111+
seg_idxc_rgb_arr, _ = self._viewer.render_offscreen(
117112
self._camera_nodes[camera.uid],
118113
self._camera_targets[camera.uid],
119114
depth=False,
120115
normal=False,
121116
seg=True,
122117
)
123118

124-
if rgb:
119+
if segmentation:
120+
seg_idxc_arr = self._context.seg_idxc_rgb_arr_to_idxc_arr(seg_idxc_rgb_arr)
121+
122+
if rgb or depth or normal:
125123
rgb_arr = retval[0]
126124
if depth:
127125
depth_arr = retval[1]
128126
if normal:
129127
normal_arr = retval[2]
130-
if segmentation:
131-
seg_idxc_arr = self._context.seg_idxc_rgb_arr_to_idxc_arr(seg_idxc_rgb_arr)
132128
return rgb_arr, depth_arr, seg_idxc_arr, normal_arr
133129

134130
def update_scene(self):
135-
self._buffer_updates = self._context.update()
131+
self._context.update()
136132

137133
def destroy(self):
138134
for node in self._camera_nodes.values():
@@ -144,13 +140,13 @@ def destroy(self):
144140

145141
if self._offscreen and self._renderer is not None:
146142
try:
147-
self._renderer._platform.make_current()
143+
self._renderer.make_current()
148144
self._renderer.delete()
149145
except OpenGL.error.GLError:
150146
pass
151147
del self._renderer
152-
gc.collect()
153148
self._renderer = None
149+
gc.collect()
154150

155151
@property
156152
def viewer(self):

genesis/vis/rasterizer_context.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ def __init__(self, options):
3535
self.rendered_envs_idx = options.rendered_envs_idx
3636
self.env_separate_rigid = options.env_separate_rigid
3737

38+
self.buffer = dict()
39+
3840
# nodes
3941
self.world_frame_node = None
4042
self.link_frame_nodes = dict()
@@ -831,31 +833,31 @@ def clear_debug_objects(self):
831833
self.clear_external_nodes()
832834

833835
def update(self):
834-
buffer_updates = dict()
836+
# Early return if already updated previously
837+
if self._t >= self.scene._t:
838+
return
835839

836-
if self._t >= self.scene._t: # already updated
837-
return buffer_updates
838-
else:
839-
self._t = self.scene._t
840+
self._t = self.scene._t
840841

841842
# clear up all dynamic nodes
842843
self.clear_dynamic_nodes()
843844

844845
# update variables not used in simulation
845846
self.visualizer.update_visual_states()
846847

848+
# Reset scene bounds to trigger recomputation. They are involved in shadow map
847849
self._scene._bounds = None
848-
self.update_link_frame(buffer_updates)
849-
self.update_tool(buffer_updates)
850-
self.update_rigid(buffer_updates)
851-
self.update_contact(buffer_updates)
852-
self.update_avatar(buffer_updates)
853-
self.update_mpm(buffer_updates)
854-
self.update_sph(buffer_updates)
855-
self.update_pbd(buffer_updates)
856-
self.update_fem(buffer_updates)
857-
858-
return buffer_updates
850+
851+
self.buffer.clear()
852+
self.update_link_frame(self.buffer)
853+
self.update_tool(self.buffer)
854+
self.update_rigid(self.buffer)
855+
self.update_contact(self.buffer)
856+
self.update_avatar(self.buffer)
857+
self.update_mpm(self.buffer)
858+
self.update_sph(self.buffer)
859+
self.update_pbd(self.buffer)
860+
self.update_fem(self.buffer)
859861

860862
def add_light(self, light):
861863
# light direction is light pose's -z frame

genesis/vis/viewer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ def update(self, auto_refresh=None):
144144
self.update_following()
145145

146146
with self.lock:
147-
self._pyrender_viewer.pending_buffer_updates |= self.context.update()
147+
# Update context
148+
self.context.update()
148149

149150
# Refresh viewer by default if and if this is possible
150151
if auto_refresh is None:
@@ -158,6 +159,9 @@ def update(self, auto_refresh=None):
158159
if self._max_FPS is not None:
159160
self.rate.sleep()
160161

162+
def render_offscreen(self, camera_node, render_target, depth=False, seg=False, normal=False):
163+
return self._pyrender_viewer.render_offscreen(camera_node, render_target, depth, seg, normal)
164+
161165
def set_camera_pose(self, pose=None, pos=None, lookat=None):
162166
"""
163167
Set viewer camera pose.

genesis/vis/visualizer.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,16 @@ def reset(self):
130130

131131
self._context.reset()
132132

133-
# Need to update viewer once here, because otherwise camera will update scene if render is called right after
134-
# build, which will lead to segfault.
135-
if self._viewer is not None:
136-
if self._viewer.is_alive():
137-
self._viewer.update(auto_refresh=True)
138-
139133
if self._raytracer is not None:
140134
self._raytracer.reset()
141135

136+
if self.viewer_lock is not None:
137+
for camera in self._cameras:
138+
self._rasterizer.render_camera(camera)
139+
140+
if self._viewer is not None:
141+
self._viewer.update(auto_refresh=True)
142+
142143
def build(self):
143144
self._context.build(self._scene)
144145

@@ -155,15 +156,8 @@ def build(self):
155156
for camera in self._cameras:
156157
camera._build()
157158

158-
if self._cameras:
159-
# need to update viewer once here, because otherwise camera will update scene if render is called right
160-
# after build, which will lead to segfault.
161-
if self._viewer is not None:
162-
self._viewer.update(auto_refresh=True)
163-
else:
164-
# viewer creation will compile rendering kernels if viewer is not created, render here once to compile
165-
self._rasterizer.update_scene()
166-
self._rasterizer.render_camera(self._cameras[0])
159+
# Make sure that the viewer is fully compiled and in a clean state
160+
self.reset()
167161

168162
def update(self, force=True, auto=None):
169163
if force: # force update

0 commit comments

Comments
 (0)