|
"""Headless GPU-accelerated OpenGL context creation on Google Colaboratory. |
|
|
|
Typical usage: |
|
|
|
# Optional PyOpenGL configuratiopn can be done here. |
|
# import OpenGL |
|
# OpenGL.ERROR_CHECKING = True |
|
|
|
# 'glcontext' must be imported before any OpenGL.* API. |
|
from lucid.misc.gl.glcontext import create_opengl_context |
|
|
|
# Now it's safe to import OpenGL and EGL functions |
|
import OpenGL.GL as gl |
|
|
|
# create_opengl_context() creates a GL context that is attached to an |
|
# offscreen surface of the specified size. Note that rendering to buffers |
|
# of other sizes and formats is still possible with OpenGL Framebuffers. |
|
# |
|
# Users are expected to directly use the EGL API in case more advanced |
|
# context management is required. |
|
width, height = 640, 480 |
|
create_opengl_context((width, height)) |
|
|
|
# OpenGL context is available here. |
|
|
|
""" |
|
|
|
from __future__ import print_function |
|
|
|
|
|
|
|
try: |
|
import OpenGL |
|
except: |
|
print('This module depends on PyOpenGL.') |
|
print('Please run "\033[1m!pip install -q pyopengl\033[0m" ' |
|
'prior importing this module.') |
|
raise |
|
|
|
import ctypes |
|
from ctypes import pointer, util |
|
import os |
|
|
|
os.environ['PYOPENGL_PLATFORM'] = 'egl' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_find_library_old = ctypes.util.find_library |
|
try: |
|
|
|
def _find_library_new(name): |
|
return { |
|
'GL': 'libOpenGL.so', |
|
'EGL': 'libEGL.so', |
|
}.get(name, _find_library_old(name)) |
|
|
|
util.find_library = _find_library_new |
|
import OpenGL.GL as gl |
|
import OpenGL.EGL as egl |
|
except: |
|
print('Unable to load OpenGL libraries. ' |
|
'Make sure you use GPU-enabled backend.') |
|
print('Press "Runtime->Change runtime type" and set ' |
|
'"Hardware accelerator" to GPU.') |
|
raise |
|
finally: |
|
util.find_library = _find_library_old |
|
|
|
|
|
def create_opengl_context(surface_size=(640, 480)): |
|
"""Create offscreen OpenGL context and make it current. |
|
|
|
Users are expected to directly use EGL API in case more advanced |
|
context management is required. |
|
|
|
Args: |
|
surface_size: (width, height), size of the offscreen rendering surface. |
|
""" |
|
egl_display = egl.eglGetDisplay(egl.EGL_DEFAULT_DISPLAY) |
|
|
|
major, minor = egl.EGLint(), egl.EGLint() |
|
egl.eglInitialize(egl_display, pointer(major), pointer(minor)) |
|
|
|
config_attribs = [ |
|
egl.EGL_SURFACE_TYPE, egl.EGL_PBUFFER_BIT, egl.EGL_BLUE_SIZE, 8, |
|
egl.EGL_GREEN_SIZE, 8, egl.EGL_RED_SIZE, 8, egl.EGL_DEPTH_SIZE, 24, |
|
egl.EGL_RENDERABLE_TYPE, egl.EGL_OPENGL_BIT, egl.EGL_NONE |
|
] |
|
config_attribs = (egl.EGLint * len(config_attribs))(*config_attribs) |
|
|
|
num_configs = egl.EGLint() |
|
egl_cfg = egl.EGLConfig() |
|
egl.eglChooseConfig(egl_display, config_attribs, pointer(egl_cfg), 1, |
|
pointer(num_configs)) |
|
|
|
width, height = surface_size |
|
pbuffer_attribs = [ |
|
egl.EGL_WIDTH, |
|
width, |
|
egl.EGL_HEIGHT, |
|
height, |
|
egl.EGL_NONE, |
|
] |
|
pbuffer_attribs = (egl.EGLint * len(pbuffer_attribs))(*pbuffer_attribs) |
|
egl_surf = egl.eglCreatePbufferSurface(egl_display, egl_cfg, |
|
pbuffer_attribs) |
|
|
|
egl.eglBindAPI(egl.EGL_OPENGL_API) |
|
|
|
context_attribs = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
egl_context = egl.eglCreateContext(egl_display, egl_cfg, |
|
egl.EGL_NO_CONTEXT, context_attribs) |
|
egl.eglMakeCurrent(egl_display, egl_surf, egl_surf, egl_context) |
|
|
|
buffer_type = egl.EGLint() |
|
out = egl.eglQueryContext(egl_display, egl_context, |
|
egl.EGL_CONTEXT_CLIENT_VERSION, buffer_type) |
|
|
|
|