Using gtkgl within Reinteract

52 views
Skip to first unread message

Robert Schroll

unread,
Jan 15, 2012, 6:27:41 PM1/15/12
to reint...@googlegroups.com
Hi all,

I've been playing, off and on, with using OpenGL for CustomResults in
Reinteract. This used to be a bit finicky, but possible. I just
2.17upgraded from Ubuntu 10.04 to 11.10 (thus from GTK 2.20 to 2.24 and
PyGTK 2.17 to 2.24), and now it needs a rather involved workaround.
Perhaps someone can suggest a better solution.

Attached, glwidget.py is adapted from the gtkgl examples and produces a
widget with a red sphere:
import glwidget
glwidget.GlSphere()
This used to work, but now it hangs while attempting to create the
Widget. (Specifically, the gldrawable.gl_begin() method hangs on the
configure event.)

I think I've traced the problem to this: gtk.gtkgl is only happy if it
is imported in the main thread. To demonstrate this, I've attached
glsafety.py, which provides a function to import gtk.gtkgl within the
main thread. Thus, if you do:
import glsafety
glsafety.initializeGL()

import glwidget
glwidget.GlSphere()
everything should work. It does for me, anyway. Unfortunately, the
trick I used to accomplish this import does not work during a module
import, so I can't put this function call within glwidget. Here are the
solutions I can think of:

- Be sure to run glsafety.initializeGL() before importing any modules
that use OpenGL. It already works, but it could become cumbersome.

- Import gtk.gtkgl during the initialization of Reinteract. I've tested
that this works, but it's an ugly solution. If other modules have
similar problems, Reinteract would end up with a long list of
precautionary imports.

- Run imports within the main thread. Most imports go quickly, so this
wouldn't block the GUI much. But one of the uses of imports within
Reinteract is to do long computations only once for all worksheets, so
this might not be a good idea.

- Add an import_main keyword to force an import to occur within the main
thread.

- Fix the problem with gtkgl. Obviously, this is the best solution, but
I have no idea about how to do it.

Any suggestions?

Thanks,
Robert

glsafety.py
glwidget.py

Owen Taylor

unread,
Feb 1, 2012, 5:59:53 PM2/1/12
to reint...@googlegroups.com
On Sun, Jan 15, 2012 at 6:27 PM, Robert Schroll <rsch...@gmail.com> wrote:
> Hi all,
>
> I've been playing, off and on, with using OpenGL for CustomResults in
> Reinteract.  This used to be a bit finicky, but possible.  I just
> 2.17upgraded from Ubuntu 10.04 to 11.10 (thus from GTK 2.20 to 2.24 and
> PyGTK 2.17 to 2.24), and now it needs a rather involved workaround. Perhaps
> someone can suggest a better solution.
>
> Attached, glwidget.py is adapted from the gtkgl examples and produces a
> widget with a red sphere:
>        import glwidget
>        glwidget.GlSphere()
> This used to work, but now it hangs while attempting to create the Widget.
>  (Specifically, the gldrawable.gl_begin() method hangs on the configure
> event.)

I don't actually see the hang trying out your example on Fedora 16
(gtk2-2.24, pygtk2-2.24), but that being said, you definitely
shouldn't be doing any GTK+ calls outside the main thread, including
gtkglext initialization.

To me the right thing to do is to do the initialization when
create_widget is called - you can modify your example as:

def create_widget(self):
global gtk, GL, GLU
import gtk.gtkgl
from OpenGL import GL
from OpenGL import GLU

Though that means writing glViewport as GL.glViewport throughout the
whole example, which is a bit annoying. To avoid that you could split
things into two files and have in glresult.py:

def create_widget(self):
import glwidget
return glwidget.GlSphere(self);

and then you could do arbitrary imports in the glwidget code, since it
would be executed in the main thread at widget creation time.

- Owen

Robert Schroll

unread,
Feb 4, 2012, 3:51:59 PM2/4/12
to reint...@googlegroups.com
On 02/01/2012 07:59 PM, Owen Taylor wrote:
> I don't actually see the hang trying out your example on Fedora 16
> (gtk2-2.24, pygtk2-2.24), but that being said, you definitely
> shouldn't be doing any GTK+ calls outside the main thread, including
> gtkglext initialization.

Thanks for the confirmation. Honestly, I was a bit surprised that
things were working before.


>
> To me the right thing to do is to do the initialization when
> create_widget is called - you can modify your example as:
>
> def create_widget(self):
> global gtk, GL, GLU
> import gtk.gtkgl
> from OpenGL import GL
> from OpenGL import GLU
>
> Though that means writing glViewport as GL.glViewport throughout the
> whole example, which is a bit annoying. To avoid that you could split
> things into two files and have in glresult.py:
>
> def create_widget(self):
> import glwidget
> return glwidget.GlSphere(self);
>
> and then you could do arbitrary imports in the glwidget code, since it
> would be executed in the main thread at widget creation time.

Thanks for the suggestion. I'm not sure I'll be able to make it work,
though. My goal here is not to draw red spheres in Reinteract, it's to
be able to use the 3D OpenGL plotting library Visvis. I need to import
the plotting functions before creating the widget. I don't think I'll
be able to import these functions without also importing OpenGL. It may
be possible to put fake OpenGL modules in place before loading Visvis,
and then slip the real ones in while creating the first widget. But
this strikes me as more clever than intelligent.

I'll think on it some more, and if I come up with something both clever
and intelligent, I'll let you know.

Thanks,
Robert

P.S. Any news on Reinteract 0.6? If I can help in anyway, please let me
know.

Owen Taylor

unread,
Feb 4, 2012, 4:30:29 PM2/4/12
to reint...@googlegroups.com
On Sat, Feb 4, 2012 at 3:51 PM, Robert Schroll <rsch...@gmail.com> wrote:
> Thanks for the suggestion.  I'm not sure I'll be able to make it work,
> though.  My goal here is not to draw red spheres in Reinteract, it's to be
> able to use the 3D OpenGL plotting library Visvis.  I need to import the
> plotting functions before creating the widget.  I don't think I'll be able
> to import these functions without also importing OpenGL.  It may be possible
> to put fake OpenGL modules in place before loading Visvis, and then slip the
> real ones in while creating the first widget.  But this strikes me as more
> clever than intelligent.

Well, if you are willing to hack up visvis, then it seems not bad -
you'd create a new backend for visvis - a 'reinteract' backend - that
when you create a Figure creates a CustomResult rather than directly
creating a figure. Then you can delay importing gtkgl into
create_widget time.

Without hacking up visvis it seems much harder. Close to impossible.
Because the gtk backend to visvis creates a widget when you create a
Figure, and creating a widget in the execution thread of reinteract is
not OK.

> P.S. Any news on Reinteract 0.6?  If I can help in anyway, please let me know.

Yeah, I dropped the ball on that one at the one-yard line. The main
blocker is for me to just sit down with my Windows machine and see if
I can figure out what's wrong with the Windows installer I built and
why it isn't working for people. I may have a chance tomorrow evening.

- Owen

Robert Schroll

unread,
Feb 4, 2012, 7:28:30 PM2/4/12
to reint...@googlegroups.com
On 02/04/2012 06:30 PM, Owen Taylor wrote:
> On Sat, Feb 4, 2012 at 3:51 PM, Robert Schroll<rsch...@gmail.com> wrote:
>> Thanks for the suggestion. I'm not sure I'll be able to make it work,
>> though. My goal here is not to draw red spheres in Reinteract, it's to be
>> able to use the 3D OpenGL plotting library Visvis. I need to import the
>> plotting functions before creating the widget. I don't think I'll be able
>> to import these functions without also importing OpenGL. It may be possible
>> to put fake OpenGL modules in place before loading Visvis, and then slip the
>> real ones in while creating the first widget. But this strikes me as more
>> clever than intelligent.
>
> Well, if you are willing to hack up visvis, then it seems not bad -
> you'd create a new backend for visvis - a 'reinteract' backend - that
> when you create a Figure creates a CustomResult rather than directly
> creating a figure. Then you can delay importing gtkgl into
> create_widget time.

I was considering this. (As I wrote the GTK backend for Visvis, it
wouldn't be so difficult.) But in some quick testing, it looks like
importing OpenGL.GL outside of the main thread has the same problems as
gtk.gtkgl. While importing gtkgl could be avoided, imports of OpenGL.GL
are scattered throughout Visvis, and I don't see a way around them.
(Visvis very much has a single-threaded mindset.)


>
> Without hacking up visvis it seems much harder. Close to impossible.
> Because the gtk backend to visvis creates a widget when you create a
> Figure, and creating a widget in the execution thread of reinteract is
> not OK.

This isn't as much a problem - I just subclass Figure and avoid calling
its __init__. Then I create the widget in create_widget. refigure2
does something similar.


>
>> P.S. Any news on Reinteract 0.6? If I can help in anyway, please let me know.
>
> Yeah, I dropped the ball on that one at the one-yard line. The main
> blocker is for me to just sit down with my Windows machine and see if
> I can figure out what's wrong with the Windows installer I built and
> why it isn't working for people. I may have a chance tomorrow evening.

I do have a neglected Windows partition on my machine. If it would
help, I can boot into that and try the installer. But when something
goes wrong, I'll be no use at all in figuring out what.

As a reminder, it'd be nice to deal with bug 663533 before the release.

Thanks,
Robert

Owen Taylor

unread,
Feb 4, 2012, 7:57:49 PM2/4/12
to reint...@googlegroups.com

Hmm, I guess the question is whether VisVis is just doing the imports
at module scope and maybe using some constants at non-draw-time, or
whether it's actively calling functions as the user is making calls -
is it calling glBindTexture, etc.

If GL calls are actively being made from the execution thread, then no
amount of fooling around with where the imports are done from is going
to work. For larks, you could try adding somewhere to the top of the
reinteract wrapper script before it imports anything something like:

imports ctypes
ctypes.CDLL("libX11.so.6").XInitThreads()

If GL calls are not being made from the execution thread, then
basically all you need to do is figure out some way to get reinteract
to import gtk.gl before the worksheet executes. I suppose we could say
that if there is a file __init__.py in a notebook, it was imported in
the main thread before executing any worksheets (and reimported if
changed before the next execution). Is that generally useful beyond
this case?
[...]


>>> P.S. Any news on Reinteract 0.6?  If I can help in anyway, please let me
>>> know.
>>
>>
>> Yeah, I dropped the ball on that one at the one-yard line. The main
>> blocker is for me to just sit down with my Windows machine and see if
>> I can figure out what's wrong with the Windows installer I built and
>> why it isn't working for people. I may have a chance tomorrow evening.
>
>
> I do have a neglected Windows partition on my machine.  If it would help, I
> can boot into that and try the installer.  But when something goes wrong,
> I'll be no use at all in figuring out what.

I think most likely it's just files missing from the creation scripts,
but yeah, it's likelier easier for me.

> As a reminder, it'd be nice to deal with bug 663533 before the release.

Yeah, it's on my todo list for the release.

- Owen

Robert Schroll

unread,
Feb 4, 2012, 9:34:39 PM2/4/12
to reint...@googlegroups.com
On 02/04/2012 09:57 PM, Owen Taylor wrote:
> Hmm, I guess the question is whether VisVis is just doing the imports
> at module scope and maybe using some constants at non-draw-time, or
> whether it's actively calling functions as the user is making calls -
> is it calling glBindTexture, etc.

For the most part, it's only making OpenGL calls when displaying the
figures, but it's not careful about that. If you check out revis
(https://github.com/rschroll/revis), you can see that I had to monkey
patch a few things to keep OpenGL calls from happening in the worker
threads. But if I use this with the glsafety.initializeGL() call to get
things imported in the main thread, everything works just fine. So I'm
pretty confident that it's just the module imports that are causing me
problems now.

This is why I said it's probably possible to import a fake OpenGL module
before revis, and then swap in the real one during a create_widget call.
But I feel this is being too clever for its own good.


>
> If GL calls are actively being made from the execution thread, then no
> amount of fooling around with where the imports are done from is going
> to work. For larks, you could try adding somewhere to the top of the
> reinteract wrapper script before it imports anything something like:
>
> imports ctypes
> ctypes.CDLL("libX11.so.6").XInitThreads()
>
> If GL calls are not being made from the execution thread, then
> basically all you need to do is figure out some way to get reinteract
> to import gtk.gl before the worksheet executes. I suppose we could say
> that if there is a file __init__.py in a notebook, it was imported in
> the main thread before executing any worksheets (and reimported if
> changed before the next execution). Is that generally useful beyond
> this case?

Can't think of another use for this offhand. Another option would be to
have a specially-named worksheet (__init__.rws?) always be executed
before any others in a notebook. Then I could put the glsafety code in
there. This might be useful for other cases where you want to set some
global options for a notebook. (I sometimes have a worksheet to set
matplotlib settings for an entire notebook.) But this sort of behavior
goes against the idea of each notebook being self-contained, so we might
not want to encourage it.

Both of these are suboptimal from the point of view of revis, though,
because they require extra work in each notebook where it is used.
Reinteract could keep a list of modules that need to be imported in the
main thread. But perhaps a better solution would be for Reinteract to
execute a user's .py file as part of its initialization. I could stick
'import gtk.gtkgl' in there to make revis work, but I'm sure there's all
sorts of weird and wonderful things you could do with this. (Or perhaps
that's a good reason not to do this....)

In any event, thanks for puzzling over this with me. It's reassuring to
know that it should be crashing. :)

Robert

Reply all
Reply to author
Forward
0 new messages