1from __future__ import print_function 2import os, logging, pprint 3 4log = logging.getLogger(__name__) 5if not os.environ.get("PYOPENGL_PLATFORM"): 6 os.environ["PYOPENGL_PLATFORM"] = "egl" 7if "DISPLAY" in os.environ: 8 del os.environ["DISPLAY"] 9import logging, contextlib 10from functools import wraps 11 12# from OpenGL.GL import * 13from OpenGL.EGL import * 14from OpenGL.EGL import debug 15from OpenGL import arrays 16from OpenGL.EGL import gbmdevice 17from OpenGL.EGL.MESA import platform_gbm 18from OpenGL.EGL.EXT import platform_device, platform_base, device_base 19 20API_MAP = { 21 EGL_OPENGL_BIT: EGL_OPENGL_API, 22 EGL_OPENGL_ES2_BIT: EGL_OPENGL_ES_API, 23 EGL_OPENGL_ES_BIT: EGL_OPENGL_ES_API, 24} 25 26 27def platformDisplay(device): 28 """Get platform display from device specifier 29 30 device -- EGLDeviceEXT, gbm card* path, or gbm card* ordinal (index) 31 32 returns display, created_device (or None if passed in) 33 raises RuntimeError if we can't create the display 34 """ 35 created_device = display = None 36 if isinstance(device, (str, int)): 37 created_device = device = gbmdevice.open_device(device) 38 if eglGetPlatformDisplay: 39 display = eglGetPlatformDisplay( 40 platform_device.EGL_PLATFORM_DEVICE_EXT 41 if isinstance(device, EGLDeviceEXT) 42 else platform_gbm.EGL_PLATFORM_GBM_MESA, 43 device, 44 ctypes.c_void_p(0), 45 ) 46 if display == EGL_NO_DISPLAY: 47 raise RuntimeError("Unable to create EGL display on %s" % (display)) 48 else: 49 raise RuntimeError("eglGetPlatformDisplay has no implementation") 50 if not created_device: 51 try: 52 name = get_device_name(device) 53 if name is not None: 54 log.debug("DRM Name: %s", name) 55 except EGLError: 56 log.debug("Unable to retrieve the DRM name") 57 return display, created_device 58 59 60def gbmPlatformSurface(display, config, platform_device, width, height): 61 """Create a GBM platform surface for display with config on platform_device 62 63 returns egl_surface, gbm_surface 64 """ 65 visual = EGLint() 66 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, visual) 67 platform_surface = gbmdevice.create_surface( 68 platform_device, 69 width, 70 height, 71 format=visual.value, 72 flags=gbmdevice.GBM_BO_USE_RENDERING, 73 ) 74 if not platform_surface: 75 raise RuntimeError("Unable to allocate a gbm surface") 76 surface = eglCreatePlatformWindowSurface(display, config, platform_surface, None) 77 if surface == EGL_NO_SURFACE: 78 log.error("Failed to create the EGL surface on the GBM surface") 79 raise RuntimeError("Platform window surface creation failure") 80 return surface, platform_surface 81 82 83def choose_config(display, attributes): 84 """utility to choose config for the display based on attributes""" 85 num_configs = EGLint() 86 configs = (EGLConfig * 1)() 87 local_attributes = arrays.GLintArray.asArray(attributes) 88 success = eglChooseConfig(display, local_attributes, configs, 1, num_configs) 89 if not success: 90 raise NoConfig("Unable to complete config filtering", attributes) 91 if not num_configs: 92 raise NoConfig( 93 "No compatible configs found", attributes, 94 ) 95 return configs[0] 96 97 98@contextlib.contextmanager 99def egl_context( 100 width=256, 101 height=256, 102 api=EGL_OPENGL_BIT, 103 attributes=( 104 EGL_BLUE_SIZE, 105 8, 106 EGL_RED_SIZE, 107 8, 108 EGL_GREEN_SIZE, 109 8, 110 EGL_DEPTH_SIZE, 111 24, 112 EGL_COLOR_BUFFER_TYPE, 113 EGL_RGB_BUFFER, 114 # EGL_CONFIG_CAVEAT, EGL_NONE, # Don't allow slow/non-conformant 115 ), 116 pbuffer=False, 117 device=None, 118 output="output.ppm", 119): 120 """Setup a context for rendering""" 121 major, minor = EGLint(), EGLint() 122 created_device = platform_surface = surface = None 123 if device is None: 124 display = eglGetDisplay(EGL_DEFAULT_DISPLAY) 125 if display == EGL_NO_DISPLAY: 126 raise RuntimeError(EGL_NO_DISPLAY, "Could not create default display") 127 else: 128 display, created_device = platformDisplay(device) 129 try: 130 # print("Display: %s"%(display.address,)) 131 try: 132 eglInitialize(display, major, minor) 133 except EGLError as err: 134 log.warning("eglInitilise failure on %s: %s", display, err.err) 135 raise NoEGLSupport(display) 136 log.debug( 137 "Available configs:\n%s", 138 debug.format_debug_configs(debug.debug_configs(display)), 139 ) 140 141 # for config in configs[:num_configs.value]: 142 # log.debug("Config: %s",pprint.pformat(debug.debug_config(display,config))) 143 local_attributes = list(attributes[:]) 144 if pbuffer: 145 local_attributes.extend( 146 [EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,] 147 ) 148 else: 149 local_attributes.extend( 150 [EGL_SURFACE_TYPE, EGL_WINDOW_BIT,] 151 ) 152 local_attributes.extend( 153 [EGL_CONFORMANT, api, EGL_NONE,] # end of list 154 ) 155 config = choose_config(display, local_attributes,) 156 log.debug( 157 "Selected config:\n%s", 158 debug.format_debug_configs(debug.debug_configs(display, configs=[config])), 159 ) 160 surface_attributes = [ 161 EGL_WIDTH, 162 width, 163 EGL_HEIGHT, 164 height, 165 EGL_NONE, 166 ] 167 if pbuffer: 168 surface = eglCreatePbufferSurface(display, config, surface_attributes,) 169 else: 170 surface, platform_surface = gbmPlatformSurface( 171 display, config, created_device, width, height 172 ) 173 eglBindAPI(API_MAP[api]) 174 ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, None) 175 if ctx == EGL_NO_CONTEXT: 176 raise RuntimeError("Unable to create context") 177 eglMakeCurrent(display, surface, surface, ctx) 178 yield display, ctx, surface 179 if output: 180 log.debug("Doing readpixels for writing buffer") 181 from OpenGL import arrays 182 183 content = arrays.GLubyteArray.zeros((width, height, 3)) 184 if api == EGL_OPENGL_BIT: 185 from OpenGL.GL import glReadPixels, GL_UNSIGNED_BYTE, GL_RGB 186 elif api == EGL_OPENGL_ES3_BIT: 187 from OpenGL.GLES3 import glReadPixels, GL_UNSIGNED_BYTE, GL_RGB 188 elif api == EGL_OPENGL_ES2_BIT: 189 from OpenGL.GLES2 import glReadPixels, GL_UNSIGNED_BYTE, GL_RGB 190 elif api == EGL_OPENGL_ES_BIT: 191 from OpenGL.GLES1 import glReadPixels, GL_UNSIGNED_BYTE, GL_RGB 192 content = glReadPixels( 193 0, 0, width, height, GL_RGB, type=GL_UNSIGNED_BYTE, array=content 194 ) 195 196 debug.write_ppm(content, output) 197 # glFinish() 198 finally: 199 if display: 200 eglMakeCurrent(display, None, None, None) 201 if surface: 202 eglDestroySurface(display, surface) 203 eglTerminate(display) 204 if platform_surface: 205 gbmdevice.gbm.gbm_surface_destroy(platform_surface) 206 if created_device: 207 gbmdevice.close_device(created_device) 208 209 210class NoEGLSupport(Exception): 211 """Raised if we could not initialise an egl context""" 212 213 214class NoConfig(Exception): 215 """Raised if we did not find any configs""" 216 217 218def debug_info(setup): 219 from OpenGL.GL import ( 220 glClearColor, 221 glClear, 222 GL_COLOR_BUFFER_BIT, 223 GL_DEPTH_BUFFER_BIT, 224 glGetString, 225 GL_VENDOR, 226 GL_EXTENSIONS, 227 glFinish, 228 ) 229 230 display, ctx, surface = setup 231 glClearColor(1.0, 1.0, 1.0, 1.0) 232 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 233 log.info("Vendor: %s", glGetString(GL_VENDOR)) 234 log.info("Extensions: %s", glGetString(GL_EXTENSIONS)) 235 glFinish() 236 237def get_device_name(device): 238 """Try to get the display's DRM device name 239 240 This is almost certainly not going to work on 241 anything other than Linux 242 """ 243 from OpenGL.EGL.EXT.device_query import ( 244 eglQueryDeviceStringEXT, 245 ) 246 from OpenGL.EGL.EXT.device_drm import ( 247 EGL_DRM_DEVICE_FILE_EXT, 248 ) 249 if eglQueryDeviceStringEXT: 250 name = eglQueryDeviceStringEXT( 251 device, 252 EGL_DRM_DEVICE_FILE_EXT 253 ) 254 return name.decode('ascii',errors='ignore') 255 return None 256 257 258def main(): 259 # NOTE: having two different implementations here is 260 # likely somewhat broken due to the 261 # OpenGL functions having retrieved their 262 # function pointers during the first pass and then 263 # trying to run them against the second 264 for device in sorted(device_base.egl_get_devices(), key=lambda x: x.address): 265 log.info("Starting tests with: %s", device) 266 try: 267 with egl_context(device=device, pbuffer=True) as setup: 268 debug_info(setup) 269 except (NoEGLSupport, NoConfig) as err: 270 log.info("Cannot configure: %s", err) 271 except (EGLError, RuntimeError): 272 log.exception("Failed during: %s", device) 273 for device in gbmdevice.enumerate_devices(): 274 log.info("Starting tests with: %s", device) 275 try: 276 with egl_context(device=device, pbuffer=False) as setup: 277 debug_info(setup) 278 except (NoEGLSupport, NoConfig) as err: 279 log.info("Cannot configure: %s", err) 280 except (EGLError, RuntimeError): 281 log.exception("Failed during: %s", device) 282 283 284if __name__ == "__main__": 285 logging.basicConfig(level=logging.DEBUG) 286 main() 287