gfx/gl/GLContextProviderGLX.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifdef MOZ_WIDGET_GTK
     7 #include <gdk/gdk.h>
     8 #include <gdk/gdkx.h>
     9 #define GET_NATIVE_WINDOW(aWidget) GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
    10 #elif defined(MOZ_WIDGET_QT)
    11 #define GET_NATIVE_WINDOW(aWidget) (Window)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
    12 #endif
    14 #include <X11/Xlib.h>
    15 #include <X11/Xutil.h>
    17 #include "mozilla/MathAlgorithms.h"
    18 #include "mozilla/StaticPtr.h"
    19 #include "mozilla/X11Util.h"
    21 #include "prenv.h"
    22 #include "GLContextProvider.h"
    23 #include "GLLibraryLoader.h"
    24 #include "nsDebug.h"
    25 #include "nsIWidget.h"
    26 #include "GLXLibrary.h"
    27 #include "gfxXlibSurface.h"
    28 #include "gfxContext.h"
    29 #include "gfxPlatform.h"
    30 #include "GLContextGLX.h"
    31 #include "gfxUtils.h"
    32 #include "gfx2DGlue.h"
    34 #include "gfxCrashReporterUtils.h"
    36 #ifdef MOZ_WIDGET_GTK
    37 #include "gfxPlatformGtk.h"
    38 #endif
    40 using namespace mozilla::gfx;
    42 namespace mozilla {
    43 namespace gl {
    45 GLXLibrary sGLXLibrary;
    47 // Check that we have at least version aMajor.aMinor .
    48 bool
    49 GLXLibrary::GLXVersionCheck(int aMajor, int aMinor)
    50 {
    51     return aMajor < mGLXMajorVersion ||
    52            (aMajor == mGLXMajorVersion && aMinor <= mGLXMinorVersion);
    53 }
    55 static inline bool
    56 HasExtension(const char* aExtensions, const char* aRequiredExtension)
    57 {
    58     return GLContext::ListHasExtension(
    59         reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
    60 }
    62 bool
    63 GLXLibrary::EnsureInitialized()
    64 {
    65     if (mInitialized) {
    66         return true;
    67     }
    69     // Don't repeatedly try to initialize.
    70     if (mTriedInitializing) {
    71         return false;
    72     }
    73     mTriedInitializing = true;
    75     // Force enabling s3 texture compression. (Bug 774134)
    76     PR_SetEnv("force_s3tc_enable=true");
    78     if (!mOGLLibrary) {
    79         const char* libGLfilename = nullptr;
    80         bool forceFeatureReport = false;
    82         // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1
    83         // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls,
    84         // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225
    85 #ifdef __OpenBSD__
    86         libGLfilename = "libGL.so";
    87 #else
    88         libGLfilename = "libGL.so.1";
    89 #endif
    91         ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport);
    92         mOGLLibrary = PR_LoadLibrary(libGLfilename);
    93         if (!mOGLLibrary) {
    94             NS_WARNING("Couldn't load OpenGL shared library.");
    95             return false;
    96         }
    97         reporter.SetSuccessful();
    98     }
   100     if (PR_GetEnv("MOZ_GLX_DEBUG")) {
   101         mDebug = true;
   102     }
   104     GLLibraryLoader::SymLoadStruct symbols[] = {
   105         /* functions that were in GLX 1.0 */
   106         { (PRFuncPtr*) &xDestroyContextInternal, { "glXDestroyContext", nullptr } },
   107         { (PRFuncPtr*) &xMakeCurrentInternal, { "glXMakeCurrent", nullptr } },
   108         { (PRFuncPtr*) &xSwapBuffersInternal, { "glXSwapBuffers", nullptr } },
   109         { (PRFuncPtr*) &xQueryVersionInternal, { "glXQueryVersion", nullptr } },
   110         { (PRFuncPtr*) &xGetCurrentContextInternal, { "glXGetCurrentContext", nullptr } },
   111         { (PRFuncPtr*) &xWaitGLInternal, { "glXWaitGL", nullptr } },
   112         { (PRFuncPtr*) &xWaitXInternal, { "glXWaitX", nullptr } },
   113         /* functions introduced in GLX 1.1 */
   114         { (PRFuncPtr*) &xQueryExtensionsStringInternal, { "glXQueryExtensionsString", nullptr } },
   115         { (PRFuncPtr*) &xGetClientStringInternal, { "glXGetClientString", nullptr } },
   116         { (PRFuncPtr*) &xQueryServerStringInternal, { "glXQueryServerString", nullptr } },
   117         { nullptr, { nullptr } }
   118     };
   120     GLLibraryLoader::SymLoadStruct symbols13[] = {
   121         /* functions introduced in GLX 1.3 */
   122         { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfig", nullptr } },
   123         { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttrib", nullptr } },
   124         // WARNING: xGetFBConfigs not set in symbols13_ext
   125         { (PRFuncPtr*) &xGetFBConfigsInternal, { "glXGetFBConfigs", nullptr } },
   126         // WARNING: symbols13_ext sets xCreateGLXPixmapWithConfig instead
   127         { (PRFuncPtr*) &xCreatePixmapInternal, { "glXCreatePixmap", nullptr } },
   128         { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyPixmap", nullptr } },
   129         { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateNewContext", nullptr } },
   130         { nullptr, { nullptr } }
   131     };
   133     GLLibraryLoader::SymLoadStruct symbols13_ext[] = {
   134         /* extension equivalents for functions introduced in GLX 1.3 */
   135         // GLX_SGIX_fbconfig extension
   136         { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfigSGIX", nullptr } },
   137         { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttribSGIX", nullptr } },
   138         // WARNING: no xGetFBConfigs equivalent in extensions
   139         // WARNING: different from symbols13:
   140         { (PRFuncPtr*) &xCreateGLXPixmapWithConfigInternal, { "glXCreateGLXPixmapWithConfigSGIX", nullptr } },
   141         { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyGLXPixmap", nullptr } }, // not from ext
   142         { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateContextWithConfigSGIX", nullptr } },
   143         { nullptr, { nullptr } }
   144     };
   146     GLLibraryLoader::SymLoadStruct symbols14[] = {
   147         /* functions introduced in GLX 1.4 */
   148         { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddress", nullptr } },
   149         { nullptr, { nullptr } }
   150     };
   152     GLLibraryLoader::SymLoadStruct symbols14_ext[] = {
   153         /* extension equivalents for functions introduced in GLX 1.4 */
   154         // GLX_ARB_get_proc_address extension
   155         { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddressARB", nullptr } },
   156         { nullptr, { nullptr } }
   157     };
   159     GLLibraryLoader::SymLoadStruct symbols_texturefrompixmap[] = {
   160         { (PRFuncPtr*) &xBindTexImageInternal, { "glXBindTexImageEXT", nullptr } },
   161         { (PRFuncPtr*) &xReleaseTexImageInternal, { "glXReleaseTexImageEXT", nullptr } },
   162         { nullptr, { nullptr } }
   163     };
   165     GLLibraryLoader::SymLoadStruct symbols_robustness[] = {
   166         { (PRFuncPtr*) &xCreateContextAttribsInternal, { "glXCreateContextAttribsARB", nullptr } },
   167         { nullptr, { nullptr } }
   168     };
   170     if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
   171         NS_WARNING("Couldn't find required entry point in OpenGL shared library");
   172         return false;
   173     }
   175     Display *display = DefaultXDisplay();
   176     int screen = DefaultScreen(display);
   178     if (!xQueryVersion(display, &mGLXMajorVersion, &mGLXMinorVersion)) {
   179         mGLXMajorVersion = 0;
   180         mGLXMinorVersion = 0;
   181         return false;
   182     }
   184     if (!GLXVersionCheck(1, 1))
   185         // Not possible to query for extensions.
   186         return false;
   188     const char *clientVendor = xGetClientString(display, LOCAL_GLX_VENDOR);
   189     const char *serverVendor = xQueryServerString(display, screen, LOCAL_GLX_VENDOR);
   190     const char *extensionsStr = xQueryExtensionsString(display, screen);
   192     GLLibraryLoader::SymLoadStruct *sym13;
   193     if (!GLXVersionCheck(1, 3)) {
   194         // Even if we don't have 1.3, we might have equivalent extensions
   195         // (as on the Intel X server).
   196         if (!HasExtension(extensionsStr, "GLX_SGIX_fbconfig")) {
   197             return false;
   198         }
   199         sym13 = symbols13_ext;
   200     } else {
   201         sym13 = symbols13;
   202     }
   203     if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym13)) {
   204         NS_WARNING("Couldn't find required entry point in OpenGL shared library");
   205         return false;
   206     }
   208     GLLibraryLoader::SymLoadStruct *sym14;
   209     if (!GLXVersionCheck(1, 4)) {
   210         // Even if we don't have 1.4, we might have equivalent extensions
   211         // (as on the Intel X server).
   212         if (!HasExtension(extensionsStr, "GLX_ARB_get_proc_address")) {
   213             return false;
   214         }
   215         sym14 = symbols14_ext;
   216     } else {
   217         sym14 = symbols14;
   218     }
   219     if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym14)) {
   220         NS_WARNING("Couldn't find required entry point in OpenGL shared library");
   221         return false;
   222     }
   224     if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") &&
   225         GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_texturefrompixmap,
   226                                          (GLLibraryLoader::PlatformLookupFunction)&xGetProcAddress))
   227     {
   228 #ifdef MOZ_WIDGET_GTK
   229         mUseTextureFromPixmap = gfxPlatformGtk::GetPlatform()->UseXRender();
   230 #else
   231         mUseTextureFromPixmap = true;
   232 #endif
   233     } else {
   234         mUseTextureFromPixmap = false;
   235         NS_WARNING("Texture from pixmap disabled");
   236     }
   238     if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") &&
   239         GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) {
   240         mHasRobustness = true;
   241     }
   243     mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI");
   244     mIsNVIDIA = serverVendor && DoesStringMatch(serverVendor, "NVIDIA Corporation");
   245     mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa");
   247     mInitialized = true;
   249     return true;
   250 }
   252 bool
   253 GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface)
   254 {
   255     if (!EnsureInitialized()) {
   256         return false;
   257     }
   259     if (aSurface->GetType() != gfxSurfaceType::Xlib || !mUseTextureFromPixmap) {
   260         return false;
   261     }
   263     return true;
   264 }
   266 GLXPixmap
   267 GLXLibrary::CreatePixmap(gfxASurface* aSurface)
   268 {
   269     if (!SupportsTextureFromPixmap(aSurface)) {
   270         return None;
   271     }
   273     gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
   274     const XRenderPictFormat *format = xs->XRenderFormat();
   275     if (!format || format->type != PictTypeDirect) {
   276         return None;
   277     }
   278     const XRenderDirectFormat& direct = format->direct;
   279     int alphaSize = FloorLog2(direct.alphaMask + 1);
   280     NS_ASSERTION((1 << alphaSize) - 1 == direct.alphaMask,
   281                  "Unexpected render format with non-adjacent alpha bits");
   283     int attribs[] = { LOCAL_GLX_DOUBLEBUFFER, False,
   284                       LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
   285                       LOCAL_GLX_ALPHA_SIZE, alphaSize,
   286                       (alphaSize ? LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT
   287                        : LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT), True,
   288                       LOCAL_GLX_RENDER_TYPE, LOCAL_GLX_RGBA_BIT,
   289                       None };
   291     int numConfigs = 0;
   292     Display *display = xs->XDisplay();
   293     int xscreen = DefaultScreen(display);
   295     ScopedXFree<GLXFBConfig> cfgs(xChooseFBConfig(display,
   296                                                   xscreen,
   297                                                   attribs,
   298                                                   &numConfigs));
   300     // Find an fbconfig that matches the pixel format used on the Pixmap.
   301     int matchIndex = -1;
   302     unsigned long redMask =
   303         static_cast<unsigned long>(direct.redMask) << direct.red;
   304     unsigned long greenMask =
   305         static_cast<unsigned long>(direct.greenMask) << direct.green;
   306     unsigned long blueMask =
   307         static_cast<unsigned long>(direct.blueMask) << direct.blue;
   308     // This is true if the Pixmap has bits for alpha or unused bits.
   309     bool haveNonColorBits =
   310         ~(redMask | greenMask | blueMask) != -1UL << format->depth;
   312     for (int i = 0; i < numConfigs; i++) {
   313         int id = None;
   314         sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &id);
   315         Visual *visual;
   316         int depth;
   317         FindVisualAndDepth(display, id, &visual, &depth);
   318         if (!visual ||
   319             visual->c_class != TrueColor ||
   320             visual->red_mask != redMask ||
   321             visual->green_mask != greenMask ||
   322             visual->blue_mask != blueMask ) {
   323             continue;
   324         }
   326         // Historically Xlib Visuals did not try to represent an alpha channel
   327         // and there was no means to use an alpha channel on a Pixmap.  The
   328         // Xlib Visual from the fbconfig was not intended to have any
   329         // information about alpha bits.
   330         //
   331         // Since then, RENDER has added formats for 32 bit depth Pixmaps.
   332         // Some of these formats have bits for alpha and some have unused
   333         // bits.
   334         //
   335         // Then the Composite extension added a 32 bit depth Visual intended
   336         // for Windows with an alpha channel, so bits not in the visual color
   337         // masks were expected to be treated as alpha bits.
   338         //
   339         // Usually GLX counts only color bits in the Visual depth, but the
   340         // depth of Composite's ARGB Visual includes alpha bits.  However,
   341         // bits not in the color masks are not necessarily alpha bits because
   342         // sometimes (NVIDIA) 32 bit Visuals are added for fbconfigs with 32
   343         // bit BUFFER_SIZE but zero alpha bits and 24 color bits (NVIDIA
   344         // again).
   345         //
   346         // This checks that the depth matches in one of the two ways.
   347         // NVIDIA now forces format->depth == depth so only the first way
   348         // is checked for NVIDIA
   349         if (depth != format->depth &&
   350             (mIsNVIDIA || depth != format->depth - alphaSize) ) {
   351             continue;
   352         }
   354         // If all bits of the Pixmap are color bits and the Pixmap depth
   355         // matches the depth of the fbconfig visual, then we can assume that
   356         // the driver will do whatever is necessary to ensure that any
   357         // GLXPixmap alpha bits are treated as set.  We can skip the
   358         // ALPHA_SIZE check in this situation.  We need to skip this check for
   359         // situations (ATI) where there are no fbconfigs without alpha bits.
   360         //
   361         // glXChooseFBConfig should prefer configs with smaller
   362         // LOCAL_GLX_BUFFER_SIZE, so we should still get zero alpha bits if
   363         // available, except perhaps with NVIDIA drivers where buffer size is
   364         // not the specified sum of the component sizes.
   365         if (haveNonColorBits) {
   366             // There are bits in the Pixmap format that haven't been matched
   367             // against the fbconfig visual.  These bits could either represent
   368             // alpha or be unused, so just check that the number of alpha bits
   369             // matches.
   370             int size = 0;
   371             sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i],
   372                                            LOCAL_GLX_ALPHA_SIZE, &size);
   373             if (size != alphaSize) {
   374                 continue;
   375             }
   376         }
   378         matchIndex = i;
   379         break;
   380     }
   381     if (matchIndex == -1) {
   382         // GLX can't handle A8 surfaces, so this is not really unexpected. The
   383         // caller should deal with this situation.
   384         NS_WARN_IF_FALSE(format->depth == 8,
   385                          "[GLX] Couldn't find a FBConfig matching Pixmap format");
   386         return None;
   387     }
   389     int pixmapAttribs[] = { LOCAL_GLX_TEXTURE_TARGET_EXT, LOCAL_GLX_TEXTURE_2D_EXT,
   390                             LOCAL_GLX_TEXTURE_FORMAT_EXT,
   391                             (alphaSize ? LOCAL_GLX_TEXTURE_FORMAT_RGBA_EXT
   392                              : LOCAL_GLX_TEXTURE_FORMAT_RGB_EXT),
   393                             None};
   395     GLXPixmap glxpixmap = xCreatePixmap(display,
   396                                         cfgs[matchIndex],
   397                                         xs->XDrawable(),
   398                                         pixmapAttribs);
   400     return glxpixmap;
   401 }
   403 void
   404 GLXLibrary::DestroyPixmap(Display* aDisplay, GLXPixmap aPixmap)
   405 {
   406     if (!mUseTextureFromPixmap) {
   407         return;
   408     }
   410     xDestroyPixmap(aDisplay, aPixmap);
   411 }
   413 void
   414 GLXLibrary::BindTexImage(Display* aDisplay, GLXPixmap aPixmap)
   415 {
   416     if (!mUseTextureFromPixmap) {
   417         return;
   418     }
   420     // Make sure all X drawing to the surface has finished before binding to a texture.
   421     if (mClientIsMesa) {
   422         // Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a
   423         // noop when direct rendering unless the current drawable is a
   424         // single-buffer window.
   425         FinishX(aDisplay);
   426     } else {
   427         xWaitX();
   428     }
   429     xBindTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT, nullptr);
   430 }
   432 void
   433 GLXLibrary::ReleaseTexImage(Display* aDisplay, GLXPixmap aPixmap)
   434 {
   435     if (!mUseTextureFromPixmap) {
   436         return;
   437     }
   439     xReleaseTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT);
   440 }
   442 void
   443 GLXLibrary::UpdateTexImage(Display* aDisplay, GLXPixmap aPixmap)
   444 {
   445     // NVIDIA drivers don't require a rebind of the pixmap in order
   446     // to display an updated image, and it's faster not to do it.
   447     if (mIsNVIDIA) {
   448         xWaitX();
   449         return;
   450     }
   452     ReleaseTexImage(aDisplay, aPixmap);
   453     BindTexImage(aDisplay, aPixmap);
   454 }
   456 #ifdef DEBUG
   458 static int (*sOldErrorHandler)(Display *, XErrorEvent *);
   459 ScopedXErrorHandler::ErrorEvent sErrorEvent;
   460 static int GLXErrorHandler(Display *display, XErrorEvent *ev)
   461 {
   462     if (!sErrorEvent.mError.error_code) {
   463         sErrorEvent.mError = *ev;
   464     }
   465     return 0;
   466 }
   468 void
   469 GLXLibrary::BeforeGLXCall()
   470 {
   471     if (mDebug) {
   472         sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
   473     }
   474 }
   476 void
   477 GLXLibrary::AfterGLXCall()
   478 {
   479     if (mDebug) {
   480         FinishX(DefaultXDisplay());
   481         if (sErrorEvent.mError.error_code) {
   482             char buffer[2048];
   483             XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer));
   484             printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %i",
   485                           buffer,
   486                           sErrorEvent.mError.error_code,
   487                           sErrorEvent.mError.request_code,
   488                           sErrorEvent.mError.minor_code,
   489                           sErrorEvent.mError.serial);
   490             NS_ABORT();
   491         }
   492         XSetErrorHandler(sOldErrorHandler);
   493     }
   494 }
   496 #define BEFORE_GLX_CALL do {           \
   497     sGLXLibrary.BeforeGLXCall();       \
   498 } while (0)
   500 #define AFTER_GLX_CALL do {            \
   501     sGLXLibrary.AfterGLXCall();        \
   502 } while (0)
   504 #else
   506 #define BEFORE_GLX_CALL do { } while(0)
   507 #define AFTER_GLX_CALL do { } while(0)
   509 #endif
   511 void
   512 GLXLibrary::xDestroyContext(Display* display, GLXContext context)
   513 {
   514     BEFORE_GLX_CALL;
   515     xDestroyContextInternal(display, context);
   516     AFTER_GLX_CALL;
   517 }
   519 Bool
   520 GLXLibrary::xMakeCurrent(Display* display,
   521                          GLXDrawable drawable,
   522                          GLXContext context)
   523 {
   524     BEFORE_GLX_CALL;
   525     Bool result = xMakeCurrentInternal(display, drawable, context);
   526     AFTER_GLX_CALL;
   527     return result;
   528 }
   530 GLXContext
   531 GLXLibrary::xGetCurrentContext()
   532 {
   533     BEFORE_GLX_CALL;
   534     GLXContext result = xGetCurrentContextInternal();
   535     AFTER_GLX_CALL;
   536     return result;
   537 }
   539 /* static */ void*
   540 GLXLibrary::xGetProcAddress(const char *procName)
   541 {
   542     BEFORE_GLX_CALL;
   543     void* result = sGLXLibrary.xGetProcAddressInternal(procName);
   544     AFTER_GLX_CALL;
   545     return result;
   546 }
   548 GLXFBConfig*
   549 GLXLibrary::xChooseFBConfig(Display* display,
   550                             int screen,
   551                             const int *attrib_list,
   552                             int *nelements)
   553 {
   554     BEFORE_GLX_CALL;
   555     GLXFBConfig* result = xChooseFBConfigInternal(display, screen, attrib_list, nelements);
   556     AFTER_GLX_CALL;
   557     return result;
   558 }
   560 GLXFBConfig*
   561 GLXLibrary::xGetFBConfigs(Display* display,
   562                           int screen,
   563                           int *nelements)
   564 {
   565     BEFORE_GLX_CALL;
   566     GLXFBConfig* result = xGetFBConfigsInternal(display, screen, nelements);
   567     AFTER_GLX_CALL;
   568     return result;
   569 }
   571 GLXContext
   572 GLXLibrary::xCreateNewContext(Display* display,
   573                               GLXFBConfig config,
   574                               int render_type,
   575                               GLXContext share_list,
   576                               Bool direct)
   577 {
   578     BEFORE_GLX_CALL;
   579     GLXContext result = xCreateNewContextInternal(display, config,
   580                                                   render_type,
   581                                                   share_list, direct);
   582     AFTER_GLX_CALL;
   583     return result;
   584 }
   586 int
   587 GLXLibrary::xGetFBConfigAttrib(Display *display,
   588                                GLXFBConfig config,
   589                                int attribute,
   590                                int *value)
   591 {
   592     BEFORE_GLX_CALL;
   593     int result = xGetFBConfigAttribInternal(display, config,
   594                                             attribute, value);
   595     AFTER_GLX_CALL;
   596     return result;
   597 }
   599 void
   600 GLXLibrary::xSwapBuffers(Display *display, GLXDrawable drawable)
   601 {
   602     BEFORE_GLX_CALL;
   603     xSwapBuffersInternal(display, drawable);
   604     AFTER_GLX_CALL;
   605 }
   607 const char *
   608 GLXLibrary::xQueryExtensionsString(Display *display,
   609                                    int screen)
   610 {
   611     BEFORE_GLX_CALL;
   612     const char *result = xQueryExtensionsStringInternal(display, screen);
   613     AFTER_GLX_CALL;
   614     return result;
   615 }
   617 const char *
   618 GLXLibrary::xGetClientString(Display *display,
   619                              int screen)
   620 {
   621     BEFORE_GLX_CALL;
   622     const char *result = xGetClientStringInternal(display, screen);
   623     AFTER_GLX_CALL;
   624     return result;
   625 }
   627 const char *
   628 GLXLibrary::xQueryServerString(Display *display,
   629                                int screen, int name)
   630 {
   631     BEFORE_GLX_CALL;
   632     const char *result = xQueryServerStringInternal(display, screen, name);
   633     AFTER_GLX_CALL;
   634     return result;
   635 }
   637 GLXPixmap
   638 GLXLibrary::xCreatePixmap(Display *display,
   639                           GLXFBConfig config,
   640                           Pixmap pixmap,
   641                           const int *attrib_list)
   642 {
   643     BEFORE_GLX_CALL;
   644     GLXPixmap result = xCreatePixmapInternal(display, config,
   645                                              pixmap, attrib_list);
   646     AFTER_GLX_CALL;
   647     return result;
   648 }
   650 GLXPixmap
   651 GLXLibrary::xCreateGLXPixmapWithConfig(Display *display,
   652                                        GLXFBConfig config,
   653                                        Pixmap pixmap)
   654 {
   655     BEFORE_GLX_CALL;
   656     GLXPixmap result = xCreateGLXPixmapWithConfigInternal(display, config, pixmap);
   657     AFTER_GLX_CALL;
   658     return result;
   659 }
   661 void
   662 GLXLibrary::xDestroyPixmap(Display *display, GLXPixmap pixmap)
   663 {
   664     BEFORE_GLX_CALL;
   665     xDestroyPixmapInternal(display, pixmap);
   666     AFTER_GLX_CALL;
   667 }
   669 Bool
   670 GLXLibrary::xQueryVersion(Display *display,
   671                           int *major,
   672                           int *minor)
   673 {
   674     BEFORE_GLX_CALL;
   675     Bool result = xQueryVersionInternal(display, major, minor);
   676     AFTER_GLX_CALL;
   677     return result;
   678 }
   680 void
   681 GLXLibrary::xBindTexImage(Display *display,
   682                           GLXDrawable drawable,
   683                           int buffer,
   684                           const int *attrib_list)
   685 {
   686     BEFORE_GLX_CALL;
   687     xBindTexImageInternal(display, drawable, buffer, attrib_list);
   688     AFTER_GLX_CALL;
   689 }
   691 void
   692 GLXLibrary::xReleaseTexImage(Display *display,
   693                              GLXDrawable drawable,
   694                              int buffer)
   695 {
   696     BEFORE_GLX_CALL;
   697     xReleaseTexImageInternal(display, drawable, buffer);
   698     AFTER_GLX_CALL;
   699 }
   701 void
   702 GLXLibrary::xWaitGL()
   703 {
   704     BEFORE_GLX_CALL;
   705     xWaitGLInternal();
   706     AFTER_GLX_CALL;
   707 }
   709 void
   710 GLXLibrary::xWaitX()
   711 {
   712     BEFORE_GLX_CALL;
   713     xWaitXInternal();
   714     AFTER_GLX_CALL;
   715 }
   717 GLXContext
   718 GLXLibrary::xCreateContextAttribs(Display* display,
   719                                   GLXFBConfig config,
   720                                   GLXContext share_list,
   721                                   Bool direct,
   722                                   const int* attrib_list)
   723 {
   724     BEFORE_GLX_CALL;
   725     GLXContext result = xCreateContextAttribsInternal(display,
   726                                                       config,
   727                                                       share_list,
   728                                                       direct,
   729                                                       attrib_list);
   730     AFTER_GLX_CALL;
   731     return result;
   732 }
   734 already_AddRefed<GLContextGLX>
   735 GLContextGLX::CreateGLContext(
   736                   const SurfaceCaps& caps,
   737                   GLContextGLX* shareContext,
   738                   bool isOffscreen,
   739                   Display* display,
   740                   GLXDrawable drawable,
   741                   GLXFBConfig cfg,
   742                   bool deleteDrawable,
   743                   gfxXlibSurface* pixmap)
   744 {
   745     GLXLibrary& glx = sGLXLibrary;
   747     int db = 0;
   748     int err = glx.xGetFBConfigAttrib(display, cfg,
   749                                       LOCAL_GLX_DOUBLEBUFFER, &db);
   750     if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
   751 #ifdef DEBUG
   752         if (DebugMode()) {
   753             printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
   754         }
   755 #endif
   756     }
   758     GLXContext context;
   759     nsRefPtr<GLContextGLX> glContext;
   760     bool error;
   762     ScopedXErrorHandler xErrorHandler;
   764 TRY_AGAIN_NO_SHARING:
   766     error = false;
   768     GLXContext glxContext = shareContext ? shareContext->mContext : nullptr;
   769     if (glx.HasRobustness()) {
   770         int attrib_list[] = {
   771             LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
   772             LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB,
   773             0,
   774         };
   776         context = glx.xCreateContextAttribs(
   777             display,
   778             cfg,
   779             glxContext,
   780             True,
   781             attrib_list);
   782     } else {
   783         context = glx.xCreateNewContext(
   784             display,
   785             cfg,
   786             LOCAL_GLX_RGBA_TYPE,
   787             glxContext,
   788             True);
   789     }
   791     if (context) {
   792         glContext = new GLContextGLX(caps,
   793                                       shareContext,
   794                                       isOffscreen,
   795                                       display,
   796                                       drawable,
   797                                       context,
   798                                       deleteDrawable,
   799                                       db,
   800                                       pixmap);
   801         if (!glContext->Init())
   802             error = true;
   803     } else {
   804         error = true;
   805     }
   807     error |= xErrorHandler.SyncAndGetError(display);
   809     if (error) {
   810         if (shareContext) {
   811             shareContext = nullptr;
   812             goto TRY_AGAIN_NO_SHARING;
   813         }
   815         NS_WARNING("Failed to create GLXContext!");
   816         glContext = nullptr; // note: this must be done while the graceful X error handler is set,
   817                             // because glxMakeCurrent can give a GLXBadDrawable error
   818     }
   820     return glContext.forget();
   821 }
   823 GLContextGLX::~GLContextGLX()
   824 {
   825     MarkDestroyed();
   827     // Wrapped context should not destroy glxContext/Surface
   828     if (!mOwnsContext) {
   829         return;
   830     }
   832     // see bug 659842 comment 76
   833 #ifdef DEBUG
   834     bool success =
   835 #endif
   836     mGLX->xMakeCurrent(mDisplay, None, nullptr);
   837     NS_ABORT_IF_FALSE(success,
   838         "glXMakeCurrent failed to release GL context before we call glXDestroyContext!");
   840     mGLX->xDestroyContext(mDisplay, mContext);
   842     if (mDeleteDrawable) {
   843         mGLX->xDestroyPixmap(mDisplay, mDrawable);
   844     }
   845 }
   847 bool
   848 GLContextGLX::Init()
   849 {
   850     SetupLookupFunction();
   851     if (!InitWithPrefix("gl", true)) {
   852         return false;
   853     }
   855     if (!IsExtensionSupported(EXT_framebuffer_object))
   856         return false;
   858     return true;
   859 }
   861 bool
   862 GLContextGLX::MakeCurrentImpl(bool aForce)
   863 {
   864     bool succeeded = true;
   866     // With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change.
   867     // (This is not the case with other drivers such as NVIDIA).
   868     // So avoid calling it more than necessary. Since GLX documentation says that:
   869     //     "glXGetCurrentContext returns client-side information.
   870     //      It does not make a round trip to the server."
   871     // I assume that it's not worth using our own TLS slot here.
   872     if (aForce || mGLX->xGetCurrentContext() != mContext) {
   873         succeeded = mGLX->xMakeCurrent(mDisplay, mDrawable, mContext);
   874         NS_ASSERTION(succeeded, "Failed to make GL context current!");
   875     }
   877     return succeeded;
   878 }
   880 bool
   881 GLContextGLX::IsCurrent() {
   882     return mGLX->xGetCurrentContext() == mContext;
   883 }
   885 bool
   886 GLContextGLX::SetupLookupFunction()
   887 {
   888     mLookupFunc = (PlatformLookupFunction)&GLXLibrary::xGetProcAddress;
   889     return true;
   890 }
   892 bool
   893 GLContextGLX::IsDoubleBuffered() const
   894 {
   895     return mDoubleBuffered;
   896 }
   898 bool
   899 GLContextGLX::SupportsRobustness() const
   900 {
   901     return mGLX->HasRobustness();
   902 }
   904 bool
   905 GLContextGLX::SwapBuffers()
   906 {
   907     if (!mDoubleBuffered)
   908         return false;
   909     mGLX->xSwapBuffers(mDisplay, mDrawable);
   910     mGLX->xWaitGL();
   911     return true;
   912 }
   914 GLContextGLX::GLContextGLX(
   915                   const SurfaceCaps& caps,
   916                   GLContext* shareContext,
   917                   bool isOffscreen,
   918                   Display *aDisplay,
   919                   GLXDrawable aDrawable,
   920                   GLXContext aContext,
   921                   bool aDeleteDrawable,
   922                   bool aDoubleBuffered,
   923                   gfxXlibSurface *aPixmap)
   924     : GLContext(caps, shareContext, isOffscreen),//aDeleteDrawable ? true : false, aShareContext, ),
   925       mContext(aContext),
   926       mDisplay(aDisplay),
   927       mDrawable(aDrawable),
   928       mDeleteDrawable(aDeleteDrawable),
   929       mDoubleBuffered(aDoubleBuffered),
   930       mGLX(&sGLXLibrary),
   931       mPixmap(aPixmap),
   932       mOwnsContext(true)
   933 {
   934     MOZ_ASSERT(mGLX);
   935     // See 899855
   936     SetProfileVersion(ContextProfile::OpenGLCompatibility, 200);
   937 }
   940 static GLContextGLX *
   941 GetGlobalContextGLX()
   942 {
   943     return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext());
   944 }
   946 static bool
   947 AreCompatibleVisuals(Visual *one, Visual *two)
   948 {
   949     if (one->c_class != two->c_class) {
   950         return false;
   951     }
   953     if (one->red_mask != two->red_mask ||
   954         one->green_mask != two->green_mask ||
   955         one->blue_mask != two->blue_mask) {
   956         return false;
   957     }
   959     if (one->bits_per_rgb != two->bits_per_rgb) {
   960         return false;
   961     }
   963     return true;
   964 }
   966 static StaticRefPtr<GLContext> gGlobalContext;
   968 already_AddRefed<GLContext>
   969 GLContextProviderGLX::CreateWrappingExisting(void* aContext, void* aSurface)
   970 {
   971     if (!sGLXLibrary.EnsureInitialized()) {
   972         return nullptr;
   973     }
   975     if (aContext && aSurface) {
   976         SurfaceCaps caps = SurfaceCaps::Any();
   977         nsRefPtr<GLContextGLX> glContext =
   978             new GLContextGLX(caps,
   979                              nullptr, // SharedContext
   980                              false, // Offscreen
   981                              (Display*)DefaultXDisplay(), // Display
   982                              (GLXDrawable)aSurface, (GLXContext)aContext,
   983                              false, // aDeleteDrawable,
   984                              true,
   985                              (gfxXlibSurface*)nullptr);
   987         glContext->mOwnsContext = false;
   988         gGlobalContext = glContext;
   990         return glContext.forget();
   991     }
   993     return nullptr;
   994 }
   996 already_AddRefed<GLContext>
   997 GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
   998 {
   999     if (!sGLXLibrary.EnsureInitialized()) {
  1000         return nullptr;
  1003     // Currently, we take whatever Visual the window already has, and
  1004     // try to create an fbconfig for that visual.  This isn't
  1005     // necessarily what we want in the long run; an fbconfig may not
  1006     // be available for the existing visual, or if it is, the GL
  1007     // performance might be suboptimal.  But using the existing visual
  1008     // is a relatively safe intermediate step.
  1010     Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
  1011     if (!display) {
  1012         NS_ERROR("X Display required for GLX Context provider");
  1013         return nullptr;
  1016     int xscreen = DefaultScreen(display);
  1017     Window window = GET_NATIVE_WINDOW(aWidget);
  1019     int numConfigs;
  1020     ScopedXFree<GLXFBConfig> cfgs;
  1021     if (sGLXLibrary.IsATI() ||
  1022         !sGLXLibrary.GLXVersionCheck(1, 3)) {
  1023         const int attribs[] = {
  1024             LOCAL_GLX_DOUBLEBUFFER, False,
  1026         };
  1027         cfgs = sGLXLibrary.xChooseFBConfig(display,
  1028                                            xscreen,
  1029                                            attribs,
  1030                                            &numConfigs);
  1031     } else {
  1032         cfgs = sGLXLibrary.xGetFBConfigs(display,
  1033                                          xscreen,
  1034                                          &numConfigs);
  1037     if (!cfgs) {
  1038         NS_WARNING("[GLX] glXGetFBConfigs() failed");
  1039         return nullptr;
  1041     NS_ASSERTION(numConfigs > 0, "No FBConfigs found!");
  1043     // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so
  1044     // we could probably do this first and replace the glXGetFBConfigs
  1045     // with glXChooseConfigs.  Docs are sparklingly clear as always.
  1046     XWindowAttributes widgetAttrs;
  1047     if (!XGetWindowAttributes(display, window, &widgetAttrs)) {
  1048         NS_WARNING("[GLX] XGetWindowAttributes() failed");
  1049         return nullptr;
  1051     const VisualID widgetVisualID = XVisualIDFromVisual(widgetAttrs.visual);
  1052 #ifdef DEBUG
  1053     printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID);
  1054 #endif
  1056     int matchIndex = -1;
  1058     for (int i = 0; i < numConfigs; i++) {
  1059         int visid = None;
  1060         sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid);
  1061         if (!visid) {
  1062             continue;
  1064         if (sGLXLibrary.IsATI()) {
  1065             int depth;
  1066             Visual *visual;
  1067             FindVisualAndDepth(display, visid, &visual, &depth);
  1068             if (depth == widgetAttrs.depth &&
  1069                 AreCompatibleVisuals(widgetAttrs.visual, visual)) {
  1070                 matchIndex = i;
  1071                 break;
  1073         } else {
  1074             if (widgetVisualID == static_cast<VisualID>(visid)) {
  1075                 matchIndex = i;
  1076                 break;
  1081     if (matchIndex == -1) {
  1082         NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual");
  1083         return nullptr;
  1086     GLContextGLX *shareContext = GetGlobalContextGLX();
  1088     SurfaceCaps caps = SurfaceCaps::Any();
  1089     nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(caps,
  1090                                                                      shareContext,
  1091                                                                      false,
  1092                                                                      display,
  1093                                                                      window,
  1094                                                                      cfgs[matchIndex],
  1095                                                                      false);
  1097     return glContext.forget();
  1100 static already_AddRefed<GLContextGLX>
  1101 CreateOffscreenPixmapContext(const gfxIntSize& size)
  1103     GLXLibrary& glx = sGLXLibrary;
  1104     if (!glx.EnsureInitialized()) {
  1105         return nullptr;
  1108     Display *display = DefaultXDisplay();
  1109     int xscreen = DefaultScreen(display);
  1111     int attribs[] = {
  1112         LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
  1113         LOCAL_GLX_X_RENDERABLE, True,
  1115     };
  1116     int numConfigs = 0;
  1118     ScopedXFree<GLXFBConfig> cfgs;
  1119     cfgs = glx.xChooseFBConfig(display,
  1120                                xscreen,
  1121                                attribs,
  1122                                &numConfigs);
  1123     if (!cfgs) {
  1124         return nullptr;
  1127     MOZ_ASSERT(numConfigs > 0,
  1128                "glXChooseFBConfig() failed to match our requested format and violated its spec!");
  1130     int visid = None;
  1131     int chosenIndex = 0;
  1133     for (int i = 0; i < numConfigs; ++i) {
  1134         int dtype;
  1136         if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_DRAWABLE_TYPE, &dtype) != Success
  1137             || !(dtype & LOCAL_GLX_PIXMAP_BIT))
  1139             continue;
  1141         if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid) != Success
  1142             || visid == 0)
  1144             continue;
  1147         chosenIndex = i;
  1148         break;
  1151     if (!visid) {
  1152         NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
  1153         return nullptr;
  1156     Visual *visual;
  1157     int depth;
  1158     FindVisualAndDepth(display, visid, &visual, &depth);
  1159     ScopedXErrorHandler xErrorHandler;
  1160     GLXPixmap glxpixmap = 0;
  1161     bool error = false;
  1163     gfxIntSize dummySize(16, 16);
  1164     nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
  1165                                                                visual,
  1166                                                                dummySize);
  1167     if (xsurface->CairoStatus() != 0) {
  1168         error = true;
  1169         goto DONE_CREATING_PIXMAP;
  1172     // Handle slightly different signature between glXCreatePixmap and
  1173     // its pre-GLX-1.3 extension equivalent (though given the ABI, we
  1174     // might not need to).
  1175     if (glx.GLXVersionCheck(1, 3)) {
  1176         glxpixmap = glx.xCreatePixmap(display,
  1177                                           cfgs[chosenIndex],
  1178                                           xsurface->XDrawable(),
  1179                                           nullptr);
  1180     } else {
  1181         glxpixmap = glx.xCreateGLXPixmapWithConfig(display,
  1182                                                        cfgs[chosenIndex],
  1183                                                        xsurface->
  1184                                                        XDrawable());
  1186     if (glxpixmap == 0) {
  1187         error = true;
  1190 DONE_CREATING_PIXMAP:
  1192     nsRefPtr<GLContextGLX> glContext;
  1193     bool serverError = xErrorHandler.SyncAndGetError(display);
  1195     if (!error && // earlier recorded error
  1196         !serverError)
  1198         // We might have an alpha channel, but it doesn't matter.
  1199         SurfaceCaps dummyCaps = SurfaceCaps::Any();
  1200         GLContextGLX* shareContext = GetGlobalContextGLX();
  1202         glContext = GLContextGLX::CreateGLContext(dummyCaps,
  1203                                                   shareContext,
  1204                                                   true,
  1205                                                   display,
  1206                                                   glxpixmap,
  1207                                                   cfgs[chosenIndex],
  1208                                                   true,
  1209                                                   xsurface);
  1212     return glContext.forget();
  1215 already_AddRefed<GLContext>
  1216 GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
  1217                                       const SurfaceCaps& caps)
  1219     gfxIntSize dummySize = gfxIntSize(16, 16);
  1220     nsRefPtr<GLContextGLX> glContext =
  1221         CreateOffscreenPixmapContext(dummySize);
  1223     if (!glContext)
  1224         return nullptr;
  1226     if (!glContext->InitOffscreen(ToIntSize(size), caps))
  1227         return nullptr;
  1229     return glContext.forget();
  1232 GLContext*
  1233 GLContextProviderGLX::GetGlobalContext()
  1235     static bool checkedContextSharing = false;
  1236     static bool useContextSharing = false;
  1238     if (!checkedContextSharing) {
  1239         useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
  1240         checkedContextSharing = true;
  1243     // TODO: get GLX context sharing to work well with multiple threads
  1244     if (!useContextSharing) {
  1245         return nullptr;
  1248     static bool triedToCreateContext = false;
  1249     if (!triedToCreateContext && !gGlobalContext) {
  1250         triedToCreateContext = true;
  1252         gfxIntSize dummySize = gfxIntSize(16, 16);
  1253         // StaticPtr doesn't support assignments from already_AddRefed,
  1254         // so use a temporary nsRefPtr to make the reference counting
  1255         // fall out correctly.
  1256         nsRefPtr<GLContext> holder = CreateOffscreenPixmapContext(dummySize);
  1257         gGlobalContext = holder;
  1260     return gGlobalContext;
  1263 void
  1264 GLContextProviderGLX::Shutdown()
  1266     gGlobalContext = nullptr;
  1269 } /* namespace gl */
  1270 } /* namespace mozilla */

mercurial