Initial draft for EGL support
Created by: kbrenneman
This is an initial draft for a libglvnd-based ABI for libEGL.
It mostly follows a similar design to libGLX. I'll give a description of the major differences from GLX, plus a description of what sort of changes would be necessary to port an existing EGL implementation.
There's still some places that are incomplete, but the overall design should be ready to be reviewed.
Differences from GLX
Vendor library loading
The first and biggest difference from GLX is that libEGL will enumerate and load all available vendor libraries up front, instead of loading each one when it's needed.
It would be nice to avoid this, but so far I haven't found a good way to do so. Some client extensions, most notably EGL_EXT_device_enumeration, basically require loading every available vendor.
Each vendor library puts a JSON file into a well-known directory, which specifies the name of the library to load. libEGL will scan those directories and load each library that it finds. The JSON format (and the overall approach) is loosely based on Vulkan's loader.
EGLDisplay creation and dispatching
Another reason that libEGL loads all of the vendor libraries up front is that it will iterate over them to create an EGLDisplay handle. When the app calls eglGetDisplay or eglGetPlatformDisplay, libEGL will pass the call to each vendor library until it finds one that works.
The majority of EGL functions (including, by definition, all display extensions) take an EGLDisplay parameter, so almost all EGL functions are dispatched to whichever vendor library created the display.
That also means that unlike GLX, libEGL does not provide (or need) functions to look up a vendor by contexts, drawables, or configs. In fact, internally it doesn't even track them.
Right now, I've got dispatch stubs for most EGL extensions built into libEGL itself, but that's just to make testing easier. However, it should be possible to use the same script with minimal changes to generate dispatch stubs for a vendor library.
Error reporting
This is a bit more awkward than GLX.
libEGL keeps track of either the last error code, or the last vendor library that it called into. That way, when the application calls eglGetError, libEGL can either return the last error code or forward the call to the vendor's eglGetError implementation.
libEGL also implements the EGL_KHR_debug extension, but it will only directly report errors that it generates. It will pass eglDebugMessageControlKHR and eglLabelObjectKHR calls through to the vendor libraries. The vendor libraries, in turn, are responsible for calling the debug callback for any errors that they generate.
The practical offshoot of this is that the same non-libglvnd-based implementation of eglGetError and EGL_KHR_debug should work with libglvnd without any modification.
Note, however, that the way EGL_KHR_debug is supposed to work means that every vendor library has to support it.
Vendor library porting and requirements
At the most basic, each vendor library has to support EGL 1.4, EGL_EXT_client_extensions, EGL_KHR_debug, and EGL_KHR_get_all_proc_addresses. In addition, the eglGetDisplay/eglGetPlatformDisplay handling requires a function equivalent to EGL 1.5's eglGetPlatformDisplay.
Object handles
EGLDisplay and EGLDeviceEXT handles must be real pointers to ensure that they're unique between vendor libraries. This is the same requirement that GLX has for GLXContext handles.
Other EGL objects (EGLContext, EGLConfig, EGLSurface, etc) are all owned by an EGLDisplay, so they have no particular requirements. Vendor libraries can use whatever they want for them.
Client extension string
The client extension string has to be split into two strings, one for platform extensions and one for everything else.
Most platform extensions don't require any special handling from libEGL. Using a separate string allows libEGL to report those extensions unconditionally.
Other client extensions (by definition) do require support from libEGL. For those, libEGL will report a client extension only if both libEGL and at least one vendor library supports it.
Current rendering API
libEGL currently only supports EGL_OPENGL_API and EGL_OPENGL_ES_API. If we ever add OpenVG, then we'll increment the major version number in the interface.
libEGL will keep track of the current rendering API, and it will also pass eglBindAPI calls through to all vendor libraries. Vendor libraries can either keep track of the current API on their own (like they would for a non-glvnd driver), or they can call back into libEGL to query the current API.
Each vendor library must accept both EGL_OPENGL_API and EGL_OPENGL_ES_API in eglBindAPI without error. However, a vendor doesn't actually have to support both in any given EGLDisplay.
In practice, this shouldn't be much of a problem. EGL_OPENGL_API and EGL_OPENGL_ES_API are interchangeable for all purposes except eglCreateContext, so the vendor's eglCreateContext implementation is the only place where it has to actually check the current API.
Other functions
eglReleaseThread, eglDebugMessageControlKHR, and eglLabelObjectKHR with EGL_OBJECT_THREAD_KHR must not fail (or rather, libEGL will ignore any failures). All three are forwarded to every vendor library, so if one vendor library fails and another succeeds, then it could wind up in an inconsistent state.