Dependencies: Pyglet vs PyOpenGL

711 views
Skip to first unread message

Almar Klein

unread,
Apr 14, 2013, 7:55:19 AM4/14/13
to pyv...@googlegroups.com, Nicolas Rougier
While we're discussing the highest levels of our project in another thread, I'd like to reopen the discussion with regard to the lowest level: our dependencies for the OpenGL API. I think that we should address this issue before we start working on our oo GL layer.

We basically have two choices: Pyglet or PyOpenGL. The former being a bit basic, the latter being easier to use (and therefore possibly a bit slower if you have many opengl calls). Pyglet also comes with functionality to create windows and detect screens etc.

It seems that Nicolas has most experience with Pygley, and he seemed a bit reluctant towards Pyglet (correct me if I'm wrong!).

I initially liked the idea of always having window backend to render too, without needing additional dependencies. On the other hand, if we implement a backend for pyglet, glut, PyQt4, PySide, WxPython, Gtk, FLTK, users are almost bound to have one of these available. And if not, installing one of these would be very simple. (Pyglet is pure Python).

So would it be fair to say that we're going to use PyOpenGL? 

If so. our dependencies become: pyopengl, numpy, and one of the above mentioned backends to provide a window to render in. Optionally, we may include pyglet in the package distribution and install if necessary.

- Almar

Cyrille Rossant

unread,
Apr 14, 2013, 8:04:26 AM4/14/13
to Almar Klein, pyv...@googlegroups.com, Nicolas Rougier



2013/4/14 Almar Klein <almar...@gmail.com>
How does one install GLUT? Is it always bundled in PyOpenGL or not? I think I can use GLUT with PyOpenGL on Windows whereas I didn't do anything to install it specifically. If a backend window can be created only with PyOpenGL/GLUT, it would mean that pyopengl+numpy are the only mandatory dependencies.

Cyrille


Cyrille Rossant

unread,
Apr 14, 2013, 8:11:20 AM4/14/13
to Almar Klein, pyv...@googlegroups.com, Nicolas Rougier
We basically have two choices: Pyglet or PyOpenGL. The former being a bit basic, the latter being easier to use (and therefore possibly a bit slower if you have many opengl calls). Pyglet also comes with functionality to create windows and detect screens etc.

Another thing: do we want an additional layer between our raw GL calls and the PyOpenGL calls? For instance a simple proxy class that would just redirect Proxy.gl*() to OpenGL.gl*(). This would make possible the following things:
  * log/capture all GL calls, which can be useful for debugging and unit testing (i.e. switch off the actual GL calls when a renderer is not available, which may happen in a continuous integration scenario)
  * use either PyOpenGL or Pyglet (meaning that numpy+pyglet would be sufficient)
  * *might* be used for offscreen rendering or similar (basically sending all GL commands to an external renderer)
Maybe there's an overhead but I don't think it would be significant.

Cyrille

Luke Campagnola

unread,
Apr 14, 2013, 8:12:57 AM4/14/13
to Cyrille Rossant, Almar Klein, pyv...@googlegroups.com, Nicolas Rougier
On Ubuntu, GLUT is included with the python-opengl package. 
 

Luke Campagnola

unread,
Apr 14, 2013, 8:33:35 AM4/14/13
to Cyrille Rossant, Almar Klein, pyv...@googlegroups.com, Nicolas Rougier
\On Sun, Apr 14, 2013 at 8:11 AM, Cyrille Rossant <cyrille...@gmail.com> wrote:

We basically have two choices: Pyglet or PyOpenGL. The former being a bit basic, the latter being easier to use (and therefore possibly a bit slower if you have many opengl calls). Pyglet also comes with functionality to create windows and detect screens etc.

Another thing: do we want an additional layer between our raw GL calls and the PyOpenGL calls? For instance a simple proxy class that would just redirect Proxy.gl*() to OpenGL.gl*(). This would make possible the following things:
  * log/capture all GL calls, which can be useful for debugging and unit testing (i.e. switch off the actual GL calls when a renderer is not available, which may happen in a continuous integration scenario)

This would be very useful.
 
  * use either PyOpenGL or Pyglet (meaning that numpy+pyglet would be sufficient)

I like this idea, but I am told that the APIs are very different. It would take some effort to reconcile the differences (I would recommend wrapping the pyglet calls to make them look more like PyOpenGL). An awesome bonus of this is that the _only_ dependency of the library would be numpy. 
 
Maybe there's an overhead but I don't think it would be significant.

I would worry about this, but I think the same effects could be achieved without using a proxy--just decide at the beginning which module to import to a shared location, like (PyOpenGL, Pyglet, GLDebugProxy) -> vispy.opengl


Luke

Cyrille Rossant

unread,
Apr 14, 2013, 8:40:55 AM4/14/13
to Luke Campagnola, Almar Klein, pyv...@googlegroups.com, Nicolas Rougier

I like this idea, but I am told that the APIs are very different. It would take some effort to reconcile the differences (I would recommend wrapping the pyglet calls to make them look more like PyOpenGL). An awesome bonus of this is that the _only_ dependency of the library would be numpy.

You're right, it may be not that simple then. But indeed, the perspective of being able to "compile" a visualization into a sequence of OpenGL calls could be interesting. For instance, maybe there would be a way to automatically convert a static scene into another language, using the raw OpenGL calls.

Cyrille

Nicolas Rougier

unread,
Apr 14, 2013, 8:47:29 AM4/14/13
to Cyrille Rossant, Luke Campagnola, Almar Klein, pyv...@googlegroups.com


One third option (for OpenGL) could be to provide our own bindings via ctype. This is what pyglet's doing and if we offer a low-level api, user won't seen them much anyway. I think we can get extract the relevant code from pyglet.

BTW, sorry for not being too responsive but I'm a bit overloaded with work right now.


Nicolas

Almar Klein

unread,
Apr 14, 2013, 9:48:54 AM4/14/13
to Nicolas Rougier, Cyrille Rossant, Luke Campagnola, pyv...@googlegroups.com
 
How does one install GLUT? Is it always bundled in PyOpenGL or not? I think I can use GLUT with PyOpenGL on Windows whereas I didn't do anything to install it specifically. If a backend window can be created only with PyOpenGL/GLUT, it would mean that pyopengl+numpy are the only mandatory dependencies.

PyOpenGL docs say that the pre-build binaries come with GLUT. I remember not being able to use it on Py3k or something (cant remember the details), so we would need to look into it. Nevertheless, I think we cannot rely on GLUT always being installed (GLUT != opengl). But one of our backends is bound to be there at least with the common scientific Python distributions.


... the perspective of being able to "compile" a visualization into a sequence of OpenGL calls could be interesting. For instance, maybe there would be a way to automatically convert a static scene into another language, using the raw OpenGL calls.

Very interesting idea!


One third option (for OpenGL) could be to provide our own bindings via ctype. This is what pyglet's doing and if we offer a low-level api, user won't seen them much anyway. I think we can get extract the relevant code from pyglet.

They auto-generate the binding I believe, right? So we better extract the code that creates the bindings. But how is this better than using pyglet.gl directly, apart from having pyglet as a dependency? (it would mean extra maintenance too!)

- Almar

 

Luke Campagnola

unread,
Apr 14, 2013, 9:50:09 AM4/14/13
to Cyrille Rossant, Almar Klein, pyv...@googlegroups.com, Nicolas Rougier
On Sun, Apr 14, 2013 at 8:40 AM, Cyrille Rossant <cyrille...@gmail.com> wrote:

I like this idea, but I am told that the APIs are very different. It would take some effort to reconcile the differences (I would recommend wrapping the pyglet calls to make them look more like PyOpenGL). An awesome bonus of this is that the _only_ dependency of the library would be numpy.

You're right, it may be not that simple then. But indeed, the perspective of being able to "compile" a visualization into a sequence of OpenGL calls could be interesting. For instance, maybe there would be a way to automatically convert a static scene into another language, using the raw OpenGL calls.

How about this:  For now, we keep it simple and plan on using PyOpenGL, but in such a way that it is easy to swap out for alternative libraries later on. Right now we have pyvis.opengl, which is where I propose the OO opengl objects go: pyvis.opengl.VertexBuffer, ShaderProgram, ect. The actual opengl api could be made available as pyvis.opengl.GL.glEnable, .glDrawArrays, .GL_FLOAT, etc. 

Then, if we decide to add support for pyglet / debugging / proxy features later, this can be supported by setting a global configuration option before importing pyvis.opengl:

    import pyvis
    pyvis.config['opengl_backend'] = 'pyglet'
    import pyvis.opengl.GL as GL   # would take care of importing pyglet symbols instead of PyOpenGL
    GL.glClear(...)



Cyrille Rossant

unread,
Apr 14, 2013, 9:51:56 AM4/14/13
to Luke Campagnola, Almar Klein, pyv...@googlegroups.com, Nicolas Rougier



2013/4/14 Luke Campagnola <luke.ca...@gmail.com>
Sounds good!
Cyrille 

Luke Campagnola

unread,
Apr 14, 2013, 10:13:14 AM4/14/13
to Almar Klein, Nicolas Rougier, Cyrille Rossant, pyv...@googlegroups.com
On Sun, Apr 14, 2013 at 9:48 AM, Almar Klein <almar...@gmail.com> wrote:
One third option (for OpenGL) could be to provide our own bindings via ctype. This is what pyglet's doing and if we offer a low-level api, user won't seen them much anyway. I think we can get extract the relevant code from pyglet.

They auto-generate the binding I believe, right? So we better extract the code that creates the bindings. But how is this better than using pyglet.gl directly, apart from having pyglet as a dependency? (it would mean extra maintenance too!)

I agree--copying pyglet code should be the last option. Better to include pyglet as a dependency or sub-package. We can add a wrapper to make the API compatible with PyOpenGL, or even better: work directly with the pyglet folks to make their API work for us (adding python3 compatibility, better support for numpy arrays, etc). 

Almar Klein

unread,
Apr 14, 2013, 10:35:36 AM4/14/13
to Luke Campagnola, Cyrille Rossant, pyv...@googlegroups.com, Nicolas Rougier
How about this:  For now, we keep it simple and plan on using PyOpenGL, but in such a way that it is easy to swap out for alternative libraries later on. Right now we have pyvis.opengl, which is where I propose the OO opengl objects go: pyvis.opengl.VertexBuffer, ShaderProgram, ect. The actual opengl api could be made available as pyvis.opengl.GL.glEnable, .glDrawArrays, .GL_FLOAT, etc. 

Good idea. Except perhaps not put it inside the oogl layer. Something like vispy.gl and a vispy.oogl. 

work directly with the pyglet folks to make their API work for us (adding python3 compatibility, better support for numpy arrays, etc). 

Pyglet does work on py3k. 

- Almar

Adam Griffiths

unread,
Apr 16, 2013, 10:01:34 PM4/16/13
to vi...@googlegroups.com, Almar Klein, Nicolas Rougier, Cyrille Rossant, pyv...@googlegroups.com
Hi guys, I'm the creator of PyGLy. Just thought I'd throw in my 2 cents.


I used Pyglet's GL wrapper and found it to be quite good.
It sticks to the python API which is nice, albeit c-like.

Pyglet's API uses ctypes... a lot.
Take a look at glGetIntergerv, and other functions.
>>> x = GLint()
>>> glGetIntegerv(GL_MAX_LIGHTS, x)

src = (c_char_p * count)(*strings)
glShaderSource(shader, count, cast(pointer(src), POINTER(POINTER(c_char))), None)
 

The main problem I had was that it doesnt support numpy directly.
I was unable to pass in mixed data types to buffers / textures, etc which can be important for efficient opengl coding
Quite often you need to pass float16, int16, int32's etc in the same buffer to OpenGL. This is mainly for meshes / animation.
In Pyglet, you need to pass in a ctype, this conversion mandates the values be the same type.
Ie, glBufferData( ..., (GLfloat * 100)(*floatArray), ... )
I tried for a while to fix this, but found no way (I'm not that experienced with python's ctype voodoo).
Perhaps you guys know of some method to do this (perhaps just 'np.array.data' would do the trick?).

Pyglet's core design is very... complex. It's overly OO and I found it incredibly difficult to follow.
A good example is the texture functions, tracing through them is a nightmare. Using them is overly complex too. You need to go through an Image object, then pull a GL texture object out of it.
The documentation can be really poor and I had a lot of trouble figuring out how to load a numpy array into a texture because this use case is just not found in the docs.

I had to monkey patch it to get OpenGL 3 working because Pyglet is OpenGL legacy down to the core windowing calls for mouse cursor rendering. This also meant I had to ditch all of pyglet's higher level fucntions because they are legacy based.

The idle loop had to be monkey patched too because it performs a render every time it clears the event queue, so moving your mouse on the window causes 100% cpu usage due to insane amounts of render calls.

I've also have problems with bugs in Pyglet.
OS-X support is not good. I had to fork Pyglet to get OpenGL 3.0 working on OS-X. I don't believe the patches have been applied after 6+ months.



PyOpenGL is supported by 99% of python gl windowing toolkits (Qt, PyGame, PyGLFW, etc.)
Even Pyglet works with PyOpenGL because the same OpenGL context is being used, so the calls are irrelevant.
You could perhaps use Pyglet's opengl calls while using another platform, but I found the extra dependency to be unneccessary.

PyOpenGL also supports numpy as a first class citizen, so I can now support mixed data types being allocated.
Most functions are wrapped in python and remove the need for ctypes and other c-type quirks like integer length, string length, returned value length, etc.

So platform independence and numpy support were big reasons to move away from pyglet.
This also meant dropping pyglet's event system. It's trivial to convert pyglet events to another event system with a wrapper.

This pythonic wrapping has a down-side, the documentation. This is the main problem with PyOpenGL.
The documentation is a copy of the opengl websites docs (albeit uglier).
Many OpenGL functions have been made more pythonic, but the signature changes are rarely documented and the quirks are NEVER documented.
For example, glBufferData - passing 0 for offset = crash, must pass None.
Other things like glGet being wrapped, some glGet functions are wrapped, some are still ctypes.
I used a LOT of trial and error to figure out the API calls I'm currently using.


I wanted to love pyglet because it's 100% python and simple to install, but it has cost me a lot of time and effort to get it working.
I'm thinking of using PyFLGW because its a simple wrapper, and the python bindings are trivial to patch.

It may not be appropriate for you guys, but ditching pyglet was the best thing I did.
Just hoping to provide some insight into the issues I've had over the last few years with pyglet, et al.


Cheers,
Adam

Almar Klein

unread,
Apr 17, 2013, 6:50:01 AM4/17/13
to Adam Griffiths, vi...@googlegroups.com, Nicolas Rougier, Cyrille Rossant, pyv...@googlegroups.com
Hi Adam, thanks for sharing your experience. This is very insightful. 

Will have a look at pyflgw. I think you misspelled the name (what a terrible acronym, anyway), making it a bit hard to google :)  
Here's a link to the github repo: https://github.com/nightcracker/pyglfw

- Almar

Reply all
Reply to author
Forward
0 new messages