Bumping manifests a=b2g-bump
[gecko.git] / gfx / gl / GLContextProviderGLX.cpp
blob4587b7d2e1ddcfcc5a2404dc2772ac895bc96ec4
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 namespace mozilla {
41 namespace gl {
43 using namespace mozilla::gfx;
45 GLXLibrary sGLXLibrary;
47 // Check that we have at least version aMajor.aMinor .
48 bool
49 GLXLibrary::GLXVersionCheck(int aMajor, int aMinor)
51 return aMajor < mGLXMajorVersion ||
52 (aMajor == mGLXMajorVersion && aMinor <= mGLXMinorVersion);
55 static inline bool
56 HasExtension(const char* aExtensions, const char* aRequiredExtension)
58 return GLContext::ListHasExtension(
59 reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
62 bool
63 GLXLibrary::EnsureInitialized()
65 if (mInitialized) {
66 return true;
69 // Don't repeatedly try to initialize.
70 if (mTriedInitializing) {
71 return false;
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;
97 reporter.SetSuccessful();
100 if (PR_GetEnv("MOZ_GLX_DEBUG")) {
101 mDebug = true;
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 } }
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 } }
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 } }
146 GLLibraryLoader::SymLoadStruct symbols14[] = {
147 /* functions introduced in GLX 1.4 */
148 { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddress", nullptr } },
149 { nullptr, { nullptr } }
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 } }
159 GLLibraryLoader::SymLoadStruct symbols_texturefrompixmap[] = {
160 { (PRFuncPtr*) &xBindTexImageInternal, { "glXBindTexImageEXT", nullptr } },
161 { (PRFuncPtr*) &xReleaseTexImageInternal, { "glXReleaseTexImageEXT", nullptr } },
162 { nullptr, { nullptr } }
165 GLLibraryLoader::SymLoadStruct symbols_robustness[] = {
166 { (PRFuncPtr*) &xCreateContextAttribsInternal, { "glXCreateContextAttribsARB", nullptr } },
167 { nullptr, { nullptr } }
170 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
171 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
172 return false;
175 Display *display = DefaultXDisplay();
176 int screen = DefaultScreen(display);
178 if (!xQueryVersion(display, &mGLXMajorVersion, &mGLXMinorVersion)) {
179 mGLXMajorVersion = 0;
180 mGLXMinorVersion = 0;
181 return false;
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;
199 sym13 = symbols13_ext;
200 } else {
201 sym13 = symbols13;
203 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym13)) {
204 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
205 return false;
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;
215 sym14 = symbols14_ext;
216 } else {
217 sym14 = symbols14;
219 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym14)) {
220 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
221 return false;
224 if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") &&
225 GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_texturefrompixmap,
226 (GLLibraryLoader::PlatformLookupFunction)&xGetProcAddress))
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");
238 if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") &&
239 GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) {
240 mHasRobustness = true;
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;
252 bool
253 GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface)
255 if (!EnsureInitialized()) {
256 return false;
259 if (aSurface->GetType() != gfxSurfaceType::Xlib || !mUseTextureFromPixmap) {
260 return false;
263 return true;
266 GLXPixmap
267 GLXLibrary::CreatePixmap(gfxASurface* aSurface)
269 if (!SupportsTextureFromPixmap(aSurface)) {
270 return None;
273 gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
274 const XRenderPictFormat *format = xs->XRenderFormat();
275 if (!format || format->type != PictTypeDirect) {
276 return None;
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;
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.
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.
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.
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).
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;
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.
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;
378 matchIndex = i;
379 break;
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;
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;
403 void
404 GLXLibrary::DestroyPixmap(Display* aDisplay, GLXPixmap aPixmap)
406 if (!mUseTextureFromPixmap) {
407 return;
410 xDestroyPixmap(aDisplay, aPixmap);
413 void
414 GLXLibrary::BindTexImage(Display* aDisplay, GLXPixmap aPixmap)
416 if (!mUseTextureFromPixmap) {
417 return;
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();
429 xBindTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT, nullptr);
432 void
433 GLXLibrary::ReleaseTexImage(Display* aDisplay, GLXPixmap aPixmap)
435 if (!mUseTextureFromPixmap) {
436 return;
439 xReleaseTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT);
442 void
443 GLXLibrary::UpdateTexImage(Display* aDisplay, GLXPixmap aPixmap)
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;
452 ReleaseTexImage(aDisplay, aPixmap);
453 BindTexImage(aDisplay, aPixmap);
456 #ifdef DEBUG
458 static int (*sOldErrorHandler)(Display *, XErrorEvent *);
459 ScopedXErrorHandler::ErrorEvent sErrorEvent;
460 static int GLXErrorHandler(Display *display, XErrorEvent *ev)
462 if (!sErrorEvent.mError.error_code) {
463 sErrorEvent.mError = *ev;
465 return 0;
468 void
469 GLXLibrary::BeforeGLXCall()
471 if (mDebug) {
472 sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
476 void
477 GLXLibrary::AfterGLXCall()
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: %lu",
485 buffer,
486 sErrorEvent.mError.error_code,
487 sErrorEvent.mError.request_code,
488 sErrorEvent.mError.minor_code,
489 sErrorEvent.mError.serial);
490 NS_ABORT();
492 XSetErrorHandler(sOldErrorHandler);
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)
514 BEFORE_GLX_CALL;
515 xDestroyContextInternal(display, context);
516 AFTER_GLX_CALL;
519 Bool
520 GLXLibrary::xMakeCurrent(Display* display,
521 GLXDrawable drawable,
522 GLXContext context)
524 BEFORE_GLX_CALL;
525 Bool result = xMakeCurrentInternal(display, drawable, context);
526 AFTER_GLX_CALL;
527 return result;
530 GLXContext
531 GLXLibrary::xGetCurrentContext()
533 BEFORE_GLX_CALL;
534 GLXContext result = xGetCurrentContextInternal();
535 AFTER_GLX_CALL;
536 return result;
539 /* static */ void*
540 GLXLibrary::xGetProcAddress(const char *procName)
542 BEFORE_GLX_CALL;
543 void* result = sGLXLibrary.xGetProcAddressInternal(procName);
544 AFTER_GLX_CALL;
545 return result;
548 GLXFBConfig*
549 GLXLibrary::xChooseFBConfig(Display* display,
550 int screen,
551 const int *attrib_list,
552 int *nelements)
554 BEFORE_GLX_CALL;
555 GLXFBConfig* result = xChooseFBConfigInternal(display, screen, attrib_list, nelements);
556 AFTER_GLX_CALL;
557 return result;
560 GLXFBConfig*
561 GLXLibrary::xGetFBConfigs(Display* display,
562 int screen,
563 int *nelements)
565 BEFORE_GLX_CALL;
566 GLXFBConfig* result = xGetFBConfigsInternal(display, screen, nelements);
567 AFTER_GLX_CALL;
568 return result;
571 GLXContext
572 GLXLibrary::xCreateNewContext(Display* display,
573 GLXFBConfig config,
574 int render_type,
575 GLXContext share_list,
576 Bool direct)
578 BEFORE_GLX_CALL;
579 GLXContext result = xCreateNewContextInternal(display, config,
580 render_type,
581 share_list, direct);
582 AFTER_GLX_CALL;
583 return result;
587 GLXLibrary::xGetFBConfigAttrib(Display *display,
588 GLXFBConfig config,
589 int attribute,
590 int *value)
592 BEFORE_GLX_CALL;
593 int result = xGetFBConfigAttribInternal(display, config,
594 attribute, value);
595 AFTER_GLX_CALL;
596 return result;
599 void
600 GLXLibrary::xSwapBuffers(Display *display, GLXDrawable drawable)
602 BEFORE_GLX_CALL;
603 xSwapBuffersInternal(display, drawable);
604 AFTER_GLX_CALL;
607 const char *
608 GLXLibrary::xQueryExtensionsString(Display *display,
609 int screen)
611 BEFORE_GLX_CALL;
612 const char *result = xQueryExtensionsStringInternal(display, screen);
613 AFTER_GLX_CALL;
614 return result;
617 const char *
618 GLXLibrary::xGetClientString(Display *display,
619 int screen)
621 BEFORE_GLX_CALL;
622 const char *result = xGetClientStringInternal(display, screen);
623 AFTER_GLX_CALL;
624 return result;
627 const char *
628 GLXLibrary::xQueryServerString(Display *display,
629 int screen, int name)
631 BEFORE_GLX_CALL;
632 const char *result = xQueryServerStringInternal(display, screen, name);
633 AFTER_GLX_CALL;
634 return result;
637 GLXPixmap
638 GLXLibrary::xCreatePixmap(Display *display,
639 GLXFBConfig config,
640 Pixmap pixmap,
641 const int *attrib_list)
643 BEFORE_GLX_CALL;
644 GLXPixmap result = xCreatePixmapInternal(display, config,
645 pixmap, attrib_list);
646 AFTER_GLX_CALL;
647 return result;
650 GLXPixmap
651 GLXLibrary::xCreateGLXPixmapWithConfig(Display *display,
652 GLXFBConfig config,
653 Pixmap pixmap)
655 BEFORE_GLX_CALL;
656 GLXPixmap result = xCreateGLXPixmapWithConfigInternal(display, config, pixmap);
657 AFTER_GLX_CALL;
658 return result;
661 void
662 GLXLibrary::xDestroyPixmap(Display *display, GLXPixmap pixmap)
664 BEFORE_GLX_CALL;
665 xDestroyPixmapInternal(display, pixmap);
666 AFTER_GLX_CALL;
669 Bool
670 GLXLibrary::xQueryVersion(Display *display,
671 int *major,
672 int *minor)
674 BEFORE_GLX_CALL;
675 Bool result = xQueryVersionInternal(display, major, minor);
676 AFTER_GLX_CALL;
677 return result;
680 void
681 GLXLibrary::xBindTexImage(Display *display,
682 GLXDrawable drawable,
683 int buffer,
684 const int *attrib_list)
686 BEFORE_GLX_CALL;
687 xBindTexImageInternal(display, drawable, buffer, attrib_list);
688 AFTER_GLX_CALL;
691 void
692 GLXLibrary::xReleaseTexImage(Display *display,
693 GLXDrawable drawable,
694 int buffer)
696 BEFORE_GLX_CALL;
697 xReleaseTexImageInternal(display, drawable, buffer);
698 AFTER_GLX_CALL;
701 void
702 GLXLibrary::xWaitGL()
704 BEFORE_GLX_CALL;
705 xWaitGLInternal();
706 AFTER_GLX_CALL;
709 void
710 GLXLibrary::xWaitX()
712 BEFORE_GLX_CALL;
713 xWaitXInternal();
714 AFTER_GLX_CALL;
717 GLXContext
718 GLXLibrary::xCreateContextAttribs(Display* display,
719 GLXFBConfig config,
720 GLXContext share_list,
721 Bool direct,
722 const int* attrib_list)
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;
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)
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 ");
755 #endif
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,
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);
791 if (context) {
792 glContext = new GLContextGLX(caps,
793 shareContext,
794 isOffscreen,
795 display,
796 drawable,
797 context,
798 deleteDrawable,
800 pixmap);
801 if (!glContext->Init())
802 error = true;
803 } else {
804 error = true;
807 error |= xErrorHandler.SyncAndGetError(display);
809 if (error) {
810 if (shareContext) {
811 shareContext = nullptr;
812 goto TRY_AGAIN_NO_SHARING;
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
820 return glContext.forget();
823 GLContextGLX::~GLContextGLX()
825 MarkDestroyed();
827 // Wrapped context should not destroy glxContext/Surface
828 if (!mOwnsContext) {
829 return;
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);
847 bool
848 GLContextGLX::Init()
850 SetupLookupFunction();
851 if (!InitWithPrefix("gl", true)) {
852 return false;
855 if (!IsExtensionSupported(EXT_framebuffer_object))
856 return false;
858 return true;
861 bool
862 GLContextGLX::MakeCurrentImpl(bool aForce)
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!");
877 return succeeded;
880 bool
881 GLContextGLX::IsCurrent() {
882 return mGLX->xGetCurrentContext() == mContext;
885 bool
886 GLContextGLX::SetupLookupFunction()
888 mLookupFunc = (PlatformLookupFunction)&GLXLibrary::xGetProcAddress;
889 return true;
892 bool
893 GLContextGLX::IsDoubleBuffered() const
895 return mDoubleBuffered;
898 bool
899 GLContextGLX::SupportsRobustness() const
901 return mGLX->HasRobustness();
904 bool
905 GLContextGLX::SwapBuffers()
907 if (!mDoubleBuffered)
908 return false;
909 mGLX->xSwapBuffers(mDisplay, mDrawable);
910 mGLX->xWaitGL();
911 return true;
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)
934 MOZ_ASSERT(mGLX);
935 // See 899855
936 SetProfileVersion(ContextProfile::OpenGLCompatibility, 200);
940 static GLContextGLX *
941 GetGlobalContextGLX()
943 return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext());
946 static bool
947 AreCompatibleVisuals(Visual *one, Visual *two)
949 if (one->c_class != two->c_class) {
950 return false;
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;
959 if (one->bits_per_rgb != two->bits_per_rgb) {
960 return false;
963 return true;
966 static StaticRefPtr<GLContext> gGlobalContext;
968 already_AddRefed<GLContext>
969 GLContextProviderGLX::CreateWrappingExisting(void* aContext, void* aSurface)
971 if (!sGLXLibrary.EnsureInitialized()) {
972 return nullptr;
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();
993 return nullptr;
996 already_AddRefed<GLContext>
997 GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
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,
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,
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::CreateHeadless()
1218 gfxIntSize dummySize = gfxIntSize(16, 16);
1219 nsRefPtr<GLContext> glContext = CreateOffscreenPixmapContext(dummySize);
1220 if (!glContext)
1221 return nullptr;
1223 return glContext.forget();
1226 already_AddRefed<GLContext>
1227 GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
1228 const SurfaceCaps& caps)
1230 nsRefPtr<GLContext> glContext = CreateHeadless();
1231 if (!glContext)
1232 return nullptr;
1234 if (!glContext->InitOffscreen(ToIntSize(size), caps))
1235 return nullptr;
1237 return glContext.forget();
1240 GLContext*
1241 GLContextProviderGLX::GetGlobalContext()
1243 static bool checkedContextSharing = false;
1244 static bool useContextSharing = false;
1246 if (!checkedContextSharing) {
1247 useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
1248 checkedContextSharing = true;
1251 // TODO: get GLX context sharing to work well with multiple threads
1252 if (!useContextSharing) {
1253 return nullptr;
1256 static bool triedToCreateContext = false;
1257 if (!triedToCreateContext && !gGlobalContext) {
1258 triedToCreateContext = true;
1260 gfxIntSize dummySize = gfxIntSize(16, 16);
1261 // StaticPtr doesn't support assignments from already_AddRefed,
1262 // so use a temporary nsRefPtr to make the reference counting
1263 // fall out correctly.
1264 nsRefPtr<GLContext> holder = CreateOffscreenPixmapContext(dummySize);
1265 gGlobalContext = holder;
1268 return gGlobalContext;
1271 void
1272 GLContextProviderGLX::Shutdown()
1274 gGlobalContext = nullptr;
1277 } /* namespace gl */
1278 } /* namespace mozilla */