thp/pyotherside — pull request #26 by dtomas (2014-09-26 10:37:10+00:00)
Title: PyOpenGL in PyOtherSide

I have some rendering code written in PyOpenGL, which I'd like to integrate in a QML application using PyOtherSide, so I needed a way to access a QML application's OpenGL context in my Python code.

I started out by implementing a QML element I called PyGLArea, following the tutorial in the Qt documentation (http://qt-project.org/doc/qt-5/qtquick-scenegraph-openglunderqml-example.html).

At first, it seemed to work all right, but as soon as I called some long-running Python function from QML, the GUI would freeze until it returned. I noticed this was due to the mutex in QPythonPriv getting acquired before the function was called, causing the rendering thread running the PyOpenGL code to wait until the mutex got released.

Reading up on Python and threading, I found out that you were supposed to use PyGILState_Ensure() and PyGILState_Release() instead of PyEval_SaveThread() and PyEval_RestoreThread() from non-Python created threads (https://docs.python.org/3.4/c-api/init.html#non-python-created-threads), so I replaced the calls accordingly, which seemed to remove the need for the mutex.
There is still the possibility of temporary GIL-related freezes, but with most of the long-running jobs being I/O (releasing the GIL), the GUI runs smoothly. (commits 75579b1 through 387842c)

Another problem with my initial approach was that the Python functions to render and initialize/cleanup OpenGL resources were passed by name. So it was not possible to re-use a renderer in different contexts. I considered adding a "contextId" property which would get passed to the functions, but did not like having to manage context objects myself, i.e. by using some global dict. Then I discovered fkrull's fork's ability to pass object references between Python and QML and used it to pass the renderer by reference. (commit 7e1fa5c)

When working with object references, I often found it useful to call methods on them, or get attributes. (commits cbb0bb9 and fd27b10)

I've also written some documentation and examples. (commit 22fdeb3)
(The PyObjectRef extension is not yet documented, though.)