import ctypes import os import OpenGL.platform from .base import Platform EGL_PLATFORM_DEVICE_EXT = 0x313F EGL_DRM_DEVICE_FILE_EXT = 0x3233 def _ensure_egl_loaded(): plugin = OpenGL.platform.PlatformPlugin.by_name('egl') if plugin is None: raise RuntimeError("EGL platform plugin is not available.") plugin_class = plugin.load() plugin.loaded = True # create instance of this platform implementation plugin = plugin_class() plugin.install(vars(OpenGL.platform)) _ensure_egl_loaded() from OpenGL import EGL as egl def _get_egl_func(func_name, res_type, *arg_types): address = egl.eglGetProcAddress(func_name) if address is None: return None proto = ctypes.CFUNCTYPE(res_type) proto.argtypes = arg_types func = proto(address) return func def _get_egl_struct(struct_name): from OpenGL._opaque import opaque_pointer_cls return opaque_pointer_cls(struct_name) # These are not defined in PyOpenGL by default. _EGLDeviceEXT = _get_egl_struct('EGLDeviceEXT') _eglGetPlatformDisplayEXT = _get_egl_func('eglGetPlatformDisplayEXT', egl.EGLDisplay) _eglQueryDevicesEXT = _get_egl_func('eglQueryDevicesEXT', egl.EGLBoolean) _eglQueryDeviceStringEXT = _get_egl_func('eglQueryDeviceStringEXT', ctypes.c_char_p) def query_devices(): if _eglQueryDevicesEXT is None: raise RuntimeError("EGL query extension is not loaded or is not supported.") num_devices = egl.EGLint() success = _eglQueryDevicesEXT(0, None, ctypes.pointer(num_devices)) if not success or num_devices.value < 1: return [] devices = (_EGLDeviceEXT * num_devices.value)() # array of size num_devices success = _eglQueryDevicesEXT(num_devices.value, devices, ctypes.pointer(num_devices)) if not success or num_devices.value < 1: return [] return [EGLDevice(devices[i]) for i in range(num_devices.value)] def get_default_device(): # Fall back to not using query extension. if _eglQueryDevicesEXT is None: return EGLDevice(None) return query_devices()[0] def get_device_by_index(device_id): if _eglQueryDevicesEXT is None and device_id == 0: return get_default_device() devices = query_devices() if device_id >= len(devices): raise ValueError('Invalid device ID ({})'.format(device_id, len(devices))) return devices[device_id] class EGLDevice: def __init__(self, display=None): self._display = display def get_display(self): if self._display is None: return egl.eglGetDisplay(egl.EGL_DEFAULT_DISPLAY) return _eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, self._display, None) @property def name(self): if self._display is None: return 'default' name = _eglQueryDeviceStringEXT(self._display, EGL_DRM_DEVICE_FILE_EXT) if name is None: return None return name.decode('ascii') def __repr__(self): return "".format(self.name) class EGLPlatform(Platform): """Renders using EGL. """ def __init__(self, viewport_width, viewport_height, device: EGLDevice = None): super(EGLPlatform, self).__init__(viewport_width, viewport_height) if device is None: device = get_default_device() self._egl_device = device self._egl_display = None self._egl_context = None def init_context(self): _ensure_egl_loaded() from OpenGL.EGL import ( EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_BLUE_SIZE, EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_DEPTH_SIZE, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_CONFORMANT, EGL_NONE, EGL_DEFAULT_DISPLAY, EGL_NO_CONTEXT, EGL_OPENGL_API, EGL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_MINOR_VERSION, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, eglGetDisplay, eglInitialize, eglChooseConfig, eglBindAPI, eglCreateContext, EGLConfig ) from OpenGL import arrays config_attributes = arrays.GLintArray.asArray([ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_BLUE_SIZE, 8, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_CONFORMANT, EGL_OPENGL_BIT, EGL_NONE ]) context_attributes = arrays.GLintArray.asArray([ EGL_CONTEXT_MAJOR_VERSION, 4, EGL_CONTEXT_MINOR_VERSION, 1, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, EGL_NONE ]) major, minor = ctypes.c_long(), ctypes.c_long() num_configs = ctypes.c_long() configs = (EGLConfig * 1)() # Cache DISPLAY if necessary and get an off-screen EGL display orig_dpy = None if 'DISPLAY' in os.environ: orig_dpy = os.environ['DISPLAY'] del os.environ['DISPLAY'] self._egl_display = self._egl_device.get_display() if orig_dpy is not None: os.environ['DISPLAY'] = orig_dpy # Initialize EGL assert eglInitialize(self._egl_display, major, minor) assert eglChooseConfig( self._egl_display, config_attributes, configs, 1, num_configs ) # Bind EGL to the OpenGL API assert eglBindAPI(EGL_OPENGL_API) # Create an EGL context self._egl_context = eglCreateContext( self._egl_display, configs[0], EGL_NO_CONTEXT, context_attributes ) # Make it current self.make_current() def make_current(self): from OpenGL.EGL import eglMakeCurrent, EGL_NO_SURFACE assert eglMakeCurrent( self._egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, self._egl_context ) def make_uncurrent(self): """Make the OpenGL context uncurrent. """ pass def delete_context(self): from OpenGL.EGL import eglDestroyContext, eglTerminate if self._egl_display is not None: if self._egl_context is not None: eglDestroyContext(self._egl_display, self._egl_context) self._egl_context = None eglTerminate(self._egl_display) self._egl_display = None def supports_framebuffers(self): return True __all__ = ['EGLPlatform']