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/. */
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))
15 #include <X11/Xutil.h>
17 #include "mozilla/MathAlgorithms.h"
18 #include "mozilla/StaticPtr.h"
19 #include "mozilla/X11Util.h"
22 #include "GLContextProvider.h"
23 #include "GLLibraryLoader.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"
32 #include "gfx2DGlue.h"
34 #include "gfxCrashReporterUtils.h"
37 #include "gfxPlatformGtk.h"
43 using namespace mozilla::gfx
;
45 GLXLibrary sGLXLibrary
;
47 // Check that we have at least version aMajor.aMinor .
49 GLXLibrary::GLXVersionCheck(int aMajor
, int aMinor
)
51 return aMajor
< mGLXMajorVersion
||
52 (aMajor
== mGLXMajorVersion
&& aMinor
<= mGLXMinorVersion
);
56 HasExtension(const char* aExtensions
, const char* aRequiredExtension
)
58 return GLContext::ListHasExtension(
59 reinterpret_cast<const GLubyte
*>(aExtensions
), aRequiredExtension
);
63 GLXLibrary::EnsureInitialized()
69 // Don't repeatedly try to initialize.
70 if (mTriedInitializing
) {
73 mTriedInitializing
= true;
75 // Force enabling s3 texture compression. (Bug 774134)
76 PR_SetEnv("force_s3tc_enable=true");
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
86 libGLfilename
= "libGL.so";
88 libGLfilename
= "libGL.so.1";
91 ScopedGfxFeatureReporter
reporter(libGLfilename
, forceFeatureReport
);
92 mOGLLibrary
= PR_LoadLibrary(libGLfilename
);
94 NS_WARNING("Couldn't load OpenGL shared library.");
97 reporter
.SetSuccessful();
100 if (PR_GetEnv("MOZ_GLX_DEBUG")) {
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");
175 Display
*display
= DefaultXDisplay();
176 int screen
= DefaultScreen(display
);
178 if (!xQueryVersion(display
, &mGLXMajorVersion
, &mGLXMinorVersion
)) {
179 mGLXMajorVersion
= 0;
180 mGLXMinorVersion
= 0;
184 if (!GLXVersionCheck(1, 1))
185 // Not possible to query for extensions.
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")) {
199 sym13
= symbols13_ext
;
203 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary
, sym13
)) {
204 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
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")) {
215 sym14
= symbols14_ext
;
219 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary
, sym14
)) {
220 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
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();
231 mUseTextureFromPixmap
= true;
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");
253 GLXLibrary::SupportsTextureFromPixmap(gfxASurface
* aSurface
)
255 if (!EnsureInitialized()) {
259 if (aSurface
->GetType() != gfxSurfaceType::Xlib
|| !mUseTextureFromPixmap
) {
267 GLXLibrary::CreatePixmap(gfxASurface
* aSurface
)
269 if (!SupportsTextureFromPixmap(aSurface
)) {
273 gfxXlibSurface
*xs
= static_cast<gfxXlibSurface
*>(aSurface
);
274 const XRenderPictFormat
*format
= xs
->XRenderFormat();
275 if (!format
|| format
->type
!= PictTypeDirect
) {
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
,
292 Display
*display
= xs
->XDisplay();
293 int xscreen
= DefaultScreen(display
);
295 ScopedXFree
<GLXFBConfig
> cfgs(xChooseFBConfig(display
,
300 // Find an fbconfig that matches the pixel format used on the Pixmap.
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
++) {
314 sGLXLibrary
.xGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_VISUAL_ID
, &id
);
317 FindVisualAndDepth(display
, id
, &visual
, &depth
);
319 visual
->c_class
!= TrueColor
||
320 visual
->red_mask
!= redMask
||
321 visual
->green_mask
!= greenMask
||
322 visual
->blue_mask
!= blueMask
) {
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
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
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
) ) {
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
371 sGLXLibrary
.xGetFBConfigAttrib(display
, cfgs
[i
],
372 LOCAL_GLX_ALPHA_SIZE
, &size
);
373 if (size
!= alphaSize
) {
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");
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
),
395 GLXPixmap glxpixmap
= xCreatePixmap(display
,
404 GLXLibrary::DestroyPixmap(Display
* aDisplay
, GLXPixmap aPixmap
)
406 if (!mUseTextureFromPixmap
) {
410 xDestroyPixmap(aDisplay
, aPixmap
);
414 GLXLibrary::BindTexImage(Display
* aDisplay
, GLXPixmap aPixmap
)
416 if (!mUseTextureFromPixmap
) {
420 // Make sure all X drawing to the surface has finished before binding to a texture.
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.
429 xBindTexImage(aDisplay
, aPixmap
, LOCAL_GLX_FRONT_LEFT_EXT
, nullptr);
433 GLXLibrary::ReleaseTexImage(Display
* aDisplay
, GLXPixmap aPixmap
)
435 if (!mUseTextureFromPixmap
) {
439 xReleaseTexImage(aDisplay
, aPixmap
, LOCAL_GLX_FRONT_LEFT_EXT
);
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.
452 ReleaseTexImage(aDisplay
, aPixmap
);
453 BindTexImage(aDisplay
, aPixmap
);
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
;
469 GLXLibrary::BeforeGLXCall()
472 sOldErrorHandler
= XSetErrorHandler(GLXErrorHandler
);
477 GLXLibrary::AfterGLXCall()
480 FinishX(DefaultXDisplay());
481 if (sErrorEvent
.mError
.error_code
) {
483 XGetErrorText(DefaultXDisplay(), sErrorEvent
.mError
.error_code
, buffer
, sizeof(buffer
));
484 printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %lu",
486 sErrorEvent
.mError
.error_code
,
487 sErrorEvent
.mError
.request_code
,
488 sErrorEvent
.mError
.minor_code
,
489 sErrorEvent
.mError
.serial
);
492 XSetErrorHandler(sOldErrorHandler
);
496 #define BEFORE_GLX_CALL do { \
497 sGLXLibrary.BeforeGLXCall(); \
500 #define AFTER_GLX_CALL do { \
501 sGLXLibrary.AfterGLXCall(); \
506 #define BEFORE_GLX_CALL do { } while(0)
507 #define AFTER_GLX_CALL do { } while(0)
512 GLXLibrary::xDestroyContext(Display
* display
, GLXContext context
)
515 xDestroyContextInternal(display
, context
);
520 GLXLibrary::xMakeCurrent(Display
* display
,
521 GLXDrawable drawable
,
525 Bool result
= xMakeCurrentInternal(display
, drawable
, context
);
531 GLXLibrary::xGetCurrentContext()
534 GLXContext result
= xGetCurrentContextInternal();
540 GLXLibrary::xGetProcAddress(const char *procName
)
543 void* result
= sGLXLibrary
.xGetProcAddressInternal(procName
);
549 GLXLibrary::xChooseFBConfig(Display
* display
,
551 const int *attrib_list
,
555 GLXFBConfig
* result
= xChooseFBConfigInternal(display
, screen
, attrib_list
, nelements
);
561 GLXLibrary::xGetFBConfigs(Display
* display
,
566 GLXFBConfig
* result
= xGetFBConfigsInternal(display
, screen
, nelements
);
572 GLXLibrary::xCreateNewContext(Display
* display
,
575 GLXContext share_list
,
579 GLXContext result
= xCreateNewContextInternal(display
, config
,
587 GLXLibrary::xGetFBConfigAttrib(Display
*display
,
593 int result
= xGetFBConfigAttribInternal(display
, config
,
600 GLXLibrary::xSwapBuffers(Display
*display
, GLXDrawable drawable
)
603 xSwapBuffersInternal(display
, drawable
);
608 GLXLibrary::xQueryExtensionsString(Display
*display
,
612 const char *result
= xQueryExtensionsStringInternal(display
, screen
);
618 GLXLibrary::xGetClientString(Display
*display
,
622 const char *result
= xGetClientStringInternal(display
, screen
);
628 GLXLibrary::xQueryServerString(Display
*display
,
629 int screen
, int name
)
632 const char *result
= xQueryServerStringInternal(display
, screen
, name
);
638 GLXLibrary::xCreatePixmap(Display
*display
,
641 const int *attrib_list
)
644 GLXPixmap result
= xCreatePixmapInternal(display
, config
,
645 pixmap
, attrib_list
);
651 GLXLibrary::xCreateGLXPixmapWithConfig(Display
*display
,
656 GLXPixmap result
= xCreateGLXPixmapWithConfigInternal(display
, config
, pixmap
);
662 GLXLibrary::xDestroyPixmap(Display
*display
, GLXPixmap pixmap
)
665 xDestroyPixmapInternal(display
, pixmap
);
670 GLXLibrary::xQueryVersion(Display
*display
,
675 Bool result
= xQueryVersionInternal(display
, major
, minor
);
681 GLXLibrary::xBindTexImage(Display
*display
,
682 GLXDrawable drawable
,
684 const int *attrib_list
)
687 xBindTexImageInternal(display
, drawable
, buffer
, attrib_list
);
692 GLXLibrary::xReleaseTexImage(Display
*display
,
693 GLXDrawable drawable
,
697 xReleaseTexImageInternal(display
, drawable
, buffer
);
702 GLXLibrary::xWaitGL()
718 GLXLibrary::xCreateContextAttribs(Display
* display
,
720 GLXContext share_list
,
722 const int* attrib_list
)
725 GLXContext result
= xCreateContextAttribsInternal(display
,
734 already_AddRefed
<GLContextGLX
>
735 GLContextGLX::CreateGLContext(
736 const SurfaceCaps
& caps
,
737 GLContextGLX
* shareContext
,
740 GLXDrawable drawable
,
743 gfxXlibSurface
* pixmap
)
745 GLXLibrary
& glx
= sGLXLibrary
;
748 int err
= glx
.xGetFBConfigAttrib(display
, cfg
,
749 LOCAL_GLX_DOUBLEBUFFER
, &db
);
750 if (LOCAL_GLX_BAD_ATTRIBUTE
!= err
) {
753 printf("[GLX] FBConfig is %sdouble-buffered\n", db
? "" : "not ");
759 nsRefPtr
<GLContextGLX
> glContext
;
762 ScopedXErrorHandler xErrorHandler
;
764 TRY_AGAIN_NO_SHARING
:
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(
783 context
= glx
.xCreateNewContext(
792 glContext
= new GLContextGLX(caps
,
801 if (!glContext
->Init())
807 error
|= xErrorHandler
.SyncAndGetError(display
);
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()
827 // Wrapped context should not destroy glxContext/Surface
832 // see bug 659842 comment 76
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
);
850 SetupLookupFunction();
851 if (!InitWithPrefix("gl", true)) {
855 if (!IsExtensionSupported(EXT_framebuffer_object
))
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!");
881 GLContextGLX::IsCurrent() {
882 return mGLX
->xGetCurrentContext() == mContext
;
886 GLContextGLX::SetupLookupFunction()
888 mLookupFunc
= (PlatformLookupFunction
)&GLXLibrary::xGetProcAddress
;
893 GLContextGLX::IsDoubleBuffered() const
895 return mDoubleBuffered
;
899 GLContextGLX::SupportsRobustness() const
901 return mGLX
->HasRobustness();
905 GLContextGLX::SwapBuffers()
907 if (!mDoubleBuffered
)
909 mGLX
->xSwapBuffers(mDisplay
, mDrawable
);
914 GLContextGLX::GLContextGLX(
915 const SurfaceCaps
& caps
,
916 GLContext
* shareContext
,
919 GLXDrawable aDrawable
,
921 bool aDeleteDrawable
,
922 bool aDoubleBuffered
,
923 gfxXlibSurface
*aPixmap
)
924 : GLContext(caps
, shareContext
, isOffscreen
),//aDeleteDrawable ? true : false, aShareContext, ),
927 mDrawable(aDrawable
),
928 mDeleteDrawable(aDeleteDrawable
),
929 mDoubleBuffered(aDoubleBuffered
),
936 SetProfileVersion(ContextProfile::OpenGLCompatibility
, 200);
940 static GLContextGLX
*
941 GetGlobalContextGLX()
943 return static_cast<GLContextGLX
*>(GLContextProviderGLX::GetGlobalContext());
947 AreCompatibleVisuals(Visual
*one
, Visual
*two
)
949 if (one
->c_class
!= two
->c_class
) {
953 if (one
->red_mask
!= two
->red_mask
||
954 one
->green_mask
!= two
->green_mask
||
955 one
->blue_mask
!= two
->blue_mask
) {
959 if (one
->bits_per_rgb
!= two
->bits_per_rgb
) {
966 static StaticRefPtr
<GLContext
> gGlobalContext
;
968 already_AddRefed
<GLContext
>
969 GLContextProviderGLX::CreateWrappingExisting(void* aContext
, void* aSurface
)
971 if (!sGLXLibrary
.EnsureInitialized()) {
975 if (aContext
&& aSurface
) {
976 SurfaceCaps caps
= SurfaceCaps::Any();
977 nsRefPtr
<GLContextGLX
> glContext
=
978 new GLContextGLX(caps
,
979 nullptr, // SharedContext
981 (Display
*)DefaultXDisplay(), // Display
982 (GLXDrawable
)aSurface
, (GLXContext
)aContext
,
983 false, // aDeleteDrawable,
985 (gfxXlibSurface
*)nullptr);
987 glContext
->mOwnsContext
= false;
988 gGlobalContext
= glContext
;
990 return glContext
.forget();
996 already_AddRefed
<GLContext
>
997 GLContextProviderGLX::CreateForWindow(nsIWidget
*aWidget
)
999 if (!sGLXLibrary
.EnsureInitialized()) {
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
);
1012 NS_ERROR("X Display required for GLX Context provider");
1016 int xscreen
= DefaultScreen(display
);
1017 Window window
= GET_NATIVE_WINDOW(aWidget
);
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
,
1032 cfgs
= sGLXLibrary
.xGetFBConfigs(display
,
1038 NS_WARNING("[GLX] glXGetFBConfigs() failed");
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");
1051 const VisualID widgetVisualID
= XVisualIDFromVisual(widgetAttrs
.visual
);
1053 printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID
);
1056 int matchIndex
= -1;
1058 for (int i
= 0; i
< numConfigs
; i
++) {
1060 sGLXLibrary
.xGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_VISUAL_ID
, &visid
);
1064 if (sGLXLibrary
.IsATI()) {
1067 FindVisualAndDepth(display
, visid
, &visual
, &depth
);
1068 if (depth
== widgetAttrs
.depth
&&
1069 AreCompatibleVisuals(widgetAttrs
.visual
, visual
)) {
1074 if (widgetVisualID
== static_cast<VisualID
>(visid
)) {
1081 if (matchIndex
== -1) {
1082 NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual");
1086 GLContextGLX
*shareContext
= GetGlobalContextGLX();
1088 SurfaceCaps caps
= SurfaceCaps::Any();
1089 nsRefPtr
<GLContextGLX
> glContext
= GLContextGLX::CreateGLContext(caps
,
1097 return glContext
.forget();
1100 static already_AddRefed
<GLContextGLX
>
1101 CreateOffscreenPixmapContext(const gfxIntSize
& size
)
1103 GLXLibrary
& glx
= sGLXLibrary
;
1104 if (!glx
.EnsureInitialized()) {
1108 Display
*display
= DefaultXDisplay();
1109 int xscreen
= DefaultScreen(display
);
1112 LOCAL_GLX_DRAWABLE_TYPE
, LOCAL_GLX_PIXMAP_BIT
,
1113 LOCAL_GLX_X_RENDERABLE
, True
,
1118 ScopedXFree
<GLXFBConfig
> cfgs
;
1119 cfgs
= glx
.xChooseFBConfig(display
,
1127 MOZ_ASSERT(numConfigs
> 0,
1128 "glXChooseFBConfig() failed to match our requested format and violated its spec!");
1131 int chosenIndex
= 0;
1133 for (int i
= 0; i
< numConfigs
; ++i
) {
1136 if (glx
.xGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_DRAWABLE_TYPE
, &dtype
) != Success
1137 || !(dtype
& LOCAL_GLX_PIXMAP_BIT
))
1141 if (glx
.xGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_VISUAL_ID
, &visid
) != Success
1152 NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
1158 FindVisualAndDepth(display
, visid
, &visual
, &depth
);
1159 ScopedXErrorHandler xErrorHandler
;
1160 GLXPixmap glxpixmap
= 0;
1163 gfxIntSize
dummySize(16, 16);
1164 nsRefPtr
<gfxXlibSurface
> xsurface
= gfxXlibSurface::Create(DefaultScreenOfDisplay(display
),
1167 if (xsurface
->CairoStatus() != 0) {
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
,
1178 xsurface
->XDrawable(),
1181 glxpixmap
= glx
.xCreateGLXPixmapWithConfig(display
,
1186 if (glxpixmap
== 0) {
1190 DONE_CREATING_PIXMAP
:
1192 nsRefPtr
<GLContextGLX
> glContext
;
1193 bool serverError
= xErrorHandler
.SyncAndGetError(display
);
1195 if (!error
&& // earlier recorded error
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
,
1212 return glContext
.forget();
1215 already_AddRefed
<GLContext
>
1216 GLContextProviderGLX::CreateHeadless()
1218 gfxIntSize dummySize
= gfxIntSize(16, 16);
1219 nsRefPtr
<GLContext
> glContext
= CreateOffscreenPixmapContext(dummySize
);
1223 return glContext
.forget();
1226 already_AddRefed
<GLContext
>
1227 GLContextProviderGLX::CreateOffscreen(const gfxIntSize
& size
,
1228 const SurfaceCaps
& caps
)
1230 nsRefPtr
<GLContext
> glContext
= CreateHeadless();
1234 if (!glContext
->InitOffscreen(ToIntSize(size
), caps
))
1237 return glContext
.forget();
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
) {
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
;
1272 GLContextProviderGLX::Shutdown()
1274 gGlobalContext
= nullptr;
1277 } /* namespace gl */
1278 } /* namespace mozilla */