mujoco_py/opengl_context.pyx (102 lines of code) (raw):
import os
import sys
from abc import ABCMeta, abstractmethod
from mujoco_py.utils import discover_mujoco
def _add_mujoco_bin_to_dyld_library_path():
mujoco_path = discover_mujoco()
bin_path = os.path.join(mujoco_path, "bin")
old_dyld_library_path = os.getenv("DYLD_LIBRARY_PATH", "")
os.environ["DYLD_LIBRARY_PATH"] = "{}:{}".format(
bin_path, old_dyld_library_path)
try:
_add_mujoco_bin_to_dyld_library_path()
import glfw
except ImportError:
pass
class OpenGLContext(metaclass=ABCMeta):
@abstractmethod
def make_context_current(self):
raise NotImplementedError()
@abstractmethod
def set_buffer_size(self, width, height):
raise NotImplementedError()
class GlfwError(RuntimeError):
pass
class GlfwContext(OpenGLContext):
_INIT_WIDTH = 1000
_INIT_HEIGHT = 1000
_GLFW_IS_INITIALIZED = False
def __init__(self, offscreen=False, quiet=False):
GlfwContext._init_glfw()
self._width = self._INIT_WIDTH
self._height = self._INIT_HEIGHT
self.window = self._create_window(offscreen, quiet=quiet)
self._set_window_size(self._width, self._height)
@staticmethod
def _init_glfw():
if GlfwContext._GLFW_IS_INITIALIZED:
return
if 'glfw' not in globals():
raise GlfwError("GLFW not installed")
glfw.set_error_callback(GlfwContext._glfw_error_callback)
# HAX: sometimes first init() fails, while second works fine.
glfw.init()
if not glfw.init():
raise GlfwError("Failed to initialize GLFW")
GlfwContext._GLFW_IS_INITIALIZED = True
def make_context_current(self):
glfw.make_context_current(self.window)
def set_buffer_size(self, width, height):
self._set_window_size(width, height)
self._width = width
self._height = height
def _create_window(self, offscreen, quiet=False):
if offscreen:
if not quiet:
print("Creating offscreen glfw")
glfw.window_hint(glfw.VISIBLE, 0)
glfw.window_hint(glfw.DOUBLEBUFFER, 0)
init_width, init_height = self._INIT_WIDTH, self._INIT_HEIGHT
else:
if not quiet:
print("Creating window glfw")
glfw.window_hint(glfw.SAMPLES, 4)
glfw.window_hint(glfw.VISIBLE, 1)
glfw.window_hint(glfw.DOUBLEBUFFER, 1)
resolution, _, refresh_rate = glfw.get_video_mode(
glfw.get_primary_monitor())
init_width, init_height = resolution
self._width = init_width
self._height = init_height
window = glfw.create_window(
self._width, self._height, "mujoco_py", None, None)
if not window:
raise GlfwError("Failed to create GLFW window")
return window
def get_buffer_size(self):
return glfw.get_framebuffer_size(self.window)
def _set_window_size(self, target_width, target_height):
self.make_context_current()
if target_width != self._width or target_height != self._height:
self._width = target_width
self._height = target_height
glfw.set_window_size(self.window, target_width, target_height)
# HAX: When running on a Mac with retina screen, the size
# sometimes doubles
width, height = glfw.get_framebuffer_size(self.window)
if target_width != width and "darwin" in sys.platform.lower():
glfw.set_window_size(self.window, target_width // 2, target_height // 2)
@staticmethod
def _glfw_error_callback(error_code, description):
print("GLFW error (code %d): %s", error_code, description)
class OffscreenOpenGLContext():
def __init__(self, device_id):
self.device_id = device_id
res = initOpenGL(device_id)
if res != 1:
raise RuntimeError("Failed to initialize OpenGL")
def close(self):
# TODO: properly close OpenGL in our contexts
closeOpenGL()
def make_context_current(self):
makeOpenGLContextCurrent(self.device_id)
def set_buffer_size(self, int width, int height):
res = setOpenGLBufferSize(self.device_id, width, height)
if res != 1:
raise RuntimeError("Failed to set buffer size")