[Mesa-dev] Proposal for an Updated Linux OpenGL ABI

Kristian Høgsberg krh at bitplanet.net
Thu Sep 13 09:05:03 PDT 2012


On Wed, Sep 12, 2012 at 5:09 PM, Andy Ritger <aritger at nvidia.com> wrote:
> There was some recent Khronos discussion about updating the OpenGL
> Implementer's Guide for Linux, to which Ian Romanick noted that this
> topic will be discussed at XDC as part of the broad "Discuss the future
> of EGL, GLX, and OpenGL ES on Linux" agenda item.
>
> To help facilitate the XDC discussion, I've put together a straw-man
> proposal for an updated Linux OpenGL ABI.  I'm sending this out now to
> start generating feedback and ideas, to help make the XDC discussion as
> productive as possible.

>From a quick read-through, it looks like there's a lot of good ideas
in here.  I'll have a closer look before XDC, but I just wanted to add
one thing I didn't see in there: pkg-config files.  Mesa provides
pkg-config files for libGL, and the EGL and GLES libraries and I think
it would be nice to standardize that as well.

Kristian

> Thanks,
> - Andy Ritger
>
> ________________________________________________________________________
>
> 2012 Linux OpenGL ABI Proposal
>
> Background
>
>     The current Linux OpenGL ABI [1] (the "2000 Linux OpenGL ABI") is
>     twelve years old, and the industry has advanced significantly in
>     the past decade:
>
>     * EGL has emerged as a compelling alternative window system binding,
>       for use both within and without the X Window System.
>
>     * The OpenGL API has evolved, reducing pressure, in modern usage, on
>       OpenGL API call overhead.
>
>     * One of the major short comings of the current ABI is that it does
>       not allow multiple vendors' implementations to coexist on the file
>       system.  Each vendor provides libGL.so.1; this can lead to library
>       collisions and installation fights.  Each Linux distributor has
>       been forced to invent its own library search path mechanism to
>       resolve these conflicts.
>
>     * In OpenGL 3.1, portions of the OpenGL API were removed (with some
>       vendors continuing to provide the removed portions, via the
>       ARB_compatibility extension).  A new Linux OpenGL ABI should
>       potentially give vendors the option to not provide those entry
>       points.
>
> Requirements
>
>     * This document proposes a new Linux ABI for OpenGL, OpenGL ES, GLX,
>       and EGL on desktop Linux systems.  While this is hopefully
>       useful for other UNIX and UNIX-like platforms, none are called
>       out explicitly.  Further, this document does not try to standardize
>       with Android or embedded Linux sorts of scenarios.
>
>     * This document defines two ABIs:
>
>         * The ABI between applications and a vendor-independent layer.
>
>         * The ABI between a vendor-independent layer and a vendor
>           implementation.
>
>     * The existing ABI to applications must be preserved, though perhaps
>       marked deprecated.  I.e., /usr/lib/libGL.so.1 must continue to
>       exist for the foreseeable future, and continue to provide the
>       entry points and semantics guaranteed by the 2000 Linux OpenGL ABI.
>       How libGL.so.1 is implemented, and how vendor implementations fit
>       into libGL.so.1, could change relative to the 2000 Linux OpenGL ABI.
>
>     * Whatever minimum versions of OpenGL, OpenGL ES, EGL, and GLX are
>       established by this standardization document, vendors must be allowed
>       to provide extensions and newer API versions, beyond what is defined
>       in this standard.
>
>     * Multiple vendors' implementations must be able to coexist on the
>       filesystem without distribution-specific "alternatives"-style selection.
>
>     * It would be nice, from a design standpoint, to allow multiple vendor
>       implementations to co-exist within the same process, and for the API
>       library to dispatch to the current vendor library with per-context
>       granularity.
>
> Glossary
>
>     * API Library: The vendor-neutral library that contains the API entry
>       points.  In most cases, this should be fairly thin and simply dispatch
>       to the vendor implementation.
>
>     * Vendor Library: The vendor-provided library that provides the actual
>       implementation.  The vendor libraries get enumerated, selected, and loaded
>       by the API libraries.
>
>     * Window system API: one of EGL or GLX.  Conceivably other window system
>       APIs could be added in the future.
>
>     * Client API: any rendering API that is used with a window system
>       API.  OpenGL, OpenGL ES, OpenVG, etc.
>
> Libraries
>
>     The libraries to be provided are:
>
>     * libGL.so.1
>         * Provides symbols for all OpenGL 1.2 entry points (as per [1]).
>         * Provides symbols for all GLX 1.3 entry points (as per [1]).
>         * This would be a vendor-neutral API library.
>         * Hopefully would just pass through to libGLX.so.1 and libOpenGL.so.1
>           (maybe using ELF DT_FILTER; see [2] and the GNU ld(1) man page).
>
>     * libOpenGL.so.1
>         * Provides symbols for all entry points in a TBD version of OpenGL.
>         * Vendors can provide additional OpenGL entry points that can be
>           retrieved via {egl,glX}GetProcAddress.
>         * No EGL or GLX entry points are provided by this library; it
>           is expected that libOpenGL.so.1 would be used in conjunction
>           with one of the Window system libraries (libGLX.so.1 or
>           libEGL.so.1).
>         * Provides a function for vendor libraries to install a dispatch table.
>         * Provides a function for vendor libraries to report their
>           GetProcAddress-able functions.
>
>     * libGLESv1_CM.so.1:
>         * Provides symbols for all OpenGL ES 1 common profile entry points.
>
>     * libGLESv2.so.1:
>         * Provides symbols for all OpenGL ES 2 and 3 entry points.
>
>     * libEGL.so.1
>         * Provides symbols for all EGL 1.4 entry points.
>         * Loads and dispatches to one or more vendor libraries.
>
>     * libGLX.so.1
>         * Provides symbols for all GLX 1.4 entry points.
>         * Provides symbols for the GLX_ARB_create_context_profile extension.
>         * Loads and dispatches to one or more vendor libraries.
>
>     * libEGL_${VENDOR}.so.1
>         * Provides a function that libEGL.so.1 can call to initialize and
>           get the EGL dispatch table.
>         * Expected to pull in the vendor's implementation of all the client
>           APIs it supports, and register with the appropriate API library at
>           MakeCurrent time.
>         * Must not export symbols with names that collide with the namespace
>           of EGL (^egl.*) or OpenGL (^gl.*).
>
>     * libGLX_${VENDOR}.so.1
>         * Provides a function that libGLX.so.1 can call to initialize and
>           get the GLX dispatch table.
>         * Expected to pull in the vendor's implementation of all the client
>           APIs it supports, and register with the appropriate API library at
>           MakeCurrent time.
>         * Must not export symbols with names that collide with the namespace
>           of GLX (^glX.*) or OpenGL (^gl.*).
>
>     For more background, see [3].
>
>     API libraries (i.e., everything other than the vendor libraries)
>     are expected to change infrequently.  For maintenance reasons, they
>     should be as simple/thin as reasonable and dispatch to vendors for as
>     much as possible.  While Khronos members would author and maintain
>     the API libraries, the source to them would presumably be hosted by
>     Khronos, available to the general public.  We would recommend to Linux
>     distributions to package the API libraries separately from vendor
>     libraries (i.e., in separate packages from Mesa, NVIDIA, AMD, etc).
>
> GLX
>
>     The GLX API library should allow for a different vendor library per
>     X screen, and dispatch to the correct vendor as early as possible
>     (though, see Issue (9)).
>
>     GLX 1.4 entry points fall into one of several categories:
>
>     (1) Entry points that take an X Display pointer and an X screen number
>         (or, an object, such as a GLXContect or GLXDrawable, that implies
>         an X screen).  E.g.,
>
>             Bool glXMakeCurrent(Display *dpy,
>                                 GLXDrawable drawable,
>                                 GLXContext ctx);
>
>         Such functions could be implemented by dispatching to the appropriate
>         vendor library based on Display and screen.
>
>     (2) Entry points that operate on the current context.  E.g.,
>
>             void glXWaitGL(void);
>
>         Such functions could be implemented by dispatching to the appropriate
>         vendor library based on the context of the current thread.
>
>     (3) Entry points that are vendor-independent and return current state.
>         E.g.,
>
>             GLXContext glXGetCurrentContext(void);
>
>         Such functions could be implemented entirely within the GLX
>         API library.
>
>     (4) "Special functions":
>
>             void *glXGetProcAddress(const GLubyte *procName);
>             const char *glXGetClientString(Display *dpy, int name);
>
>         glXGetClientString() is addressed in the Issues section, and
>         glXGetProcAddress is addressed in the Dispatching section.
>
>     There would be an X protocol-based mechanism to map an X Display
>     pointer and screen number to GLX vendor library, presumably using
>     something like the existing X_DRI2Connect/DRI2DriverVDPAU request.
>     This would be used similarly to how VDPAU determines the vendor
>     library to load (see [4]).
>
>     At MakeCurrent time, the vendor library would call a function in
>     libOpenGL.so.1 to register its dispatch table.
>
> EGL
>
>     Similar to GLX, EGL API entry points fall into one of several categories:
>
>     (1) Entry points that take an EGLDisplay.  E.g.,
>
>             EGLSurface eglCreateWindowSurface(EGLDisplay dpy,
>                                               EGLConfig config,
>                                               EGLNativeWindowType win,
>                                               const EGLint *attrib_list);
>
>         Such functions could be implemented by dispatching to the appropriate
>         vendor library based on EGLDisplay.
>
>     (2) Entry points that operate on the current context.  E.g.,
>
>             EGLBoolean eglWaitGL(void);
>
>         Such functions could be implemented by dispatching to the appropriate
>         vendor library based on the context of the current thread.
>
>     (3) Entry points that are vendor-independent and return current state.  E.g.,
>
>             EGLContext eglGetCurrentContext(void);
>
>         Such functions could be implemented entirely within the EGL API library.
>
>     (4) "Special functions":
>
>             EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id);
>             EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
>             void *eglGetProcAddress(const char *procname);
>
>     The general dispatching approach in EGL would be the same as described
>     above for GLX.  The vendor selection, done during eglInitialize(),
>     would be more sophisticated that the GLX equivalent.
>
>     The Mesa EGL implementation appears to be almost exactly this.
>
> Dispatching
>
>     All client API library (OpenGL, OpenGL ES) entry points are
>     context-dependent.  All the entry points provided by these libraries
>     would retrieve the current dispatch table from TLS and jump to the
>     vendor implementation.
>
>     There are two categories of client API library entry points:
>
>     (1) A fixed list of entry points that all vendors must provide per
>         this document.
>
>     (2) A dynamic list of entry points (for extensions, newer versions
>         of OpenGL, etc) which would only be accessible to applications via
>         {glX,egl}GetProcAddress.  This list will vary by vendor.
>
>     For category (1), the vendor would just provide an array of function
>     pointers as the dispatch table.  The ABI standard would define a
>     dispatch table index to each entry point in this category.  The ABI
>     library would need to provide a function to the vendor library that
>     allowed the vendor to change the dispatch table pointer.
>
>     For category (2), since GetProcAddress is context-independent, the
>     API library would need to provide the union of entry points for all
>     vendor implementations.  It seems like this could be handled in
>     several different ways:
>
>     Option (a): Define the possible list, or at least the indices,
>     statically: make the dispatch table for category (2) fixed size,
>     and have some sort of centralized registry to manage indices into
>     the dispatch table.  Allocation into this table could be handled in
>     a way similar to OpenGL enum assignment (see [5]).
>
>         Pros:
>             * Easier for vendors to define this dispatch table statically
>               at compile time.
>         Cons:
>             * Need to coordinate for dispatch table index assignment.
>             * As more entry points are added, a fixed size would
>               eventually be exhausted.
>             * Potentially large and sparse dispatch tables would be
>               inefficient for memory usage.
>
>     Option (b): At run time, the API library could:
>         * Get the list of GetProcAddress-able functions from each
>           vendor library.
>         * Build the union of GetProcAddress-able functions.
>         * Assign dispatch table indices for each function.
>         * Tell the vendor libraries what dispatch table index was
>           assigned for each of their functions.
>
>         Pros:
>             * Flexible to handle an arbitrary number of functions.
>         Cons:
>             * Vendors have to build their dispatch tables at run time
>               to accommodate the dynamically assigned dispatch table indices.
>             * Need to query all vendor libraries upfront; this seems a
>               little unfortunate, since there potentially could be many
>               vendor implementations on the file system, and only a few
>               are likely to be used within the context of any one process.
>
>     Option (c): Return entry points for all GetProcAddress'ed strings.  In this
>         model, the API library would use logic like this:
>
>         * Does a dispatch function already exist for the string passed
>           into GetProcAddress?  If so, return that.
>         * Else, online generate a dispatch function for the given string.
>           Default the dispatch table to a noop function.
>         * At MakeCurrent time, the vendor library would provide all
>           the strings/function pointers that it supports and the API
>           library would need to plug those vendor functions into the
>           online-generated entry points.  I.e., effectively "lazily
>           resolve" at MakeCurrent time.
>
>         Pros:
>             * Does not require loading vendor libraries before the vendor
>               library would be otherwise needed.
>         Cons:
>             * Some complexity at MakeCurrent time to map the
>               GetProcAddress'ed entry points to the vendor functions.
>             * This would break apps who determine if a feature is
>               available via GetProcAddress (though such apps are broken:
>               they are supposed to check the extension string, per [6]).
>
> Example Control Flow
>
>     Scenario 1: Application links against libGLX.so.1 and libOpenGL.so.1:
>
>         * libOpenGL.so.1's entry points default to a dispatch table filled
>           with noop functions.
>         * Application calls any GLX entry point; libGLX.so.1 queries
>           the X server for the vendor name to use with each X screen.
>         * When application calls entry point that should be dispatched
>           to vendor, libGLX.so.1 searches defined search paths to find
>           the correct vendor library.
>         * libGLX.so.1 loads vendor library and gets its table of GLX
>           dispatch functions.
>         * libGLX.so.1 dispatches to vendor library for appropriate GLX
>           entry points.
>         * Application calls MakeCurrent, which gets dispatched to
>           vendor library.
>         * Vendor library's MakeCurrent calls libOpenGL.so.1 to plug
>           dispatch table(s) into TLS.
>         * Application calls OpenGL entry points in libOpenGL.so.1;
>           these dispatch to vendor library.
>
>     Scenario 2: Application links against libEGL.so.1 and libOpenGL.so.1:
>
>         * libOpenGL.so.1's entry points default to a dispatch table filled
>           with noop functions.
>         * Application calls eglInitialize(); EGL API library uses
>           configuration magic to select appropriate vendor driver.
>         * libEGL.so.1 loads vendor library and gets its table of EGL
>           dispatch functions.
>         * libEGL.so.1 dispatches to vendor library for appropriate EGL
>           entry points.
>         * Application calls MakeCurrent, which gets dispatched to
>           vendor library.
>         * Vendor library's MakeCurrent calls libOpenGL.so.1 to plug
>           dispatch table(s) into TLS.
>         * Application calls OpenGL entry points in libOpenGL.so.1;
>           these dispatch to vendor library.
>
>     Scenario 3: Application links against libGL.so.1
>
>         * Should be same as the libGLX.so.1 + libOpenGL.so.1 scenario.
>
> Issues
>
>     (1) Should this document mandate particular filesystem paths for
>         any of the libraries?
>
>         As long as the API libraries are in the link-time and load-time
>         search paths, leaving API library path up to distributions seems
>         acceptable.  But we ought to standardize where vendor libraries
>         should get installed (since they might be installed by the vendor,
>         rather than the distribution).
>
>     (2) glXGetClientString() is vendor-specific, but does not take a
>         screen argument (though it does take a Display pointer).  How should
>         it be implemented?
>
>         PROPOSED: The best libGLX.so.1 can do is probably the following:
>         * Enumerate all of the X screens on the X server.
>         * Query the vendor for each X screen.
>         * Get the client string for each vendor.
>         * Take the union of client strings across all vendors.
>
>     (3) How should Window System (GLX,EGL) API functions work with
>         {glX,egl}GetProcAddress?  GetProcAddress is supposed to return
>         context-independent functions.  For client-API functions,
>         dispatching can always be done based on the current context,
>         but window system layer functions must be dispatched differently
>         depending on the arguments they take.  It isn't clear how to
>         dispatch a window system layer function without knowledge of
>         its parameters.
>
>     (4) What dispatching model should be used for GetProcAddress-able
>         entry points?
>
>         PROPOSED: Option (c) from the Dispatching section: online generate
>         entry points for every string passed to GetProcAddress, and map
>         to the actual vendor's functions at MakeCurrent time.
>
>     (5) Even though it is 2012, some important OpenGL applications still
>         use immediate mode OpenGL in very API-heavy ways.  In such cases,
>         even just minimal dispatching overhead has a significant impact
>         on performance.  How can we mitigate the performance impact in
>         such scenarios?
>
>         PROPOSED: The performant solution is to online-generate code
>         directly into the top-level function of the API library.  The API
>         library should provide a function that vendors can call, when
>         they deem it thread-safe to do so, that replaces the code in an
>         API library function with vendor-provided code.
>
>     (6) How should libEGL.so select the vendor?
>
>         Mesa's EGL implementation seems like at least a good starting
>         point for these heuristics.
>
>     (7) Multiple client API libraries (libOpenGL.so.1, libGLESv2.so.1,
>         etc) provide symbols with the same name.  It is conceivable that
>         a single process may have multiple libraries loaded (either
>         explicitly loaded by an application, or chains of library
>         dependencies cause multiple of these libraries to be loaded).
>         How should symbol collisions be resolved?
>
>         As I understand it, Mesa has resolved this problem by making it
>         not matter which conflicting symbol gets loaded: the dispatch
>         table contains the union of entry points exposed by GLESv1,
>         GLESv2, and GL, and the dispatch function in each client API
>         library jumps through the same dispatch table.
>
>         Is the Mesa solution a reasonable requirement to make of all
>         vendors?  It would be fine for NVIDIA.
>
>         Alternatively, ELF symbol versioning could be used to distinguish
>         between symbols of the same name in each of the client API
>         libraries.  See "Maintaining APIs and ABIs" in Ulrich Drepper's
>         DSO Howto [7].  I've coded up a demonstration of how that might
>         work here: [8].
>
>     (8) How should OpenGL deprecation impact the Linux OpenGL ABI?
>
>         NVIDIA intends to support the OpenGL ARB_compatibility context
>         indefinitely, but other vendors may want to omit that.  In that
>         case, perhaps it would make sense to split libOpenGL.so.1 into
>         separate libraries; e.g.,
>
>             * libOpenGLv31.so.1 provides all entry points available in
>               the core profile of OpenGL 3.1.
>
>             * libOpenGLv10.so.1 provides entry points that were removed
>               in OpenGL 3.1.
>
>         The two digits identify the major.minor number of the first GL
>         version the library supports.
>
>         If an application wants to use a compatibility profile, utilizing
>         entry points in OpenGL 3.1 and any that were removed in OpenGL
>         3.1, then link against both libraries:
>
>            -lOpenGLv31 -lOpenGLv10
>
>         It would be intended that there are no symbol collisions between
>         libOpenGLv31.so.1 and libOpenGLv10.so.1.
>
>         But what happens if a future OpenGL version (M.N) removes another
>         set of entry points?  It would sort of make sense to organize
>         the libraries like this:
>
>         * libOpenGLvMN.so.1 provides all entry points available in the
>           core profile of OpenGL M.N.
>         * libOpenGLv31.so.1 provides all entry points that were removed
>           in OpenGL M.N.
>         * libOpenGLv10.so.1 provides all entry points that were removed
>           in OpenGL 3.1.
>
>         But, we should not remove entry points from libOpenGLv31.so.1.
>
>         Perhaps multiple libraries are more complicated than they are
>         worth, and we should use a single libOpenGL.so.1?
>
>     (9) How should server-side GLX be handled with multiple vendors?
>         X extensions are registered with server, not screen, scope.
>         Thus, there is not a good way for different vendors to provide
>         their server-side GLX implementation per-screen.
>
>         EGL, because it does not define any X server extension, may be
>         an easier way to allow multiple vendors to execute simultaneously
>         on different X screens.
>
>         It seems conceivable that a vendor neutral GLX server module
>         could be defined, which would dispatch to vendors' server-side
>         GLX implementations with X screen granularity.
>
>         However, that standardization effort is deferred for now: this
>         proposal is already large enough.  Plus, with the growing interest
>         in EGL, there may not be sufficient motivation to standardize
>         server-side GLX multi-vendor support.
>
>         It still seems prudent to design the client-side libGLX.so.1
>         API library to allow multiple simultaneous vendors.
>
>     (10) How should any of the vendor selection mechanisms in libEGL.so.1
>         or libGLX.so.1 interact with Dave Airlie's Prime work?
>
> References
>
>     [1] http://www.opengl.org/registry/ABI/
>     [2] http://docs.oracle.com/cd/E23824_01/html/819-0690/chapter4-4.html
>     [3] http://www.khronos.org/registry/implementers_guide.html
>     [4] http://cgit.freedesktop.org/~aplattner/libvdpau/
>     [5] http://www.opengl.org/registry/doc/enums.html
>     [6] http://www.opengl.org/registry/doc/rules.html#using
>     [7] http://www.akkadia.org/drepper/dsohowto.pdf
>     [8] http://github.com/aritger/libgl-elf-tricks-demo
>
> Revision History
>
>     #1 September 12, 2012: aritger
>         - initial version
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list