PyOpenGL
lastmod 2025-02-14created 2024-02-2918 edits
PyOpenGL is the most common cross platform Python binding to OpenGL and related APIs. The binding is created using the standard ctypes library, and is provided under an extremely liberal BSD-style Open-Source license.
Categories
PyOpenGL_accelerate
| INFORMATION |
| Note that PyOpenGL_accelerate is fully compatible with PyOpenGL, so you get the performance improvement without modifying existing PyOpenGL code. |
PyOpenGL_accelerate can be turned ON/OFF with the USE_ACCELERATE environment variable.
The following is the content of the OpenGL/acceleratesupport.py file:
"""Common code for accelerated modules"""
import logging
from OpenGL import _configflags
needed_version = (3, 1, 6)
_log = logging.getLogger("OpenGL.acceleratesupport")
try:
import OpenGL_accelerate
if _configflags.USE_ACCELERATE:
if OpenGL_accelerate.__version_tuple__ < needed_version:
_log.warning(
"""Incompatible version of OpenGL_accelerate found, need at least %s found %s""",
needed_version,
OpenGL_accelerate.__version_tuple__,
)
raise ImportError("""Old version of OpenGL_accelerate""")
ACCELERATE_AVAILABLE = True
_log.debug("""OpenGL_accelerate module loaded""")
else:
raise ImportError("""Acceleration disabled""")
except ImportError as err:
_log.info("""No OpenGL_accelerate module loaded: %s""", err)
ACCELERATE_AVAILABLE = False
_configflags.USE_ACCELERATE is the code that reads the USE_ACCELERATE environment variable.
Environment Variables
-
PYOPENGL_ERROR_CHECKING = True -
PYOPENGL_ERROR_LOGGING = False -
PYOPENGL_ERROR_ON_COPY = False -
PYOPENGL_ARRAY_SIZE_CHECKING = True -
PYOPENGL_STORE_POINTERS = True -
PYOPENGL_USE_ACCELERATE = True- Whether to use PyOpenGL_accelerate -
PYOPENGL_CONTEXT_CHECKING = False -
PYOPENGL_FULL_LOGGING = False -
PYOPENGL_ALLOW_NUMPY_SCALARS = False -
PYOPENGL_UNSIGNED_BYTE_IMAGES_AS_STRING = True -
PYOPENGL_UNSIGNED_BYTE_IMAGES_AS_STRING = True -
PYOPENGL_PLATFORM = '...'- Specify the platform
Platforms
PlatformPlugin("nt", "OpenGL.platform.win32.Win32Platform")
PlatformPlugin("darwin", "OpenGL.platform.darwin.DarwinPlatform")
PlatformPlugin("linux2", "OpenGL.platform.glx.GLXPlatform")
PlatformPlugin("linux", "OpenGL.platform.glx.GLXPlatform")
PlatformPlugin("glx", "OpenGL.platform.glx.GLXPlatform")
PlatformPlugin("posix", "OpenGL.platform.glx.GLXPlatform")
PlatformPlugin("x11", "OpenGL.platform.glx.GLXPlatform") # xdg session type
PlatformPlugin("osmesa", "OpenGL.platform.osmesa.OSMesaPlatform")
PlatformPlugin("egl", "OpenGL.platform.egl.EGLPlatform")
PlatformPlugin("wayland", "OpenGL.platform.egl.EGLPlatform") # xdg session type
PlatformPlugin(
"xwayland", "OpenGL.platform.egl.EGLPlatform"
) # xdg session type, but use egl even though normally you'd expect GLX
You can call something like OpenGL.setPlatform('egl'), or set the PYOPENGL_PLATFORM environment variable.
Example
PyOpenGL_accelerate seems to be hardware acceleration.
Sample code:
import glfw
from OpenGL.GL import *
import OpenGL.GL.shaders
import numpy
def main():
# initialize glfw
if not glfw.init():
return
window = glfw.create_window(800, 600, "My OpenGL window", None, None)
if not window:
glfw.terminate()
return
glfw.make_context_current(window)
# positions colors
triangle = [-0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
0.0, 0.5, 0.0, 0.0, 0.0, 1.0]
triangle = numpy.array(triangle, dtype = numpy.float32)
vertex_shader = """
#version 330
in vec3 position;
in vec3 color;
out vec3 newColor;
void main()
{
gl_Position = vec4(position, 1.0f);
newColor = color;
}
"""
fragment_shader = """
#version 330
in vec3 newColor;
out vec4 outColor;
void main()
{
outColor = vec4(newColor, 1.0f);
}
"""
shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, 72, triangle, GL_STATIC_DRAW)
position = glGetAttribLocation(shader, "position")
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0))
glEnableVertexAttribArray(position)
color = glGetAttribLocation(shader, "color")
glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12))
glEnableVertexAttribArray(color)
glUseProgram(shader)
glClearColor(0.2, 0.3, 0.2, 1.0)
while not glfw.window_should_close(window):
glfw.poll_events()
glClear(GL_COLOR_BUFFER_BIT)
glDrawArrays(GL_TRIANGLES, 0, 3)
glfw.swap_buffers(window)
glfw.terminate()
if __name__ == "__main__":
main()
Rotating cube example
OpenGL with PyOpenGL introduction and creation of Rotating Cube
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 1),
(1, 1, 1),
(-1, -1, 1),
(-1, 1, 1)
)
edges = (
(0,1),
(0,3),
(0,4),
(2,1),
(2,3),
(2,7),
(6,3),
(6,4),
(6,7),
(5,1),
(5,4),
(5,7)
)
def Cube():
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0.0,0.0, -5)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glRotatef(1, 3, 1, 1)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
Cube()
pygame.display.flip()
pygame.time.wait(10)
main()
Drawing Object
Troubleshooting
__________________ ERROR collecting tester/test_entrypoint.py __________________
tester/test_entrypoint.py:8: in <module>
from ddrm.entrypoint import main as entrypoint_main
ddrm/entrypoint.py:8: in <module>
from ddrm.apps import run_app
ddrm/apps/__init__.py:21: in <module>
from ddrm.apps.player import Player
ddrm/apps/player/__init__.py:10: in <module>
from OpenGL import GL
/usr/local/lib/python3.11/site-packages/OpenGL/GL/__init__.py:4: in <module>
from OpenGL.GL.VERSION.GL_1_1 import *
/usr/local/lib/python3.11/site-packages/OpenGL/GL/VERSION/GL_1_1.py:14: in <module>
from OpenGL.raw.GL.VERSION.GL_1_1 import *
/usr/local/lib/python3.11/site-packages/OpenGL/raw/GL/VERSION/GL_1_1.py:7: in <module>
from OpenGL.raw.GL import _errors
/usr/local/lib/python3.11/site-packages/OpenGL/raw/GL/_errors.py:4: in <module>
_error_checker = _ErrorChecker( _p, _p.GL.glGetError )
E AttributeError: 'NoneType' object has no attribute 'glGetError'
Install libgl1-mesa-dev:
OpenGL.error.Error: Attempt to retrieve context when no valid context
When running under Wayland on Ubuntu 20.04 or later, the following error may be printed:
pygame-ce 2.4.1 (SDL 2.28.5, Python 3.11.4)
/home/your/Project/ddrm/test.py:13: Warning: PyGame seems to be running through X11 on top of wayland, instead of wayland directly
...
OpenGL.error.Error: Attempt to retrieve context when no valid context
Set the SDL_VIDEO_X11_FORCE_EGL=1 environment variable as follows:
numpy.dtype size changed, may indicate binary incompatibility
('numpy.dtype size changed, may indicate binary incompatibility. Expected 96 from C header, got 88 from PyObject', 1, <OpenGL.platform.baseplatform.glGenTextures object at 0x72b5e17db840>)
Traceback (most recent call last):
File "/home/your/Project/ddrm/ddrm/apps/__init__.py", line 96, in run_app
app.start()
File "/home/your/Project/ddrm/ddrm/apps/player/__init__.py", line 52, in start
self.on_init()
File "/home/your/Project/ddrm/ddrm/apps/player/__init__.py", line 73, in on_init
self._renderer = PygameRenderer()
^^^^^^^^^^^^^^^^
File "/home/your/Project/ddrm/ddrm/apps/player/renderer.py", line 18, in __init__
super().__init__()
File "/home/your/Project/ddrm/.venv/lib/python3.11/site-packages/imgui/integrations/base.py", line 18, in __init__
self.refresh_font_texture()
File "/home/your/Project/ddrm/.venv/lib/python3.11/site-packages/imgui/integrations/opengl.py", line 247, in refresh_font_texture
self._font_texture = gl.glGenTextures(1)
^^^^^^^^^^^^^^^^^^^
File "src/latebind.pyx", line 39, in OpenGL_accelerate.latebind.LateBind.__call__
File "src/wrapper.pyx", line 303, in OpenGL_accelerate.wrapper.Wrapper.__call__
File "src/wrapper.pyx", line 88, in OpenGL_accelerate.wrapper.CArgCalculator.c_call
File "src/wrapper.pyx", line 69, in OpenGL_accelerate.wrapper.CArgCalculatorElement.c_call
File "src/wrapper.pyx", line 64, in OpenGL_accelerate.wrapper.CArgCalculatorElement.c_call
File "src/arraydatatype.pyx", line 355, in OpenGL_accelerate.arraydatatype.SizedOutputOrInput.c_call
File "src/arraydatatype.pyx", line 224, in OpenGL_accelerate.arraydatatype.ArrayDatatype.c_zeros
File "src/arraydatatype.pyx", line 69, in OpenGL_accelerate.arraydatatype.HandlerRegistry.c_get_output_handler
File "src/arraydatatype.pyx", line 80, in OpenGL_accelerate.arraydatatype.HandlerRegistry.c_handler_by_plugin_name
File "/home/your/Project/ddrm/.venv/lib/python3.11/site-packages/OpenGL/plugins.py", line 18, in load
return importByName( self.import_path )
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/your/Project/ddrm/.venv/lib/python3.11/site-packages/OpenGL/plugins.py", line 45, in importByName
module = __import__( ".".join(moduleName), {}, {}, moduleName)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/your/Project/ddrm/.venv/lib/python3.11/site-packages/OpenGL/arrays/numpymodule.py", line 28, in <module>
from OpenGL_accelerate.numpy_formathandler import NumpyHandler
File "src/numpy_formathandler.pyx", line 1, in init OpenGL_accelerate.numpy_formathandler
ValueError: ('numpy.dtype size changed, may indicate binary incompatibility. Expected 96 from C header, got 88 from PyObject', 1, <OpenGL.platform.baseplatform.glGenTextures object at 0x72b5e17db840>)
Just remove PyOpenGL_accelerate.