PyOpenGL is an python module that implements OpenGL functions in python allowing you to write OpenGL applications using Python.
With OpenGL you are able to write applications that use "GPU acceleration". So if you have an Nvidia RTX 3060 gpu on your system, the opengl functions will use it to render the 3D graphics on screen.
So technically you can write a game based on OpenGL, though Python is not a very ideal language for writing games. For game development you should use C++ instead. Moreover using OpenGL based API directly is also not recommended, since you would have to do a lot of rudimentary drawing tasks yourself.
Instead you are better off using a game development library like SDL or a full-fledged framework like Unreal or Unity. Python even has a wrapper module for SDL called PyGame.
It must be kept in mind that OpenGL is just a set of specifications, and various vendors provide implementation of this specifications in the form of an API that can be used in other programming languages like C++.
In this simple and quick tutorial we shall take a look at the required steps to install PyOpenGL on Windows 10 and test it.
Step 1: Install Python
First off, you need to have Python on your system. You can simply download it from:
https://www.python.org/downloads/Run the installer and it will install the python interpreter on Windows.
Step 2: Install PyOpenGL modules
The next task is to install PyOpenGL package which brings in OpenGL functions in python. However there is a twist. The original method was to install it from the pip packages using the following command:
pip install PyOpenGL PyOpenGL_accelerate
However the above will not working. It will install PyOpenGL packages, but when you try to import the packages, it will fail.
The alternative working method is to download un-official packages from a 3rd party site.
https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopenglBe careful to download the .whl package file that matches the Python interpreter version on your system. For example I downloaded:
PyOpenGL-3.1.6-cp310-cp310-win_amd64.whl PyOpenGL_accelerate-3.1.6-cp310-cp310-win_amd64.whl
as I have Python 3.10 install on my system. the "cp-310" part indicates which version of python interpreter is the package compiled for.
If you download a package for a different Python version, it will fail to install.
Code
The following is a simple python program, that will import the OpenGL modules and print out some basic information about the driver being used.
# PyOpenGL Setup # Ref: https://stackabuse.com/brief-introduction-to-opengl-in-python-with-pyopengl/ import sys print('Python version: ' + sys.version + '\n') import OpenGL.GL import OpenGL.GLUT import OpenGL.GLU from OpenGL import * from OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import * print("OpenGL Imports successful!") # If you see this printed to the console then installation was successful def showScreen(): return glutInit() # Initialize a glut instance which will allow us to customize our window glutInitDisplayMode(GLUT_RGBA) # Set the display mode to be colored glutInitWindowSize(500, 500) # Set the width and height of your window glutInitWindowPosition(0, 0) # Set the position at which this windows should appear wind = glutCreateWindow("OpenGL Coding Practice") # Give your window a title # print OpenGL Driver Information try: # this method can be called only after glutCreateWindow has been called. # it works only after a opengl context has been created # OpenGL Context: https://www.khronos.org/opengl/wiki/OpenGL_Context print("OpenGL Vendor: " + GL.glGetString(GL.GL_VENDOR).decode()) print("OpenGL Renderer: " + GL.glGetString(GL.GL_RENDERER).decode()) gl_version_str = GL.glGetString(GL.GL_VERSION) gl_version = float(gl_version_str[:3]) print("OpenGL Renderer Version: " + str(gl_version) + " ( " + gl_version_str.decode() + " )") print("OpenGL Shading Language Version: " + GL.glGetString(GL.GL_SHADING_LANGUAGE_VERSION).decode()) print("OpenGL Total Extensions: " + str(GL.glGetIntegerv(GL.GL_NUM_EXTENSIONS))) gl_extensions_str = GL.glGetString(GL.GL_EXTENSIONS).decode() #print("OpenGL Extensions: " + gl_extensions_str) #print("OpenGL ATTRIBUTES:\n",", ".join(d for d in dir(GL) if d.startswith("GL_"))) vram_total = vram_used = vram_available = 'Unknown' # https://gamedev.stackexchange.com/questions/3346/how-can-i-tell-how-much-video-card-memory-im-using # Only for Nvidia GPUs # https://stackoverflow.com/questions/43267640/how-i-can-get-my-total-gpu-memory-using-qts-native-opengl if('GL_NVX_gpu_memory_info' in gl_extensions_str): # Ref: https://github.com/collincebecky/QT-OPENCV-GSTREAMER-CUDA/blob/master/glUtility.h # https://registry.khronos.org/OpenGL/extensions/NVX/NVX_gpu_memory_info.txt GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX = 0x9048 GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX = 0x9049 vram_total = GL.glGetIntegerv(GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX) vram_available = GL.glGetIntegerv(GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX) vram_used = vram_total - vram_available # For AMD gpus (Integrated GPUs) # https://registry.khronos.org/OpenGL/extensions/ATI/ATI_meminfo.txt elif ('GL_ATI_meminfo' in gl_extensions_str): TEXTURE_FREE_MEMORY_ATI = 0x87FC vram_total = GL.glGetIntegerv(TEXTURE_FREE_MEMORY_ATI) else: print('Memory information not available') print("Total VRAM: " + str( vram_total ) + " KB") print("VRAM Used: " + str( vram_used ) + " KB") print("Total Available VRAM: " + str( vram_available ) + " KB") except Exception as e: print('GL.glGetString failed:' + str(e)) glutDisplayFunc(showScreen) # Tell OpenGL to call the showScreen method continuously glutIdleFunc(showScreen) # Draw any graphics or shapes in the showScreen function at all times glutMainLoop() # Keeps the window created above displaying/running in a loop
Output
I used the free Visual Studio Code IDE to run the above program. It should output details about the OpenGL driver that is being used for OpenGL rendering.
On my Asus TUF gaming laptop I have both RTX 3060 dGPU and Radeon Vega 8 iGPU.
When Nvidia is configured as the default GPU, the output looks something like this:
OpenGL Imports successful! OpenGL Vendor: NVIDIA Corporation OpenGL Renderer: NVIDIA GeForce RTX 3060 Laptop GPU/PCIe/SSE2 OpenGL Renderer Version: 4.6 ( 4.6.0 NVIDIA 512.78 ) OpenGL Shading Language Version: 4.60 NVIDIA OpenGL Total Extensions: 402 Total VRAM: 6291456 KB VRAM Used: 292168 KB Total Available VRAM: 5999288 KB
Note that 4.6 is the version of the OpenGL standard that has been implemented by this driver.
So you can write programs that use OpenGL 4.6 features. With the GL_NVX_gpu_memory_info extension it also reports information about VRAM on the GPU. The above NVidia RTX 3060 has 6GB vram for instance.
However reporting the vram might not be possible for all kinds of gpus like the AMD igpu.
When AMD Radeon is set as the default GPU, the output looks like this:
OpenGL Imports successful! OpenGL Vendor: ATI Technologies Inc. OpenGL Renderer: AMD Radeon(TM) Graphics OpenGL Renderer Version: 4.6 ( 4.6.14756 Compatibility Profile Context 20.40.44.02 27.20.14044.2001 ) OpenGL Shading Language Version: 4.60 OpenGL Total Extensions: 305
There is a difference in the number of extensions supported by the OpenGL drivers from Nvidia vs. AMD.
Nvidia being a more powerful dedicated gpu supports more extensions, whereas the integrated gpu from amd is less powerful with comparatively fewer features.
On systems that do not have any kind of gpu (either dedicated or integrated), the system provides a software based implementation of OpenGL. Software based OpenGL renderer is far slower compared to hardware based ones simply because the software libraries use the CPU which cannot handle rendering as fast as GPUs.
References:
https://www.programcreek.com/python/example/95621/OpenGL.GL.glGetString - The glGetString samples have been taken from this page.
https://stackoverflow.com/questions/10037251/how-to-determine-the-opengl-version-under-windows
https://stackoverflow.com/questions/12184506/why-does-glgetstringgl-version-return-null-zero-instead-of-the-opengl-versio
How OpenGL connects to the GPU
Some of you might be wondering, how exactly does OpenGL talk to the GPU to perform the rendering. This topic has been discussed on Stackoverflow over here and here.
Any OpenGL application initially loads the "opengl32.dll" file which is present on all versions of Windows. This particular library acts as a buffer and it in turn loads an actual ICD (Installable Client Driver) which provides the OpenGL implementation for to the specific GPU like Nvidia RTX 3060.
If you are using an Nvidia RTX 3060 GPU then it will load - nvoglv64.dll
With AMD iGPU the OpenGL driver file is - atig6pxx.dll
The respective driver files talk to the gpu hardware and provide "hardware acceleration" or hardware based execution.
PyOpenGL application -> FreeGLUT dll -> opengl32.dll -> nvoglv64.dll -> the Nvidia GPU (graphics card)
The official wiki also explains this
https://www.khronos.org/opengl/wiki/FAQ#How_Does_It_Work_On_Windows.3F
Other Libraries - GLU and GLUT
OpenGL does not have a standalone SDK or API per se that can be used directly, but there are actually other libraries that wrap around OpenGL functions from "drivers" to provide access to the OpenGL functions that can be used to write applications.
These are called Extension Loading Libraries or OpenGL Loading Library. These libraries basically load "pointers" to OpenGL functions at runtime which the application can call directly.
Extension Loading Library (FreeGLUT) -> Actual OpenGL Driver (nvoglv64.dll)
These individual Loading Libraries provide their own SDK (header and lib files in C++) for developing applications.
PyOpenGL is a wrapper around 2 libraries which are OpenGL Utility Toolkit and OpenGL Utility Library.
To be more specific PyOpenGL is a wrapper around the implementation of GLUT called FreeGLUT.
GLUT provides functionality like drawing windows, registering callbacks for keyboard, mouse etc. Specifications are available here.
The GLU library specifications are available here.
They are listed on the official site: https://www.opengl.org/resources/librarIES
In PyOpenGL function names start with "glut", "glu" and "gl" which indicates which library they come from. Function from GLUT are prefixed with "glut", whereas "glu" indicates GLU. Function names starting with just "gl" indicate the core OpenGL functions
Besides GLUT and GLU there are many other alternative 3rd party wrappers available for OpenGL. Some common ones include:
GLEW - http://glew.sourceforge.net/
GLFW - https://www.glfw.org/
Both the above libraries have Python bindings.
Links and Resources
https://stackabuse.com/brief-introduction-to-opengl-in-python-with-pyopengl/ - A brief introduction to PyOpenGL
https://www.khronos.org/opengl/wiki/
https://open.gl/ - Learn the latest OpenGL version
https://docs.gl/
https://www.opengl.org/Documentation/Documentation.html
https://www.opengl.org/sdk/libs/