Monday, January 23, 2006

Munching on OpenGL in Common Lisp

First post! I wonder if those are the most common words in the first post to a blog. I'm going to skip the introductions and instead describe something I'm working on. Well, more like "hacking on" in the best sense of those words.

I've written a package called "glouton" (which means "glutton" in French; can't resist including "g" and "l" with a little cross-language action!) to do some OpenGL programming in Common Lisp. Now, if you believe what you read on comp.lang.lisp this is trivial, many bindings already exist, you can write your own bindings in an hour, etc. Whatever. I know about the "nameless bindings"
of Knut Arild Erstad, but they don't have a free license. I looked at SDL, concluded (possibly in error) that the Lisp OpenGL bindings weren't very complete, and moved on. But for me, the deal breaker in existing OpenGL bindings is that they don't work with CLX , the defacto X Windows library for Common Lisp. CLX doesn't use the C Xlib library at all; it opens a socket and makes protocol requests directly to the X server. OpenGL and GLX, on the other hand, use a combination of exchanges with the server via Xlib's connection and, in the sexiest implementations, direct manipulation of the graphics hardware, called "direct rendering." I'd really like to support direct rendering while still using CLX event handling and X requests if at all possible.

It turns out that a hack is possible. The X server returns integer IDs for all interesting resources to its clients; these IDs are valid across different connections to the X server, or even in different clients. So we can create two connections to the server, one through CLX and one using Xlib, create the window using one or the other, create a GLX context and make in current in Xlib, then set the event mask in CLX and get events for it in the CLX-based event loop. Some synchronization is necessary between the two connections, particularly after a :configure-notify event; it seems like you need to call XPending() or something on the Xlib connection in order to notify the GLX client side of a reconfiguration of the frame buffer size. This was all more-or-less working on a Macintosh PowerBook, in my first try, currently here.
And then I bought a laptop with an Nvidia graphics card, and things stopped working...

I was creating the window in CLX, which was quite easy, but the results I was now seeing were very flakey: sometimes an image would appear, sometimes it wouldn't sometimes it appear only after a few mouse clicks or resizes. I googled around to no great effect, finally finding a clue that all GLX objects have to exist in the same address space. Well, that doesn't really apply here, but I changed things around to create the window in Xlib (more involved), then look up the window in CLX and set an event mask for it to get events. TaDa! There'll be some pretty pictures up here in a later post.

At some point I'd like to dig into the sources for GLX and the drivers to see what's going on for real, but that's a project for another day. I hope this hack is portable and will continue to work!

Incidently, I first saw the two connection trick in code Gilbert Baumann wrote to interface McCLIM to Cairo. Mad props also to cffi, which is a really solid portable foreign function interface package.