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.


Anonymous said...

Glad to see you charging in full steam instead of giving up because there isn't something existing that does exactly what you want

Anonymous said...

...looked at SDL, concluded (possibly in error) that the Lisp OpenGL bindings weren't very complete, and moved on.

I think you are confused about SDL and OpenGL -- the two are not necessarily related. Do you mean that the SDL bindings weren't very complete? That may be true, but, like you noticed, writing the bindings are fairly trivial. Furthermore, SDL runs on (pretty much) every OS/platform out there. It features a light weight event system, which is also consistent across the various OS choices out there.

It has been a while since I wrote OpenGL code in Lisp (I did so in MCL using some contributed code that used AGL -- I should have just used SDL to start, but didn't know about how nice it is at that point), but if/when I start again, I'll definitely do so using SDL...

Anonymous said...

How does your approach compare with OpenGL via the GLX extension support in Portable CLX?

Anonymous said...

Were you going to add glouton to CLiki?

with links to

Tim Moore said...

How does your approach compare with OpenGL via the GLX extension support in Portable CLX?

The GLX extension in CLX directly implements the GLX network protocol / X extension using CLX's facilities for sending and receiving protocol requests. The API exported to the user is basically the OpenGL API (modulo some name changes). The functions in the API make GLX requests.

In glouton, the exported interface calls functions in the C OpenGL library via FFI. Those functions might make GLX requests over a socket, or they might directly interact with the graphics hardware