[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