OpenMotionLab/MotionGPT
118
1import ctypes2import os3 4import OpenGL.platform5 6from .base import Platform7 8EGL_PLATFORM_DEVICE_EXT = 0x313F9EGL_DRM_DEVICE_FILE_EXT = 0x323310 11 12def _ensure_egl_loaded():13 plugin = OpenGL.platform.PlatformPlugin.by_name('egl')14 if plugin is None:15 raise RuntimeError("EGL platform plugin is not available.")16 17 plugin_class = plugin.load()18 plugin.loaded = True19 # create instance of this platform implementation20 plugin = plugin_class()21 22 plugin.install(vars(OpenGL.platform))23 24 25_ensure_egl_loaded()26from OpenGL import EGL as egl27 28 29def _get_egl_func(func_name, res_type, *arg_types):30 address = egl.eglGetProcAddress(func_name)31 if address is None:32 return None33 34 proto = ctypes.CFUNCTYPE(res_type)35 proto.argtypes = arg_types36 func = proto(address)37 return func38 39 40def _get_egl_struct(struct_name):41 from OpenGL._opaque import opaque_pointer_cls42 return opaque_pointer_cls(struct_name)43 44 45# These are not defined in PyOpenGL by default.46_EGLDeviceEXT = _get_egl_struct('EGLDeviceEXT')47_eglGetPlatformDisplayEXT = _get_egl_func('eglGetPlatformDisplayEXT', egl.EGLDisplay)48_eglQueryDevicesEXT = _get_egl_func('eglQueryDevicesEXT', egl.EGLBoolean)49_eglQueryDeviceStringEXT = _get_egl_func('eglQueryDeviceStringEXT', ctypes.c_char_p)50 51 52def query_devices():53 if _eglQueryDevicesEXT is None:54 raise RuntimeError("EGL query extension is not loaded or is not supported.")55 56 num_devices = egl.EGLint()57 success = _eglQueryDevicesEXT(0, None, ctypes.pointer(num_devices))58 if not success or num_devices.value < 1:59 return []60 61 devices = (_EGLDeviceEXT * num_devices.value)() # array of size num_devices62 success = _eglQueryDevicesEXT(num_devices.value, devices, ctypes.pointer(num_devices))63 if not success or num_devices.value < 1:64 return []65 66 return [EGLDevice(devices[i]) for i in range(num_devices.value)]67 68 69def get_default_device():70 # Fall back to not using query extension.71 if _eglQueryDevicesEXT is None:72 return EGLDevice(None)73 74 return query_devices()[0]75 76 77def get_device_by_index(device_id):78 if _eglQueryDevicesEXT is None and device_id == 0:79 return get_default_device()80 81 devices = query_devices()82 if device_id >= len(devices):83 raise ValueError('Invalid device ID ({})'.format(device_id, len(devices)))84 return devices[device_id]85 86 87class EGLDevice:88 89 def __init__(self, display=None):90 self._display = display91 92 def get_display(self):93 if self._display is None:94 return egl.eglGetDisplay(egl.EGL_DEFAULT_DISPLAY)95 96 return _eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, self._display, None)97 98 @property99 def name(self):100 if self._display is None:101 return 'default'102 103 name = _eglQueryDeviceStringEXT(self._display, EGL_DRM_DEVICE_FILE_EXT)104 if name is None:105 return None106 107 return name.decode('ascii')108 109 def __repr__(self):110 return "<EGLDevice(name={})>".format(self.name)111 112 113class EGLPlatform(Platform):114 """Renders using EGL.115 """116 117 def __init__(self, viewport_width, viewport_height, device: EGLDevice = None):118 super(EGLPlatform, self).__init__(viewport_width, viewport_height)119 if device is None:120 device = get_default_device()121 122 self._egl_device = device123 self._egl_display = None124 self._egl_context = None125 126 def init_context(self):127 _ensure_egl_loaded()128 129 from OpenGL.EGL import (130 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_BLUE_SIZE,131 EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_DEPTH_SIZE,132 EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,133 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_CONFORMANT,134 EGL_NONE, EGL_DEFAULT_DISPLAY, EGL_NO_CONTEXT,135 EGL_OPENGL_API, EGL_CONTEXT_MAJOR_VERSION,136 EGL_CONTEXT_MINOR_VERSION,137 EGL_CONTEXT_OPENGL_PROFILE_MASK,138 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,139 eglGetDisplay, eglInitialize, eglChooseConfig,140 eglBindAPI, eglCreateContext, EGLConfig141 )142 from OpenGL import arrays143 144 config_attributes = arrays.GLintArray.asArray([145 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,146 EGL_BLUE_SIZE, 8,147 EGL_RED_SIZE, 8,148 EGL_GREEN_SIZE, 8,149 EGL_DEPTH_SIZE, 24,150 EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,151 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,152 EGL_CONFORMANT, EGL_OPENGL_BIT,153 EGL_NONE154 ])155 context_attributes = arrays.GLintArray.asArray([156 EGL_CONTEXT_MAJOR_VERSION, 4,157 EGL_CONTEXT_MINOR_VERSION, 1,158 EGL_CONTEXT_OPENGL_PROFILE_MASK,159 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,160 EGL_NONE161 ])162 major, minor = ctypes.c_long(), ctypes.c_long()163 num_configs = ctypes.c_long()164 configs = (EGLConfig * 1)()165 166 # Cache DISPLAY if necessary and get an off-screen EGL display167 orig_dpy = None168 if 'DISPLAY' in os.environ:169 orig_dpy = os.environ['DISPLAY']170 del os.environ['DISPLAY']171 172 self._egl_display = self._egl_device.get_display()173 if orig_dpy is not None:174 os.environ['DISPLAY'] = orig_dpy175 176 # Initialize EGL177 assert eglInitialize(self._egl_display, major, minor)178 assert eglChooseConfig(179 self._egl_display, config_attributes, configs, 1, num_configs180 )181 182 # Bind EGL to the OpenGL API183 assert eglBindAPI(EGL_OPENGL_API)184 185 # Create an EGL context186 self._egl_context = eglCreateContext(187 self._egl_display, configs[0],188 EGL_NO_CONTEXT, context_attributes189 )190 191 # Make it current192 self.make_current()193 194 def make_current(self):195 from OpenGL.EGL import eglMakeCurrent, EGL_NO_SURFACE196 assert eglMakeCurrent(197 self._egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,198 self._egl_context199 )200 201 def make_uncurrent(self):202 """Make the OpenGL context uncurrent.203 """204 pass205 206 def delete_context(self):207 from OpenGL.EGL import eglDestroyContext, eglTerminate208 if self._egl_display is not None:209 if self._egl_context is not None:210 eglDestroyContext(self._egl_display, self._egl_context)211 self._egl_context = None212 eglTerminate(self._egl_display)213 self._egl_display = None214 215 def supports_framebuffers(self):216 return True217 218 219__all__ = ['EGLPlatform']220 