Skip to content

Commit 0d8b55b

Browse files
authored
[MISC] Fix OSMesa software rendering pipeline on Windows CI. (Genesis-Embodied-AI#1418)
* Fix OSMesa software rendering on Windows CI. * More robust multisampling config. * Raise exception if using 'osmesa' PyOpenGL platform on Windows OS. * Prevent managing multiple scene concurrently if interactive viewer is enabled. * Enable OSMesa fallback on Linux.
1 parent a7483c7 commit 0d8b55b

File tree

8 files changed

+32
-19
lines changed

8 files changed

+32
-19
lines changed

.github/workflows/generic.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,11 @@ jobs:
5656
shell: bash
5757
run: |
5858
# FIXME: Updating to 25.1.0 breaks rendering regardless PYOPENGL_PLATFORM is set to osmesa or egl.
59-
curl -L -o mesa.7z https://github.com/pal1000/mesa-dist-win/releases/download/24.3.4/mesa3d-24.3.4-release-msvc.7z
59+
curl -L -o mesa.7z https://github.com/pal1000/mesa-dist-win/releases/download/23.3.3/mesa3d-23.3.3-release-msvc.7z
6060
7z x mesa.7z -omesa
6161
mv -v mesa/x64/* /C/Windows/System32/
6262
ls -alt /C/Windows/System32/opengl32.dll
6363
64-
echo "PYOPENGL_PLATFORM=osmesa" >> $GITHUB_ENV
65-
6664
- name: Install system dependencies (Linux)
6765
if: startsWith(matrix.OS, 'ubuntu-')
6866
run: |

genesis/ext/pyrender/offscreen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def _create(self, platform):
208208

209209
self._platform = OSMesaPlatform(self.viewport_width, self.viewport_height)
210210
else:
211-
raise ValueError("Unsupported PyOpenGL platform: {}".format(os.environ["PYOPENGL_PLATFORM"]))
211+
raise ValueError("Unsupported PyOpenGL platform: {}".format(platform))
212212
self._platform.init_context()
213213
self._platform.make_current()
214214

genesis/ext/pyrender/renderer.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,12 +1198,15 @@ def _configure_main_framebuffer(self):
11981198
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, self._main_db)
11991199

12001200
# Generate multisample buffer
1201+
num_samples = min(glGetIntegerv(GL_MAX_SAMPLES), 4)
12011202
self._main_cb_ms, self._main_db_ms = glGenRenderbuffers(2)
12021203
glBindRenderbuffer(GL_RENDERBUFFER, self._main_cb_ms)
1203-
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA, self.viewport_width, self.viewport_height)
1204+
glRenderbufferStorageMultisample(
1205+
GL_RENDERBUFFER, num_samples, GL_RGBA, self.viewport_width, self.viewport_height
1206+
)
12041207
glBindRenderbuffer(GL_RENDERBUFFER, self._main_db_ms)
12051208
glRenderbufferStorageMultisample(
1206-
GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT24, self.viewport_width, self.viewport_height
1209+
GL_RENDERBUFFER, num_samples, GL_DEPTH_COMPONENT24, self.viewport_width, self.viewport_height
12071210
)
12081211
self._main_fb_ms = glGenFramebuffers(1)
12091212
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self._main_fb_ms)

genesis/options/vis.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ class ViewerOptions(Options):
1717
----------
1818
res : tuple, shape (2,), optional
1919
The resolution of the viewer. If not set, will auto-compute using resolution of the connected display.
20-
run_in_thread: bool
21-
Whether to run the viewer in a background thread. This option is not supported on MacOS. True by default if available.
20+
run_in_thread : bool
21+
Whether to run the viewer in a background thread. This option is not supported on MacOS. True by default if
22+
available.
2223
refresh_rate : int
2324
The refresh rate of the viewer.
2425
max_FPS : int | None
25-
The FPS (frames per second) the viewer will be capped at. Note that this will also synchronize the simulation speed. If not set, the viewer will render at maximum speed.
26+
The FPS (frames per second) the viewer will be capped at. Note that this will also synchronize the simulation
27+
speed. If not set, the viewer will render at maximum speed.
2628
camera_pos : tuple of float, shape (3,)
2729
The position of the viewer's camera.
2830
camera_lookat : tuple of float, shape (3,)

genesis/vis/rasterizer.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import os
21
import gc
2+
import os
3+
import sys
34

45
import numpy as np
56

@@ -26,6 +27,8 @@ def build(self):
2627
if self._offscreen:
2728
# if environment variable is set, use the platform specified, otherwise some platform-specific default
2829
platform = os.environ.get("PYOPENGL_PLATFORM", "egl" if gs.platform == "Linux" else "pyglet")
30+
if sys.platform == "win32" and platform == "osmesa":
31+
gs.raise_exception("PYOPENGL_PLATFORM='osmesa' is not supported on Windows OS.")
2932
self._renderer = pyrender.OffscreenRenderer(
3033
pyopengl_platform=platform, seg_node_map=self._context.seg_node_map
3134
)

genesis/vis/viewer.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,14 @@ def build(self, scene):
6565
if opengl_platform_orig is None:
6666
if gs.platform == "Windows":
6767
all_opengl_platforms = ("wgl",) # same as "native"
68+
elif gs.platform == "Linux":
69+
# "native" is platform-specific ("egl" or "glx")
70+
all_opengl_platforms = ("native", "egl", "glx", "osmesa")
6871
else:
69-
all_opengl_platforms = ("native", "egl", "glx") # "native" is platform-specific ("egl" or "glx")
72+
all_opengl_platforms = ("native",)
7073
else:
74+
if gs.platform == "Windows" and opengl_platform_orig == "osmesa":
75+
gs.raise_exception("PYOPENGL_PLATFORM='osmesa' is not supported on Windows OS.")
7176
all_opengl_platforms = (opengl_platform_orig,)
7277

7378
for i, platform in enumerate(all_opengl_platforms):
@@ -108,11 +113,10 @@ def build(self, scene):
108113

109114
if i == len(all_opengl_platforms) - 1:
110115
raise
111-
finally:
112-
if opengl_platform_orig is None:
113-
del os.environ["PYOPENGL_PLATFORM"]
114-
else:
115-
os.environ["PYOPENGL_PLATFORM"] = opengl_platform_orig
116+
117+
# Select PyOpenGL backend compatible with `pyrender.OffscreenRenderer`
118+
if platform not in ("osmesa", "pyglet", "egl"):
119+
os.environ["PYOPENGL_PLATFORM"] = "pyglet"
116120

117121
self.lock = ViewerLock(self._pyrender_viewer)
118122

genesis/vis/visualizer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ def __init__(self, scene, show_viewer, vis_options, viewer_options, renderer):
6060
self._connected_to_display = False
6161

6262
if show_viewer:
63+
if gs.global_scene_list:
64+
raise gs.raise_exception(
65+
"Interactive viewer not supported when managing multiple scenes. Please set `show_viewer=False` "
66+
"or call `scene.destroy`."
67+
)
68+
6369
if viewer_options.res is None:
6470
viewer_height = (screen.height * scale) * VIEWER_DEFAULT_HEIGHT_RATIO
6571
viewer_width = viewer_height / VIEWER_DEFAULT_ASPECT_RATIO

tests/test_render.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
@pytest.mark.required
1414
@pytest.mark.parametrize("segmentation_level", ["entity", "link"])
1515
@pytest.mark.parametrize("particle_mode", ["visual", "particle"])
16-
@pytest.mark.xfail(reason="This test is not passing on all platforms for now.")
1716
def test_segmentation(segmentation_level, particle_mode):
1817
"""Test segmentation rendering."""
1918
scene = gs.Scene(
@@ -87,7 +86,6 @@ def test_segmentation(segmentation_level, particle_mode):
8786

8887
@pytest.mark.required
8988
@pytest.mark.skipif(sys.platform == "darwin", reason="Segfault inside 'shadow_mapping_pass' on MacOS VM.")
90-
@pytest.mark.xfail(reason="This test is not passing on all platforms for now.")
9189
def test_batched_offscreen_rendering(show_viewer, tol):
9290
scene = gs.Scene(
9391
vis_options=gs.options.VisOptions(
@@ -243,7 +241,6 @@ def test_batched_offscreen_rendering(show_viewer, tol):
243241

244242
@pytest.mark.required
245243
@pytest.mark.skipif(sys.platform == "darwin", reason="Segfault inside 'shadow_mapping_pass' on MacOS VM.")
246-
@pytest.mark.xfail(reason="This test is not passing on all platforms for now.")
247244
def test_batched_mounted_camera_rendering(show_viewer, tol):
248245
scene = gs.Scene(
249246
vis_options=gs.options.VisOptions(

0 commit comments

Comments
 (0)