
Simon Peyton-Jones wrote:
This is nasty. As I understand it,
* GLUT assumes that the same OS thread executes some Haskell code, calls C, which calls back to Haskell.
All OpenGL calls operate upon the current context and window, which are per-thread settings. The context is set with glXMakeCurrent (X11) or wglMakeCurrent (Windows); this sets a specific context and a specific Drawable (X11) or DC (Windows) as current for the calling thread. IOW, the OpenGL API isn't so much thread-safe as thread-aware. This is fine if the program is managing the threads itself, but it's likely to be a nuisance within a system which switches threads arbitrarily. GLUT sets the current context/window at appropriate points (glutCreateWindow, glutSetWindow, and before invoking callbacks). This works fine providing that the OpenGL calls are made within the thread in which the callback is invoked.
* Concurrent Haskell never lets this happen, for very good reason. The thread executing Haskell code is just an anonymous OS thread executing multiple Haskell threads.
The good reason is this: if one designated OS thread must execute a particular bunch of Haskell code, what if that OS thread gets blocked doing I/O on behalf of some other Haskell thread? It's hard to say just which Haskell threads "belong" to that designated OS thread.
The only thing I can think of is that the Haskell call-back thread somehow says that it can only be executed by the designated OS thread; and when blocks (the Haskell call-back, that is) the OS thread doesn't grab another Haskell thread to execute, but instead steps aside for an anonymous worker thread to do the job. Makes it all more complicated, alas.
Is there no way to get the "current context" explicitly, and treat it as some kind of "handle" that accompanies GLUT calls?
GLUT creates its own contexts, but these aren't available to the
application; at least, not officially; the relevant variables (e.g
__glutCurrentWindow), aren't "static", so you could get them if you
really wanted.
Even so, you would still have to ensure that {glX,wgl}MakeCurrent was
called at the appropriate points. AFAICT, this would require either
interacting directly with the (OS) thread management code, or calling
{glX,wgl}MakeCurrent multiple times before *every* OpenGL call.
Basically, GLUT isn't so much a library as a complete (albeit very
simple) framework. It makes it easy to write simple OpenGL programs,
but it also makes it hard to write real programs.
OTOH, if you don't want to use GLUT, you have to interact with the
native window system, and use the platform-specific "glue" layer
(glX*, wgl* etc) to initialise and manage the rendering "environment"
(although particular toolkits may handle the latter part for you, e.g.
via an "OpenGL canvas" widget).
--
Glynn Clements