Wednesday, July 8, 2009

The Eagle EGL loader

I happen to have a small side project over here that's a non-conformant, itty-bitty EGL loader for the DRI drivers. Eagle started as a test case for the dri driver interface changes I was doing for DRI2. Before the interface changes, the driver interface was GLX specific and I wanted to remove all X/GLX dependencies from the driver and make it easy to load the dri driver in an EGL framework. So eagle started as a simple loader for the driver to verify the interface changes. At some point I realized that it was pretty close to working and finished up the remaining pieces. It's still lacking a proper EGLConfig picker, but it's fairly capable and sufficient for Wayland.

Now, there's also a mesa EGL loader. The mesa code is very generic and supports EGL on GLX, EGL on gallium, EGL on swrast, whereas Eagle is strictly written to just support the new DRI driver interface. That means Eagle is very minimal, while mesa egl has some overhead (more indirection, more .so's to dlopen). The mesa EGL code doesn't have support for the new (DRI2) dri driver interface, so it only works for gallium capable drivers, specifically, it won't work for the Intel DRI driver.

Merging the Eagle code into the mesa EGL code, has a good number of benefits: the mesa code will learn how to load DRI2 drivers, I won't have to write an fbconfig chooser, and there'll be only one EGL for mesa. So there's a lot of appeal there. The downside, and the main reason I'm still keeping Eagle a separate project is that I want to experiment with the glue code API between EGL and GEM/DRM. The way you create an EGLDisplay or an EGLSurface you have to first somehow create an instance of an EGLNativeDisplayType or EGLNativeWindowType, EGLNativePixmapType and then pass that to an EGL constructor such as eglCreateWindowSurface(). I'm not a diplomat, so let me just say it as it is: that's fricking braindead! See, if you have to go outside the generic EGL API to create an EGLNativePixmapType, why can't we just skip the middle man and create the EGLSurface straight from the implementation specific code. That way we wouldn't have to pollute the EGL API with strange, useless "native" types and we wouldn't need and window and a pixmap constructor for EGL surfaces.

Anyway, the native type fiasco is just a wart in the API that I like obsessing over. There's nothing that prevents an EGL implementation, such as Eagle, from implementing it's own non-standard entry points to create an EGLSurface straight from a GEM buffer handle, for example. Or non-standard API to get at the GEM handle for the back buffer so that we can use the KMS page flipping API. Which is what Eagle does and it's the main reason that it still exists. Eagle is currently a playground where I can try out different types of constructors and extensions for integrating EGL with GEM and KMS. Once we get the KMS page flipping ioctl worked out, I'm planning to write a Eagle+KMS backend for clutter, so clutter apps can run straight on the KMS framebuffer. Next step from there would be a clutter based Wayland compositor... oh wait, isn't that what Moblin should be?


Anonymous said...

1) you had promised a GTK wayland backend in an earlier post :(

2)Is there something that stops Wayland from working with the gallium3d based EGL (all drivers are going to use gallium in a few months)

3)Congrats for the miniHoegsbers

keep up the good work :-)

Jon Leech said...

The reason you create EGL displays and window surfaces from native resources is that EGL is explicitly designed to integrate Khronos APIs into an existing native window system where this association must be made. Nothing prevents an implementation from using EGL_DEFAULT_DISPLAY and defining some dummy handle for a native window type, however.

Incidentally, calling people who design software you don't agree with "frickin' braindead" is a really, really, profoundly *bad* way to encourage them to do anything to help you out in the future.

Jon Leech

Kristian Høgsberg said...

@Jon: I understand that EGL has to integrate with whatever underlying display system, whether this is X or just a naked framebuffer. However, I don't agree with the half-hearted API entry points that EGL provides to this end.

The entry points are clearly designed to make X integration easy; I can see how you can pass an X Display or and X Window directly to the constructors. However, that's the least interesting case. Any real embedded EGL stack will have custom/proprietary functions to create the resources that back the EGLDisplay and EGLSurface. Maybe I have to pass width, height and stride to an implementation specific constructor to create the EGLNativeWindowType, which I then pass straight to eglCreateWindowSurface(). If I have to call out to implementation specific code, wouldn't it be much easier if I could just create the EGLSurface directly from an implementation specific constructor? What are the lifetime rules for the native types? Do I destroy them after creating the EGLSurface, after destroying the EGLSurface or not at all? It would be a lot accomodating not to force an implementation to invent these native types.

Ideally, the native part of the API should be described in an appendix as the recommended way of integrating with X and be optional. Creating EGLDisplay and EGLSurface directly from the implementation specific code should be the recommended way for all other implementations.

As for the "braindead" comment, that wasn't targeted at the API designers but at the API. I know that may be a academic distinction as we all take pride in our work. However, it wasn't a personal attack, it was a way to vent over a problem with an important API that I have no way to influence.

Acorn Pooley said...

You could certainly suggest or write an EGL extension that constructs an EGLSurface "from scratch" using the eglCreateWindowSurface() attrib_list to specify things like width, height etc. However, since neither EGL nor GLES is a window system, there is no mechanism for moving, resizing, restacking etc such a window, which is perhaps why such extensions have not caught on.

Also note that the "NativeWindowType" does not necessarily have to be a single type. You could have a platform whose "NativeWindowType" is a union of several objects. For example eglCreateWindowSurface could accept a window object, a GEM buffer handle, an LCDscreen object, or an overlay object, etc, cast to EGLNativeWindowType. (you might need a new attribute to indicate what type of object you are passing unless each of those objects is distinguishable on your system).