michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_WIDGET_GTK michael@0: #include michael@0: #include michael@0: #define GET_NATIVE_WINDOW(aWidget) GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW)) michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: #define GET_NATIVE_WINDOW(aWidget) (Window)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)) michael@0: #endif michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "mozilla/MathAlgorithms.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "mozilla/X11Util.h" michael@0: michael@0: #include "prenv.h" michael@0: #include "GLContextProvider.h" michael@0: #include "GLLibraryLoader.h" michael@0: #include "nsDebug.h" michael@0: #include "nsIWidget.h" michael@0: #include "GLXLibrary.h" michael@0: #include "gfxXlibSurface.h" michael@0: #include "gfxContext.h" michael@0: #include "gfxPlatform.h" michael@0: #include "GLContextGLX.h" michael@0: #include "gfxUtils.h" michael@0: #include "gfx2DGlue.h" michael@0: michael@0: #include "gfxCrashReporterUtils.h" michael@0: michael@0: #ifdef MOZ_WIDGET_GTK michael@0: #include "gfxPlatformGtk.h" michael@0: #endif michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: michael@0: GLXLibrary sGLXLibrary; michael@0: michael@0: // Check that we have at least version aMajor.aMinor . michael@0: bool michael@0: GLXLibrary::GLXVersionCheck(int aMajor, int aMinor) michael@0: { michael@0: return aMajor < mGLXMajorVersion || michael@0: (aMajor == mGLXMajorVersion && aMinor <= mGLXMinorVersion); michael@0: } michael@0: michael@0: static inline bool michael@0: HasExtension(const char* aExtensions, const char* aRequiredExtension) michael@0: { michael@0: return GLContext::ListHasExtension( michael@0: reinterpret_cast(aExtensions), aRequiredExtension); michael@0: } michael@0: michael@0: bool michael@0: GLXLibrary::EnsureInitialized() michael@0: { michael@0: if (mInitialized) { michael@0: return true; michael@0: } michael@0: michael@0: // Don't repeatedly try to initialize. michael@0: if (mTriedInitializing) { michael@0: return false; michael@0: } michael@0: mTriedInitializing = true; michael@0: michael@0: // Force enabling s3 texture compression. (Bug 774134) michael@0: PR_SetEnv("force_s3tc_enable=true"); michael@0: michael@0: if (!mOGLLibrary) { michael@0: const char* libGLfilename = nullptr; michael@0: bool forceFeatureReport = false; michael@0: michael@0: // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1 michael@0: // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls, michael@0: // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225 michael@0: #ifdef __OpenBSD__ michael@0: libGLfilename = "libGL.so"; michael@0: #else michael@0: libGLfilename = "libGL.so.1"; michael@0: #endif michael@0: michael@0: ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport); michael@0: mOGLLibrary = PR_LoadLibrary(libGLfilename); michael@0: if (!mOGLLibrary) { michael@0: NS_WARNING("Couldn't load OpenGL shared library."); michael@0: return false; michael@0: } michael@0: reporter.SetSuccessful(); michael@0: } michael@0: michael@0: if (PR_GetEnv("MOZ_GLX_DEBUG")) { michael@0: mDebug = true; michael@0: } michael@0: michael@0: GLLibraryLoader::SymLoadStruct symbols[] = { michael@0: /* functions that were in GLX 1.0 */ michael@0: { (PRFuncPtr*) &xDestroyContextInternal, { "glXDestroyContext", nullptr } }, michael@0: { (PRFuncPtr*) &xMakeCurrentInternal, { "glXMakeCurrent", nullptr } }, michael@0: { (PRFuncPtr*) &xSwapBuffersInternal, { "glXSwapBuffers", nullptr } }, michael@0: { (PRFuncPtr*) &xQueryVersionInternal, { "glXQueryVersion", nullptr } }, michael@0: { (PRFuncPtr*) &xGetCurrentContextInternal, { "glXGetCurrentContext", nullptr } }, michael@0: { (PRFuncPtr*) &xWaitGLInternal, { "glXWaitGL", nullptr } }, michael@0: { (PRFuncPtr*) &xWaitXInternal, { "glXWaitX", nullptr } }, michael@0: /* functions introduced in GLX 1.1 */ michael@0: { (PRFuncPtr*) &xQueryExtensionsStringInternal, { "glXQueryExtensionsString", nullptr } }, michael@0: { (PRFuncPtr*) &xGetClientStringInternal, { "glXGetClientString", nullptr } }, michael@0: { (PRFuncPtr*) &xQueryServerStringInternal, { "glXQueryServerString", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: GLLibraryLoader::SymLoadStruct symbols13[] = { michael@0: /* functions introduced in GLX 1.3 */ michael@0: { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfig", nullptr } }, michael@0: { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttrib", nullptr } }, michael@0: // WARNING: xGetFBConfigs not set in symbols13_ext michael@0: { (PRFuncPtr*) &xGetFBConfigsInternal, { "glXGetFBConfigs", nullptr } }, michael@0: // WARNING: symbols13_ext sets xCreateGLXPixmapWithConfig instead michael@0: { (PRFuncPtr*) &xCreatePixmapInternal, { "glXCreatePixmap", nullptr } }, michael@0: { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyPixmap", nullptr } }, michael@0: { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateNewContext", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: GLLibraryLoader::SymLoadStruct symbols13_ext[] = { michael@0: /* extension equivalents for functions introduced in GLX 1.3 */ michael@0: // GLX_SGIX_fbconfig extension michael@0: { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfigSGIX", nullptr } }, michael@0: { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttribSGIX", nullptr } }, michael@0: // WARNING: no xGetFBConfigs equivalent in extensions michael@0: // WARNING: different from symbols13: michael@0: { (PRFuncPtr*) &xCreateGLXPixmapWithConfigInternal, { "glXCreateGLXPixmapWithConfigSGIX", nullptr } }, michael@0: { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyGLXPixmap", nullptr } }, // not from ext michael@0: { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateContextWithConfigSGIX", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: GLLibraryLoader::SymLoadStruct symbols14[] = { michael@0: /* functions introduced in GLX 1.4 */ michael@0: { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddress", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: GLLibraryLoader::SymLoadStruct symbols14_ext[] = { michael@0: /* extension equivalents for functions introduced in GLX 1.4 */ michael@0: // GLX_ARB_get_proc_address extension michael@0: { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddressARB", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: GLLibraryLoader::SymLoadStruct symbols_texturefrompixmap[] = { michael@0: { (PRFuncPtr*) &xBindTexImageInternal, { "glXBindTexImageEXT", nullptr } }, michael@0: { (PRFuncPtr*) &xReleaseTexImageInternal, { "glXReleaseTexImageEXT", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: GLLibraryLoader::SymLoadStruct symbols_robustness[] = { michael@0: { (PRFuncPtr*) &xCreateContextAttribsInternal, { "glXCreateContextAttribsARB", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &symbols[0])) { michael@0: NS_WARNING("Couldn't find required entry point in OpenGL shared library"); michael@0: return false; michael@0: } michael@0: michael@0: Display *display = DefaultXDisplay(); michael@0: int screen = DefaultScreen(display); michael@0: michael@0: if (!xQueryVersion(display, &mGLXMajorVersion, &mGLXMinorVersion)) { michael@0: mGLXMajorVersion = 0; michael@0: mGLXMinorVersion = 0; michael@0: return false; michael@0: } michael@0: michael@0: if (!GLXVersionCheck(1, 1)) michael@0: // Not possible to query for extensions. michael@0: return false; michael@0: michael@0: const char *clientVendor = xGetClientString(display, LOCAL_GLX_VENDOR); michael@0: const char *serverVendor = xQueryServerString(display, screen, LOCAL_GLX_VENDOR); michael@0: const char *extensionsStr = xQueryExtensionsString(display, screen); michael@0: michael@0: GLLibraryLoader::SymLoadStruct *sym13; michael@0: if (!GLXVersionCheck(1, 3)) { michael@0: // Even if we don't have 1.3, we might have equivalent extensions michael@0: // (as on the Intel X server). michael@0: if (!HasExtension(extensionsStr, "GLX_SGIX_fbconfig")) { michael@0: return false; michael@0: } michael@0: sym13 = symbols13_ext; michael@0: } else { michael@0: sym13 = symbols13; michael@0: } michael@0: if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym13)) { michael@0: NS_WARNING("Couldn't find required entry point in OpenGL shared library"); michael@0: return false; michael@0: } michael@0: michael@0: GLLibraryLoader::SymLoadStruct *sym14; michael@0: if (!GLXVersionCheck(1, 4)) { michael@0: // Even if we don't have 1.4, we might have equivalent extensions michael@0: // (as on the Intel X server). michael@0: if (!HasExtension(extensionsStr, "GLX_ARB_get_proc_address")) { michael@0: return false; michael@0: } michael@0: sym14 = symbols14_ext; michael@0: } else { michael@0: sym14 = symbols14; michael@0: } michael@0: if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym14)) { michael@0: NS_WARNING("Couldn't find required entry point in OpenGL shared library"); michael@0: return false; michael@0: } michael@0: michael@0: if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") && michael@0: GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_texturefrompixmap, michael@0: (GLLibraryLoader::PlatformLookupFunction)&xGetProcAddress)) michael@0: { michael@0: #ifdef MOZ_WIDGET_GTK michael@0: mUseTextureFromPixmap = gfxPlatformGtk::GetPlatform()->UseXRender(); michael@0: #else michael@0: mUseTextureFromPixmap = true; michael@0: #endif michael@0: } else { michael@0: mUseTextureFromPixmap = false; michael@0: NS_WARNING("Texture from pixmap disabled"); michael@0: } michael@0: michael@0: if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") && michael@0: GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) { michael@0: mHasRobustness = true; michael@0: } michael@0: michael@0: mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI"); michael@0: mIsNVIDIA = serverVendor && DoesStringMatch(serverVendor, "NVIDIA Corporation"); michael@0: mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa"); michael@0: michael@0: mInitialized = true; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface) michael@0: { michael@0: if (!EnsureInitialized()) { michael@0: return false; michael@0: } michael@0: michael@0: if (aSurface->GetType() != gfxSurfaceType::Xlib || !mUseTextureFromPixmap) { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: GLXPixmap michael@0: GLXLibrary::CreatePixmap(gfxASurface* aSurface) michael@0: { michael@0: if (!SupportsTextureFromPixmap(aSurface)) { michael@0: return None; michael@0: } michael@0: michael@0: gfxXlibSurface *xs = static_cast(aSurface); michael@0: const XRenderPictFormat *format = xs->XRenderFormat(); michael@0: if (!format || format->type != PictTypeDirect) { michael@0: return None; michael@0: } michael@0: const XRenderDirectFormat& direct = format->direct; michael@0: int alphaSize = FloorLog2(direct.alphaMask + 1); michael@0: NS_ASSERTION((1 << alphaSize) - 1 == direct.alphaMask, michael@0: "Unexpected render format with non-adjacent alpha bits"); michael@0: michael@0: int attribs[] = { LOCAL_GLX_DOUBLEBUFFER, False, michael@0: LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT, michael@0: LOCAL_GLX_ALPHA_SIZE, alphaSize, michael@0: (alphaSize ? LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT michael@0: : LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT), True, michael@0: LOCAL_GLX_RENDER_TYPE, LOCAL_GLX_RGBA_BIT, michael@0: None }; michael@0: michael@0: int numConfigs = 0; michael@0: Display *display = xs->XDisplay(); michael@0: int xscreen = DefaultScreen(display); michael@0: michael@0: ScopedXFree cfgs(xChooseFBConfig(display, michael@0: xscreen, michael@0: attribs, michael@0: &numConfigs)); michael@0: michael@0: // Find an fbconfig that matches the pixel format used on the Pixmap. michael@0: int matchIndex = -1; michael@0: unsigned long redMask = michael@0: static_cast(direct.redMask) << direct.red; michael@0: unsigned long greenMask = michael@0: static_cast(direct.greenMask) << direct.green; michael@0: unsigned long blueMask = michael@0: static_cast(direct.blueMask) << direct.blue; michael@0: // This is true if the Pixmap has bits for alpha or unused bits. michael@0: bool haveNonColorBits = michael@0: ~(redMask | greenMask | blueMask) != -1UL << format->depth; michael@0: michael@0: for (int i = 0; i < numConfigs; i++) { michael@0: int id = None; michael@0: sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &id); michael@0: Visual *visual; michael@0: int depth; michael@0: FindVisualAndDepth(display, id, &visual, &depth); michael@0: if (!visual || michael@0: visual->c_class != TrueColor || michael@0: visual->red_mask != redMask || michael@0: visual->green_mask != greenMask || michael@0: visual->blue_mask != blueMask ) { michael@0: continue; michael@0: } michael@0: michael@0: // Historically Xlib Visuals did not try to represent an alpha channel michael@0: // and there was no means to use an alpha channel on a Pixmap. The michael@0: // Xlib Visual from the fbconfig was not intended to have any michael@0: // information about alpha bits. michael@0: // michael@0: // Since then, RENDER has added formats for 32 bit depth Pixmaps. michael@0: // Some of these formats have bits for alpha and some have unused michael@0: // bits. michael@0: // michael@0: // Then the Composite extension added a 32 bit depth Visual intended michael@0: // for Windows with an alpha channel, so bits not in the visual color michael@0: // masks were expected to be treated as alpha bits. michael@0: // michael@0: // Usually GLX counts only color bits in the Visual depth, but the michael@0: // depth of Composite's ARGB Visual includes alpha bits. However, michael@0: // bits not in the color masks are not necessarily alpha bits because michael@0: // sometimes (NVIDIA) 32 bit Visuals are added for fbconfigs with 32 michael@0: // bit BUFFER_SIZE but zero alpha bits and 24 color bits (NVIDIA michael@0: // again). michael@0: // michael@0: // This checks that the depth matches in one of the two ways. michael@0: // NVIDIA now forces format->depth == depth so only the first way michael@0: // is checked for NVIDIA michael@0: if (depth != format->depth && michael@0: (mIsNVIDIA || depth != format->depth - alphaSize) ) { michael@0: continue; michael@0: } michael@0: michael@0: // If all bits of the Pixmap are color bits and the Pixmap depth michael@0: // matches the depth of the fbconfig visual, then we can assume that michael@0: // the driver will do whatever is necessary to ensure that any michael@0: // GLXPixmap alpha bits are treated as set. We can skip the michael@0: // ALPHA_SIZE check in this situation. We need to skip this check for michael@0: // situations (ATI) where there are no fbconfigs without alpha bits. michael@0: // michael@0: // glXChooseFBConfig should prefer configs with smaller michael@0: // LOCAL_GLX_BUFFER_SIZE, so we should still get zero alpha bits if michael@0: // available, except perhaps with NVIDIA drivers where buffer size is michael@0: // not the specified sum of the component sizes. michael@0: if (haveNonColorBits) { michael@0: // There are bits in the Pixmap format that haven't been matched michael@0: // against the fbconfig visual. These bits could either represent michael@0: // alpha or be unused, so just check that the number of alpha bits michael@0: // matches. michael@0: int size = 0; michael@0: sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], michael@0: LOCAL_GLX_ALPHA_SIZE, &size); michael@0: if (size != alphaSize) { michael@0: continue; michael@0: } michael@0: } michael@0: michael@0: matchIndex = i; michael@0: break; michael@0: } michael@0: if (matchIndex == -1) { michael@0: // GLX can't handle A8 surfaces, so this is not really unexpected. The michael@0: // caller should deal with this situation. michael@0: NS_WARN_IF_FALSE(format->depth == 8, michael@0: "[GLX] Couldn't find a FBConfig matching Pixmap format"); michael@0: return None; michael@0: } michael@0: michael@0: int pixmapAttribs[] = { LOCAL_GLX_TEXTURE_TARGET_EXT, LOCAL_GLX_TEXTURE_2D_EXT, michael@0: LOCAL_GLX_TEXTURE_FORMAT_EXT, michael@0: (alphaSize ? LOCAL_GLX_TEXTURE_FORMAT_RGBA_EXT michael@0: : LOCAL_GLX_TEXTURE_FORMAT_RGB_EXT), michael@0: None}; michael@0: michael@0: GLXPixmap glxpixmap = xCreatePixmap(display, michael@0: cfgs[matchIndex], michael@0: xs->XDrawable(), michael@0: pixmapAttribs); michael@0: michael@0: return glxpixmap; michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::DestroyPixmap(Display* aDisplay, GLXPixmap aPixmap) michael@0: { michael@0: if (!mUseTextureFromPixmap) { michael@0: return; michael@0: } michael@0: michael@0: xDestroyPixmap(aDisplay, aPixmap); michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::BindTexImage(Display* aDisplay, GLXPixmap aPixmap) michael@0: { michael@0: if (!mUseTextureFromPixmap) { michael@0: return; michael@0: } michael@0: michael@0: // Make sure all X drawing to the surface has finished before binding to a texture. michael@0: if (mClientIsMesa) { michael@0: // Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a michael@0: // noop when direct rendering unless the current drawable is a michael@0: // single-buffer window. michael@0: FinishX(aDisplay); michael@0: } else { michael@0: xWaitX(); michael@0: } michael@0: xBindTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT, nullptr); michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::ReleaseTexImage(Display* aDisplay, GLXPixmap aPixmap) michael@0: { michael@0: if (!mUseTextureFromPixmap) { michael@0: return; michael@0: } michael@0: michael@0: xReleaseTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT); michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::UpdateTexImage(Display* aDisplay, GLXPixmap aPixmap) michael@0: { michael@0: // NVIDIA drivers don't require a rebind of the pixmap in order michael@0: // to display an updated image, and it's faster not to do it. michael@0: if (mIsNVIDIA) { michael@0: xWaitX(); michael@0: return; michael@0: } michael@0: michael@0: ReleaseTexImage(aDisplay, aPixmap); michael@0: BindTexImage(aDisplay, aPixmap); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: michael@0: static int (*sOldErrorHandler)(Display *, XErrorEvent *); michael@0: ScopedXErrorHandler::ErrorEvent sErrorEvent; michael@0: static int GLXErrorHandler(Display *display, XErrorEvent *ev) michael@0: { michael@0: if (!sErrorEvent.mError.error_code) { michael@0: sErrorEvent.mError = *ev; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::BeforeGLXCall() michael@0: { michael@0: if (mDebug) { michael@0: sOldErrorHandler = XSetErrorHandler(GLXErrorHandler); michael@0: } michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::AfterGLXCall() michael@0: { michael@0: if (mDebug) { michael@0: FinishX(DefaultXDisplay()); michael@0: if (sErrorEvent.mError.error_code) { michael@0: char buffer[2048]; michael@0: XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer)); michael@0: printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %i", michael@0: buffer, michael@0: sErrorEvent.mError.error_code, michael@0: sErrorEvent.mError.request_code, michael@0: sErrorEvent.mError.minor_code, michael@0: sErrorEvent.mError.serial); michael@0: NS_ABORT(); michael@0: } michael@0: XSetErrorHandler(sOldErrorHandler); michael@0: } michael@0: } michael@0: michael@0: #define BEFORE_GLX_CALL do { \ michael@0: sGLXLibrary.BeforeGLXCall(); \ michael@0: } while (0) michael@0: michael@0: #define AFTER_GLX_CALL do { \ michael@0: sGLXLibrary.AfterGLXCall(); \ michael@0: } while (0) michael@0: michael@0: #else michael@0: michael@0: #define BEFORE_GLX_CALL do { } while(0) michael@0: #define AFTER_GLX_CALL do { } while(0) michael@0: michael@0: #endif michael@0: michael@0: void michael@0: GLXLibrary::xDestroyContext(Display* display, GLXContext context) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: xDestroyContextInternal(display, context); michael@0: AFTER_GLX_CALL; michael@0: } michael@0: michael@0: Bool michael@0: GLXLibrary::xMakeCurrent(Display* display, michael@0: GLXDrawable drawable, michael@0: GLXContext context) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: Bool result = xMakeCurrentInternal(display, drawable, context); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: GLXContext michael@0: GLXLibrary::xGetCurrentContext() michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: GLXContext result = xGetCurrentContextInternal(); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: /* static */ void* michael@0: GLXLibrary::xGetProcAddress(const char *procName) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: void* result = sGLXLibrary.xGetProcAddressInternal(procName); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: GLXFBConfig* michael@0: GLXLibrary::xChooseFBConfig(Display* display, michael@0: int screen, michael@0: const int *attrib_list, michael@0: int *nelements) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: GLXFBConfig* result = xChooseFBConfigInternal(display, screen, attrib_list, nelements); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: GLXFBConfig* michael@0: GLXLibrary::xGetFBConfigs(Display* display, michael@0: int screen, michael@0: int *nelements) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: GLXFBConfig* result = xGetFBConfigsInternal(display, screen, nelements); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: GLXContext michael@0: GLXLibrary::xCreateNewContext(Display* display, michael@0: GLXFBConfig config, michael@0: int render_type, michael@0: GLXContext share_list, michael@0: Bool direct) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: GLXContext result = xCreateNewContextInternal(display, config, michael@0: render_type, michael@0: share_list, direct); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: int michael@0: GLXLibrary::xGetFBConfigAttrib(Display *display, michael@0: GLXFBConfig config, michael@0: int attribute, michael@0: int *value) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: int result = xGetFBConfigAttribInternal(display, config, michael@0: attribute, value); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::xSwapBuffers(Display *display, GLXDrawable drawable) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: xSwapBuffersInternal(display, drawable); michael@0: AFTER_GLX_CALL; michael@0: } michael@0: michael@0: const char * michael@0: GLXLibrary::xQueryExtensionsString(Display *display, michael@0: int screen) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: const char *result = xQueryExtensionsStringInternal(display, screen); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: const char * michael@0: GLXLibrary::xGetClientString(Display *display, michael@0: int screen) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: const char *result = xGetClientStringInternal(display, screen); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: const char * michael@0: GLXLibrary::xQueryServerString(Display *display, michael@0: int screen, int name) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: const char *result = xQueryServerStringInternal(display, screen, name); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: GLXPixmap michael@0: GLXLibrary::xCreatePixmap(Display *display, michael@0: GLXFBConfig config, michael@0: Pixmap pixmap, michael@0: const int *attrib_list) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: GLXPixmap result = xCreatePixmapInternal(display, config, michael@0: pixmap, attrib_list); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: GLXPixmap michael@0: GLXLibrary::xCreateGLXPixmapWithConfig(Display *display, michael@0: GLXFBConfig config, michael@0: Pixmap pixmap) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: GLXPixmap result = xCreateGLXPixmapWithConfigInternal(display, config, pixmap); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::xDestroyPixmap(Display *display, GLXPixmap pixmap) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: xDestroyPixmapInternal(display, pixmap); michael@0: AFTER_GLX_CALL; michael@0: } michael@0: michael@0: Bool michael@0: GLXLibrary::xQueryVersion(Display *display, michael@0: int *major, michael@0: int *minor) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: Bool result = xQueryVersionInternal(display, major, minor); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::xBindTexImage(Display *display, michael@0: GLXDrawable drawable, michael@0: int buffer, michael@0: const int *attrib_list) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: xBindTexImageInternal(display, drawable, buffer, attrib_list); michael@0: AFTER_GLX_CALL; michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::xReleaseTexImage(Display *display, michael@0: GLXDrawable drawable, michael@0: int buffer) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: xReleaseTexImageInternal(display, drawable, buffer); michael@0: AFTER_GLX_CALL; michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::xWaitGL() michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: xWaitGLInternal(); michael@0: AFTER_GLX_CALL; michael@0: } michael@0: michael@0: void michael@0: GLXLibrary::xWaitX() michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: xWaitXInternal(); michael@0: AFTER_GLX_CALL; michael@0: } michael@0: michael@0: GLXContext michael@0: GLXLibrary::xCreateContextAttribs(Display* display, michael@0: GLXFBConfig config, michael@0: GLXContext share_list, michael@0: Bool direct, michael@0: const int* attrib_list) michael@0: { michael@0: BEFORE_GLX_CALL; michael@0: GLXContext result = xCreateContextAttribsInternal(display, michael@0: config, michael@0: share_list, michael@0: direct, michael@0: attrib_list); michael@0: AFTER_GLX_CALL; michael@0: return result; michael@0: } michael@0: michael@0: already_AddRefed michael@0: GLContextGLX::CreateGLContext( michael@0: const SurfaceCaps& caps, michael@0: GLContextGLX* shareContext, michael@0: bool isOffscreen, michael@0: Display* display, michael@0: GLXDrawable drawable, michael@0: GLXFBConfig cfg, michael@0: bool deleteDrawable, michael@0: gfxXlibSurface* pixmap) michael@0: { michael@0: GLXLibrary& glx = sGLXLibrary; michael@0: michael@0: int db = 0; michael@0: int err = glx.xGetFBConfigAttrib(display, cfg, michael@0: LOCAL_GLX_DOUBLEBUFFER, &db); michael@0: if (LOCAL_GLX_BAD_ATTRIBUTE != err) { michael@0: #ifdef DEBUG michael@0: if (DebugMode()) { michael@0: printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not "); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: GLXContext context; michael@0: nsRefPtr glContext; michael@0: bool error; michael@0: michael@0: ScopedXErrorHandler xErrorHandler; michael@0: michael@0: TRY_AGAIN_NO_SHARING: michael@0: michael@0: error = false; michael@0: michael@0: GLXContext glxContext = shareContext ? shareContext->mContext : nullptr; michael@0: if (glx.HasRobustness()) { michael@0: int attrib_list[] = { michael@0: LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB, michael@0: LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB, michael@0: 0, michael@0: }; michael@0: michael@0: context = glx.xCreateContextAttribs( michael@0: display, michael@0: cfg, michael@0: glxContext, michael@0: True, michael@0: attrib_list); michael@0: } else { michael@0: context = glx.xCreateNewContext( michael@0: display, michael@0: cfg, michael@0: LOCAL_GLX_RGBA_TYPE, michael@0: glxContext, michael@0: True); michael@0: } michael@0: michael@0: if (context) { michael@0: glContext = new GLContextGLX(caps, michael@0: shareContext, michael@0: isOffscreen, michael@0: display, michael@0: drawable, michael@0: context, michael@0: deleteDrawable, michael@0: db, michael@0: pixmap); michael@0: if (!glContext->Init()) michael@0: error = true; michael@0: } else { michael@0: error = true; michael@0: } michael@0: michael@0: error |= xErrorHandler.SyncAndGetError(display); michael@0: michael@0: if (error) { michael@0: if (shareContext) { michael@0: shareContext = nullptr; michael@0: goto TRY_AGAIN_NO_SHARING; michael@0: } michael@0: michael@0: NS_WARNING("Failed to create GLXContext!"); michael@0: glContext = nullptr; // note: this must be done while the graceful X error handler is set, michael@0: // because glxMakeCurrent can give a GLXBadDrawable error michael@0: } michael@0: michael@0: return glContext.forget(); michael@0: } michael@0: michael@0: GLContextGLX::~GLContextGLX() michael@0: { michael@0: MarkDestroyed(); michael@0: michael@0: // Wrapped context should not destroy glxContext/Surface michael@0: if (!mOwnsContext) { michael@0: return; michael@0: } michael@0: michael@0: // see bug 659842 comment 76 michael@0: #ifdef DEBUG michael@0: bool success = michael@0: #endif michael@0: mGLX->xMakeCurrent(mDisplay, None, nullptr); michael@0: NS_ABORT_IF_FALSE(success, michael@0: "glXMakeCurrent failed to release GL context before we call glXDestroyContext!"); michael@0: michael@0: mGLX->xDestroyContext(mDisplay, mContext); michael@0: michael@0: if (mDeleteDrawable) { michael@0: mGLX->xDestroyPixmap(mDisplay, mDrawable); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: GLContextGLX::Init() michael@0: { michael@0: SetupLookupFunction(); michael@0: if (!InitWithPrefix("gl", true)) { michael@0: return false; michael@0: } michael@0: michael@0: if (!IsExtensionSupported(EXT_framebuffer_object)) michael@0: return false; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: GLContextGLX::MakeCurrentImpl(bool aForce) michael@0: { michael@0: bool succeeded = true; michael@0: michael@0: // With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change. michael@0: // (This is not the case with other drivers such as NVIDIA). michael@0: // So avoid calling it more than necessary. Since GLX documentation says that: michael@0: // "glXGetCurrentContext returns client-side information. michael@0: // It does not make a round trip to the server." michael@0: // I assume that it's not worth using our own TLS slot here. michael@0: if (aForce || mGLX->xGetCurrentContext() != mContext) { michael@0: succeeded = mGLX->xMakeCurrent(mDisplay, mDrawable, mContext); michael@0: NS_ASSERTION(succeeded, "Failed to make GL context current!"); michael@0: } michael@0: michael@0: return succeeded; michael@0: } michael@0: michael@0: bool michael@0: GLContextGLX::IsCurrent() { michael@0: return mGLX->xGetCurrentContext() == mContext; michael@0: } michael@0: michael@0: bool michael@0: GLContextGLX::SetupLookupFunction() michael@0: { michael@0: mLookupFunc = (PlatformLookupFunction)&GLXLibrary::xGetProcAddress; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: GLContextGLX::IsDoubleBuffered() const michael@0: { michael@0: return mDoubleBuffered; michael@0: } michael@0: michael@0: bool michael@0: GLContextGLX::SupportsRobustness() const michael@0: { michael@0: return mGLX->HasRobustness(); michael@0: } michael@0: michael@0: bool michael@0: GLContextGLX::SwapBuffers() michael@0: { michael@0: if (!mDoubleBuffered) michael@0: return false; michael@0: mGLX->xSwapBuffers(mDisplay, mDrawable); michael@0: mGLX->xWaitGL(); michael@0: return true; michael@0: } michael@0: michael@0: GLContextGLX::GLContextGLX( michael@0: const SurfaceCaps& caps, michael@0: GLContext* shareContext, michael@0: bool isOffscreen, michael@0: Display *aDisplay, michael@0: GLXDrawable aDrawable, michael@0: GLXContext aContext, michael@0: bool aDeleteDrawable, michael@0: bool aDoubleBuffered, michael@0: gfxXlibSurface *aPixmap) michael@0: : GLContext(caps, shareContext, isOffscreen),//aDeleteDrawable ? true : false, aShareContext, ), michael@0: mContext(aContext), michael@0: mDisplay(aDisplay), michael@0: mDrawable(aDrawable), michael@0: mDeleteDrawable(aDeleteDrawable), michael@0: mDoubleBuffered(aDoubleBuffered), michael@0: mGLX(&sGLXLibrary), michael@0: mPixmap(aPixmap), michael@0: mOwnsContext(true) michael@0: { michael@0: MOZ_ASSERT(mGLX); michael@0: // See 899855 michael@0: SetProfileVersion(ContextProfile::OpenGLCompatibility, 200); michael@0: } michael@0: michael@0: michael@0: static GLContextGLX * michael@0: GetGlobalContextGLX() michael@0: { michael@0: return static_cast(GLContextProviderGLX::GetGlobalContext()); michael@0: } michael@0: michael@0: static bool michael@0: AreCompatibleVisuals(Visual *one, Visual *two) michael@0: { michael@0: if (one->c_class != two->c_class) { michael@0: return false; michael@0: } michael@0: michael@0: if (one->red_mask != two->red_mask || michael@0: one->green_mask != two->green_mask || michael@0: one->blue_mask != two->blue_mask) { michael@0: return false; michael@0: } michael@0: michael@0: if (one->bits_per_rgb != two->bits_per_rgb) { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static StaticRefPtr gGlobalContext; michael@0: michael@0: already_AddRefed michael@0: GLContextProviderGLX::CreateWrappingExisting(void* aContext, void* aSurface) michael@0: { michael@0: if (!sGLXLibrary.EnsureInitialized()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (aContext && aSurface) { michael@0: SurfaceCaps caps = SurfaceCaps::Any(); michael@0: nsRefPtr glContext = michael@0: new GLContextGLX(caps, michael@0: nullptr, // SharedContext michael@0: false, // Offscreen michael@0: (Display*)DefaultXDisplay(), // Display michael@0: (GLXDrawable)aSurface, (GLXContext)aContext, michael@0: false, // aDeleteDrawable, michael@0: true, michael@0: (gfxXlibSurface*)nullptr); michael@0: michael@0: glContext->mOwnsContext = false; michael@0: gGlobalContext = glContext; michael@0: michael@0: return glContext.forget(); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget) michael@0: { michael@0: if (!sGLXLibrary.EnsureInitialized()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // Currently, we take whatever Visual the window already has, and michael@0: // try to create an fbconfig for that visual. This isn't michael@0: // necessarily what we want in the long run; an fbconfig may not michael@0: // be available for the existing visual, or if it is, the GL michael@0: // performance might be suboptimal. But using the existing visual michael@0: // is a relatively safe intermediate step. michael@0: michael@0: Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY); michael@0: if (!display) { michael@0: NS_ERROR("X Display required for GLX Context provider"); michael@0: return nullptr; michael@0: } michael@0: michael@0: int xscreen = DefaultScreen(display); michael@0: Window window = GET_NATIVE_WINDOW(aWidget); michael@0: michael@0: int numConfigs; michael@0: ScopedXFree cfgs; michael@0: if (sGLXLibrary.IsATI() || michael@0: !sGLXLibrary.GLXVersionCheck(1, 3)) { michael@0: const int attribs[] = { michael@0: LOCAL_GLX_DOUBLEBUFFER, False, michael@0: 0 michael@0: }; michael@0: cfgs = sGLXLibrary.xChooseFBConfig(display, michael@0: xscreen, michael@0: attribs, michael@0: &numConfigs); michael@0: } else { michael@0: cfgs = sGLXLibrary.xGetFBConfigs(display, michael@0: xscreen, michael@0: &numConfigs); michael@0: } michael@0: michael@0: if (!cfgs) { michael@0: NS_WARNING("[GLX] glXGetFBConfigs() failed"); michael@0: return nullptr; michael@0: } michael@0: NS_ASSERTION(numConfigs > 0, "No FBConfigs found!"); michael@0: michael@0: // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so michael@0: // we could probably do this first and replace the glXGetFBConfigs michael@0: // with glXChooseConfigs. Docs are sparklingly clear as always. michael@0: XWindowAttributes widgetAttrs; michael@0: if (!XGetWindowAttributes(display, window, &widgetAttrs)) { michael@0: NS_WARNING("[GLX] XGetWindowAttributes() failed"); michael@0: return nullptr; michael@0: } michael@0: const VisualID widgetVisualID = XVisualIDFromVisual(widgetAttrs.visual); michael@0: #ifdef DEBUG michael@0: printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID); michael@0: #endif michael@0: michael@0: int matchIndex = -1; michael@0: michael@0: for (int i = 0; i < numConfigs; i++) { michael@0: int visid = None; michael@0: sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid); michael@0: if (!visid) { michael@0: continue; michael@0: } michael@0: if (sGLXLibrary.IsATI()) { michael@0: int depth; michael@0: Visual *visual; michael@0: FindVisualAndDepth(display, visid, &visual, &depth); michael@0: if (depth == widgetAttrs.depth && michael@0: AreCompatibleVisuals(widgetAttrs.visual, visual)) { michael@0: matchIndex = i; michael@0: break; michael@0: } michael@0: } else { michael@0: if (widgetVisualID == static_cast(visid)) { michael@0: matchIndex = i; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (matchIndex == -1) { michael@0: NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual"); michael@0: return nullptr; michael@0: } michael@0: michael@0: GLContextGLX *shareContext = GetGlobalContextGLX(); michael@0: michael@0: SurfaceCaps caps = SurfaceCaps::Any(); michael@0: nsRefPtr glContext = GLContextGLX::CreateGLContext(caps, michael@0: shareContext, michael@0: false, michael@0: display, michael@0: window, michael@0: cfgs[matchIndex], michael@0: false); michael@0: michael@0: return glContext.forget(); michael@0: } michael@0: michael@0: static already_AddRefed michael@0: CreateOffscreenPixmapContext(const gfxIntSize& size) michael@0: { michael@0: GLXLibrary& glx = sGLXLibrary; michael@0: if (!glx.EnsureInitialized()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: Display *display = DefaultXDisplay(); michael@0: int xscreen = DefaultScreen(display); michael@0: michael@0: int attribs[] = { michael@0: LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT, michael@0: LOCAL_GLX_X_RENDERABLE, True, michael@0: 0 michael@0: }; michael@0: int numConfigs = 0; michael@0: michael@0: ScopedXFree cfgs; michael@0: cfgs = glx.xChooseFBConfig(display, michael@0: xscreen, michael@0: attribs, michael@0: &numConfigs); michael@0: if (!cfgs) { michael@0: return nullptr; michael@0: } michael@0: michael@0: MOZ_ASSERT(numConfigs > 0, michael@0: "glXChooseFBConfig() failed to match our requested format and violated its spec!"); michael@0: michael@0: int visid = None; michael@0: int chosenIndex = 0; michael@0: michael@0: for (int i = 0; i < numConfigs; ++i) { michael@0: int dtype; michael@0: michael@0: if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_DRAWABLE_TYPE, &dtype) != Success michael@0: || !(dtype & LOCAL_GLX_PIXMAP_BIT)) michael@0: { michael@0: continue; michael@0: } michael@0: if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid) != Success michael@0: || visid == 0) michael@0: { michael@0: continue; michael@0: } michael@0: michael@0: chosenIndex = i; michael@0: break; michael@0: } michael@0: michael@0: if (!visid) { michael@0: NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!"); michael@0: return nullptr; michael@0: } michael@0: michael@0: Visual *visual; michael@0: int depth; michael@0: FindVisualAndDepth(display, visid, &visual, &depth); michael@0: ScopedXErrorHandler xErrorHandler; michael@0: GLXPixmap glxpixmap = 0; michael@0: bool error = false; michael@0: michael@0: gfxIntSize dummySize(16, 16); michael@0: nsRefPtr xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), michael@0: visual, michael@0: dummySize); michael@0: if (xsurface->CairoStatus() != 0) { michael@0: error = true; michael@0: goto DONE_CREATING_PIXMAP; michael@0: } michael@0: michael@0: // Handle slightly different signature between glXCreatePixmap and michael@0: // its pre-GLX-1.3 extension equivalent (though given the ABI, we michael@0: // might not need to). michael@0: if (glx.GLXVersionCheck(1, 3)) { michael@0: glxpixmap = glx.xCreatePixmap(display, michael@0: cfgs[chosenIndex], michael@0: xsurface->XDrawable(), michael@0: nullptr); michael@0: } else { michael@0: glxpixmap = glx.xCreateGLXPixmapWithConfig(display, michael@0: cfgs[chosenIndex], michael@0: xsurface-> michael@0: XDrawable()); michael@0: } michael@0: if (glxpixmap == 0) { michael@0: error = true; michael@0: } michael@0: michael@0: DONE_CREATING_PIXMAP: michael@0: michael@0: nsRefPtr glContext; michael@0: bool serverError = xErrorHandler.SyncAndGetError(display); michael@0: michael@0: if (!error && // earlier recorded error michael@0: !serverError) michael@0: { michael@0: // We might have an alpha channel, but it doesn't matter. michael@0: SurfaceCaps dummyCaps = SurfaceCaps::Any(); michael@0: GLContextGLX* shareContext = GetGlobalContextGLX(); michael@0: michael@0: glContext = GLContextGLX::CreateGLContext(dummyCaps, michael@0: shareContext, michael@0: true, michael@0: display, michael@0: glxpixmap, michael@0: cfgs[chosenIndex], michael@0: true, michael@0: xsurface); michael@0: } michael@0: michael@0: return glContext.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size, michael@0: const SurfaceCaps& caps) michael@0: { michael@0: gfxIntSize dummySize = gfxIntSize(16, 16); michael@0: nsRefPtr glContext = michael@0: CreateOffscreenPixmapContext(dummySize); michael@0: michael@0: if (!glContext) michael@0: return nullptr; michael@0: michael@0: if (!glContext->InitOffscreen(ToIntSize(size), caps)) michael@0: return nullptr; michael@0: michael@0: return glContext.forget(); michael@0: } michael@0: michael@0: GLContext* michael@0: GLContextProviderGLX::GetGlobalContext() michael@0: { michael@0: static bool checkedContextSharing = false; michael@0: static bool useContextSharing = false; michael@0: michael@0: if (!checkedContextSharing) { michael@0: useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0; michael@0: checkedContextSharing = true; michael@0: } michael@0: michael@0: // TODO: get GLX context sharing to work well with multiple threads michael@0: if (!useContextSharing) { michael@0: return nullptr; michael@0: } michael@0: michael@0: static bool triedToCreateContext = false; michael@0: if (!triedToCreateContext && !gGlobalContext) { michael@0: triedToCreateContext = true; michael@0: michael@0: gfxIntSize dummySize = gfxIntSize(16, 16); michael@0: // StaticPtr doesn't support assignments from already_AddRefed, michael@0: // so use a temporary nsRefPtr to make the reference counting michael@0: // fall out correctly. michael@0: nsRefPtr holder = CreateOffscreenPixmapContext(dummySize); michael@0: gGlobalContext = holder; michael@0: } michael@0: michael@0: return gGlobalContext; michael@0: } michael@0: michael@0: void michael@0: GLContextProviderGLX::Shutdown() michael@0: { michael@0: gGlobalContext = nullptr; michael@0: } michael@0: michael@0: } /* namespace gl */ michael@0: } /* namespace mozilla */ michael@0: