On Wed, Sep 12, 2012 at 5:09 PM, Andy Ritger <arit...@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@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev