1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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) \
10 GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW))
14 #include <X11/Xutil.h>
15 #include "X11UndefineNone.h"
17 #include "mozilla/MathAlgorithms.h"
18 #include "mozilla/StaticPtr.h"
19 #include "mozilla/layers/CompositorOptions.h"
20 #include "mozilla/Range.h"
21 #include "mozilla/ScopeExit.h"
22 #include "mozilla/widget/CompositorWidget.h"
23 #include "mozilla/widget/GtkCompositorWidget.h"
24 #include "mozilla/Unused.h"
27 #include "GLContextProvider.h"
28 #include "GLLibraryLoader.h"
30 #include "nsIWidget.h"
31 #include "GLXLibrary.h"
32 #include "gfxXlibSurface.h"
33 #include "gfxContext.h"
35 #include "gfxPlatform.h"
36 #include "GLContextGLX.h"
38 #include "gfx2DGlue.h"
39 #include "GLScreenBuffer.h"
42 #include "gfxCrashReporterUtils.h"
45 # include "gfxPlatformGtk.h"
51 using namespace mozilla::gfx
;
52 using namespace mozilla::widget
;
54 GLXLibrary sGLXLibrary
;
56 static inline bool HasExtension(const char* aExtensions
,
57 const char* aRequiredExtension
) {
58 return GLContext::ListHasExtension(
59 reinterpret_cast<const GLubyte
*>(aExtensions
), aRequiredExtension
);
62 bool GLXLibrary::EnsureInitialized() {
67 // Don't repeatedly try to initialize.
68 if (mTriedInitializing
) {
71 mTriedInitializing
= true;
73 // Force enabling s3 texture compression. (Bug 774134)
74 PR_SetEnv("force_s3tc_enable=true");
77 // see e.g. bug 608526: it is intrinsically interesting to know whether we
78 // have dynamically linked to libGL.so.1 because at least the NVIDIA
79 // implementation requires an executable stack, which causes mprotect calls,
80 // which trigger glibc bug
81 // http://sourceware.org/bugzilla/show_bug.cgi?id=12225
82 const char* libGLfilename
= "libGL.so.1";
84 libGLfilename
= "libGL.so";
87 const bool forceFeatureReport
= false;
88 ScopedGfxFeatureReporter
reporter(libGLfilename
, forceFeatureReport
);
89 mOGLLibrary
= PR_LoadLibrary(libGLfilename
);
91 NS_WARNING("Couldn't load OpenGL shared library.");
94 reporter
.SetSuccessful();
97 if (gfxEnv::GlxDebug()) {
103 (PRFuncPtr*)&mSymbols.f##X, { \
107 #define END_OF_SYMBOLS \
112 const SymLoadStruct symbols
[] = {
113 /* functions that were in GLX 1.0 */
114 SYMBOL(DestroyContext
),
117 SYMBOL(QueryVersion
),
119 SYMBOL(GetCurrentContext
),
123 /* functions introduced in GLX 1.1 */
124 SYMBOL(QueryExtensionsString
),
125 SYMBOL(GetClientString
),
126 SYMBOL(QueryServerString
),
128 /* functions introduced in GLX 1.3 */
129 SYMBOL(ChooseFBConfig
),
130 SYMBOL(ChooseVisual
),
131 SYMBOL(GetFBConfigAttrib
),
132 SYMBOL(GetFBConfigs
),
133 SYMBOL(CreatePixmap
),
134 SYMBOL(DestroyPixmap
),
135 SYMBOL(CreateNewContext
),
137 // Core in GLX 1.4, ARB extension before.
138 {(PRFuncPtr
*)&mSymbols
.fGetProcAddress
,
139 {{"glXGetProcAddress", "glXGetProcAddressARB"}}},
143 const SymbolLoader
libLoader(*mOGLLibrary
);
144 if (!libLoader
.LoadSymbols(symbols
)) {
145 NS_WARNING("Couldn't load required GLX symbols.");
149 const SymbolLoader
pfnLoader(mSymbols
.fGetProcAddress
);
151 Display
* display
= DefaultXDisplay();
152 int screen
= DefaultScreen(display
);
156 if (!fQueryVersion(display
, &major
, &minor
) || major
!= 1 || minor
< 3) {
157 NS_ERROR("GLX version older than 1.3. (released in 1998)");
162 const SymLoadStruct symbols_texturefrompixmap
[] = {
163 SYMBOL(BindTexImageEXT
), SYMBOL(ReleaseTexImageEXT
), END_OF_SYMBOLS
};
165 const SymLoadStruct symbols_createcontext
[] = {
166 SYMBOL(CreateContextAttribsARB
), END_OF_SYMBOLS
};
168 const SymLoadStruct symbols_videosync
[] = {
169 SYMBOL(GetVideoSyncSGI
), SYMBOL(WaitVideoSyncSGI
), END_OF_SYMBOLS
};
171 const SymLoadStruct symbols_swapcontrol
[] = {SYMBOL(SwapIntervalEXT
),
174 const auto fnLoadSymbols
= [&](const SymLoadStruct
* symbols
) {
175 if (pfnLoader
.LoadSymbols(symbols
)) return true;
177 ClearSymbols(symbols
);
181 const char* clientVendor
= fGetClientString(display
, LOCAL_GLX_VENDOR
);
182 const char* serverVendor
=
183 fQueryServerString(display
, screen
, LOCAL_GLX_VENDOR
);
184 const char* extensionsStr
= fQueryExtensionsString(display
, screen
);
186 if (HasExtension(extensionsStr
, "GLX_EXT_texture_from_pixmap") &&
187 fnLoadSymbols(symbols_texturefrompixmap
)) {
188 mUseTextureFromPixmap
= gfxPrefs::UseGLXTextureFromPixmap();
190 mUseTextureFromPixmap
= false;
191 NS_WARNING("Texture from pixmap disabled");
194 if (HasExtension(extensionsStr
, "GLX_ARB_create_context") &&
195 HasExtension(extensionsStr
, "GLX_ARB_create_context_profile") &&
196 fnLoadSymbols(symbols_createcontext
)) {
197 mHasCreateContextAttribs
= true;
200 if (HasExtension(extensionsStr
, "GLX_ARB_create_context_robustness")) {
201 mHasRobustness
= true;
204 if (HasExtension(extensionsStr
, "GLX_NV_robustness_video_memory_purge")) {
205 mHasVideoMemoryPurge
= true;
208 if (HasExtension(extensionsStr
, "GLX_SGI_video_sync") &&
209 fnLoadSymbols(symbols_videosync
)) {
210 mHasVideoSync
= true;
213 if (!HasExtension(extensionsStr
, "GLX_EXT_swap_control") ||
214 !fnLoadSymbols(symbols_swapcontrol
)) {
216 "GLX_swap_control unsupported, ASAP mode may still block on buffer "
220 mIsATI
= serverVendor
&& DoesStringMatch(serverVendor
, "ATI");
222 serverVendor
&& DoesStringMatch(serverVendor
, "NVIDIA Corporation");
223 mClientIsMesa
= clientVendor
&& DoesStringMatch(clientVendor
, "Mesa");
230 bool GLXLibrary::SupportsTextureFromPixmap(gfxASurface
* aSurface
) {
231 if (!EnsureInitialized()) {
235 if (aSurface
->GetType() != gfxSurfaceType::Xlib
|| !mUseTextureFromPixmap
) {
242 bool GLXLibrary::SupportsVideoSync() {
243 if (!EnsureInitialized()) {
247 return mHasVideoSync
;
250 GLXPixmap
GLXLibrary::CreatePixmap(gfxASurface
* aSurface
) {
251 if (!SupportsTextureFromPixmap(aSurface
)) {
255 gfxXlibSurface
* xs
= static_cast<gfxXlibSurface
*>(aSurface
);
256 const XRenderPictFormat
* format
= xs
->XRenderFormat();
257 if (!format
|| format
->type
!= PictTypeDirect
) {
260 const XRenderDirectFormat
& direct
= format
->direct
;
261 int alphaSize
= FloorLog2(direct
.alphaMask
+ 1);
262 NS_ASSERTION((1 << alphaSize
) - 1 == direct
.alphaMask
,
263 "Unexpected render format with non-adjacent alpha bits");
265 int attribs
[] = {LOCAL_GLX_DOUBLEBUFFER
,
267 LOCAL_GLX_DRAWABLE_TYPE
,
268 LOCAL_GLX_PIXMAP_BIT
,
269 LOCAL_GLX_ALPHA_SIZE
,
271 (alphaSize
? LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT
272 : LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT
),
274 LOCAL_GLX_RENDER_TYPE
,
279 Display
* display
= xs
->XDisplay();
280 int xscreen
= DefaultScreen(display
);
282 ScopedXFree
<GLXFBConfig
> cfgs(
283 fChooseFBConfig(display
, xscreen
, attribs
, &numConfigs
));
285 // Find an fbconfig that matches the pixel format used on the Pixmap.
287 unsigned long redMask
= static_cast<unsigned long>(direct
.redMask
)
289 unsigned long greenMask
= static_cast<unsigned long>(direct
.greenMask
)
291 unsigned long blueMask
= static_cast<unsigned long>(direct
.blueMask
)
293 // This is true if the Pixmap has bits for alpha or unused bits.
294 bool haveNonColorBits
=
295 ~(redMask
| greenMask
| blueMask
) != -1UL << format
->depth
;
297 for (int i
= 0; i
< numConfigs
; i
++) {
299 sGLXLibrary
.fGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_VISUAL_ID
, &id
);
302 FindVisualAndDepth(display
, id
, &visual
, &depth
);
303 if (!visual
|| visual
->c_class
!= TrueColor
||
304 visual
->red_mask
!= redMask
|| visual
->green_mask
!= greenMask
||
305 visual
->blue_mask
!= blueMask
) {
309 // Historically Xlib Visuals did not try to represent an alpha channel
310 // and there was no means to use an alpha channel on a Pixmap. The
311 // Xlib Visual from the fbconfig was not intended to have any
312 // information about alpha bits.
314 // Since then, RENDER has added formats for 32 bit depth Pixmaps.
315 // Some of these formats have bits for alpha and some have unused
318 // Then the Composite extension added a 32 bit depth Visual intended
319 // for Windows with an alpha channel, so bits not in the visual color
320 // masks were expected to be treated as alpha bits.
322 // Usually GLX counts only color bits in the Visual depth, but the
323 // depth of Composite's ARGB Visual includes alpha bits. However,
324 // bits not in the color masks are not necessarily alpha bits because
325 // sometimes (NVIDIA) 32 bit Visuals are added for fbconfigs with 32
326 // bit BUFFER_SIZE but zero alpha bits and 24 color bits (NVIDIA
329 // This checks that the depth matches in one of the two ways.
330 // NVIDIA now forces format->depth == depth so only the first way
331 // is checked for NVIDIA
332 if (depth
!= format
->depth
&&
333 (mIsNVIDIA
|| depth
!= format
->depth
- alphaSize
)) {
337 // If all bits of the Pixmap are color bits and the Pixmap depth
338 // matches the depth of the fbconfig visual, then we can assume that
339 // the driver will do whatever is necessary to ensure that any
340 // GLXPixmap alpha bits are treated as set. We can skip the
341 // ALPHA_SIZE check in this situation. We need to skip this check for
342 // situations (ATI) where there are no fbconfigs without alpha bits.
344 // glXChooseFBConfig should prefer configs with smaller
345 // LOCAL_GLX_BUFFER_SIZE, so we should still get zero alpha bits if
346 // available, except perhaps with NVIDIA drivers where buffer size is
347 // not the specified sum of the component sizes.
348 if (haveNonColorBits
) {
349 // There are bits in the Pixmap format that haven't been matched
350 // against the fbconfig visual. These bits could either represent
351 // alpha or be unused, so just check that the number of alpha bits
354 sGLXLibrary
.fGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_ALPHA_SIZE
,
356 if (size
!= alphaSize
) {
364 if (matchIndex
== -1) {
365 // GLX can't handle A8 surfaces, so this is not really unexpected. The
366 // caller should deal with this situation.
367 NS_WARNING_ASSERTION(
369 "[GLX] Couldn't find a FBConfig matching Pixmap format");
373 int pixmapAttribs
[] = {LOCAL_GLX_TEXTURE_TARGET_EXT
, LOCAL_GLX_TEXTURE_2D_EXT
,
374 LOCAL_GLX_TEXTURE_FORMAT_EXT
,
375 (alphaSize
? LOCAL_GLX_TEXTURE_FORMAT_RGBA_EXT
376 : LOCAL_GLX_TEXTURE_FORMAT_RGB_EXT
),
379 GLXPixmap glxpixmap
=
380 fCreatePixmap(display
, cfgs
[matchIndex
], xs
->XDrawable(), pixmapAttribs
);
385 void GLXLibrary::DestroyPixmap(Display
* aDisplay
, GLXPixmap aPixmap
) {
386 if (!mUseTextureFromPixmap
) {
390 fDestroyPixmap(aDisplay
, aPixmap
);
393 void GLXLibrary::BindTexImage(Display
* aDisplay
, GLXPixmap aPixmap
) {
394 if (!mUseTextureFromPixmap
) {
398 // Make sure all X drawing to the surface has finished before binding to a
401 // Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a
402 // noop when direct rendering unless the current drawable is a
403 // single-buffer window.
408 fBindTexImage(aDisplay
, aPixmap
, LOCAL_GLX_FRONT_LEFT_EXT
, nullptr);
411 void GLXLibrary::ReleaseTexImage(Display
* aDisplay
, GLXPixmap aPixmap
) {
412 if (!mUseTextureFromPixmap
) {
416 fReleaseTexImage(aDisplay
, aPixmap
, LOCAL_GLX_FRONT_LEFT_EXT
);
419 void GLXLibrary::UpdateTexImage(Display
* aDisplay
, GLXPixmap aPixmap
) {
420 // NVIDIA drivers don't require a rebind of the pixmap in order
421 // to display an updated image, and it's faster not to do it.
427 ReleaseTexImage(aDisplay
, aPixmap
);
428 BindTexImage(aDisplay
, aPixmap
);
431 static int (*sOldErrorHandler
)(Display
*, XErrorEvent
*);
432 ScopedXErrorHandler::ErrorEvent sErrorEvent
;
433 static int GLXErrorHandler(Display
* display
, XErrorEvent
* ev
) {
434 if (!sErrorEvent
.mError
.error_code
) {
435 sErrorEvent
.mError
= *ev
;
440 void GLXLibrary::BeforeGLXCall() const {
442 sOldErrorHandler
= XSetErrorHandler(GLXErrorHandler
);
446 void GLXLibrary::AfterGLXCall() const {
448 FinishX(DefaultXDisplay());
449 if (sErrorEvent
.mError
.error_code
) {
451 XGetErrorText(DefaultXDisplay(), sErrorEvent
.mError
.error_code
, buffer
,
453 printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %lu", buffer
,
454 sErrorEvent
.mError
.error_code
,
455 sErrorEvent
.mError
.request_code
,
456 sErrorEvent
.mError
.minor_code
, sErrorEvent
.mError
.serial
);
457 MOZ_ASSERT_UNREACHABLE("AfterGLXCall sErrorEvent");
459 XSetErrorHandler(sOldErrorHandler
);
463 already_AddRefed
<GLContextGLX
> GLContextGLX::CreateGLContext(
464 CreateContextFlags flags
, const SurfaceCaps
& caps
, bool isOffscreen
,
465 Display
* display
, GLXDrawable drawable
, GLXFBConfig cfg
,
466 bool deleteDrawable
, gfxXlibSurface
* pixmap
) {
467 GLXLibrary
& glx
= sGLXLibrary
;
470 int err
= glx
.fGetFBConfigAttrib(display
, cfg
, LOCAL_GLX_DOUBLEBUFFER
, &db
);
471 if (LOCAL_GLX_BAD_ATTRIBUTE
!= err
) {
473 printf("[GLX] FBConfig is %sdouble-buffered\n", db
? "" : "not ");
478 RefPtr
<GLContextGLX
> glContext
;
481 OffMainThreadScopedXErrorHandler xErrorHandler
;
486 if (glx
.HasCreateContextAttribs()) {
487 AutoTArray
<int, 13> attrib_list
;
488 if (glx
.HasRobustness()) {
489 const int robust_attribs
[] = {
490 LOCAL_GLX_CONTEXT_FLAGS_ARB
,
491 LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB
,
492 LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
,
493 LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB
,
495 attrib_list
.AppendElements(robust_attribs
,
496 MOZ_ARRAY_LENGTH(robust_attribs
));
498 if (glx
.HasVideoMemoryPurge()) {
499 const int memory_purge_attribs
[] = {
500 LOCAL_GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
,
503 attrib_list
.AppendElements(memory_purge_attribs
,
504 MOZ_ARRAY_LENGTH(memory_purge_attribs
));
506 if (!(flags
& CreateContextFlags::REQUIRE_COMPAT_PROFILE
)) {
507 int core_attribs
[] = {
508 LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB
,
510 LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB
,
512 LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB
,
513 LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB
,
515 attrib_list
.AppendElements(core_attribs
,
516 MOZ_ARRAY_LENGTH(core_attribs
));
518 attrib_list
.AppendElement(0);
520 context
= glx
.fCreateContextAttribs(display
, cfg
, nullptr, True
,
521 attrib_list
.Elements());
523 context
= glx
.fCreateNewContext(display
, cfg
, LOCAL_GLX_RGBA_TYPE
,
528 glContext
= new GLContextGLX(flags
, caps
, isOffscreen
, display
, drawable
,
529 context
, deleteDrawable
, db
, pixmap
);
530 if (!glContext
->Init()) error
= true;
535 error
|= xErrorHandler
.SyncAndGetError(display
);
538 NS_WARNING("Failed to create GLXContext!");
539 glContext
= nullptr; // note: this must be done while the graceful X
540 // error handler is set, because glxMakeCurrent can
541 // give a GLXBadDrawable error
544 return glContext
.forget();
548 GLContextGLX::~GLContextGLX() {
551 // Wrapped context should not destroy glxContext/Surface
556 // see bug 659842 comment 76
560 mGLX
->fMakeCurrent(mDisplay
, X11None
, nullptr);
562 "glXMakeCurrent failed to release GL context before we call "
563 "glXDestroyContext!");
565 mGLX
->fDestroyContext(mDisplay
, mContext
);
567 if (mDeleteDrawable
) {
568 mGLX
->fDestroyPixmap(mDisplay
, mDrawable
);
572 bool GLContextGLX::Init() {
573 if (!GLContext::Init()) {
577 // EXT_framebuffer_object is not supported on Core contexts
578 // so we'll also check for ARB_framebuffer_object
579 if (!IsExtensionSupported(EXT_framebuffer_object
) &&
580 !IsSupported(GLFeature::framebuffer_object
))
586 bool GLContextGLX::MakeCurrentImpl() const {
587 if (mGLX
->IsMesa()) {
588 // Read into the event queue to ensure that Mesa receives a
589 // DRI2InvalidateBuffers event before drawing. See bug 1280653.
590 Unused
<< XPending(mDisplay
);
593 const bool succeeded
= mGLX
->fMakeCurrent(mDisplay
, mDrawable
, mContext
);
594 NS_ASSERTION(succeeded
, "Failed to make GL context current!");
596 if (!IsOffscreen() && mGLX
->SupportsSwapControl()) {
597 // Many GLX implementations default to blocking until the next
598 // VBlank when calling glXSwapBuffers. We want to run unthrottled
599 // in ASAP mode. See bug 1280744.
600 const bool isASAP
= (gfxPrefs::LayoutFrameRate() == 0);
601 mGLX
->fSwapInterval(mDisplay
, mDrawable
, isASAP
? 0 : 1);
606 bool GLContextGLX::IsCurrentImpl() const {
607 return mGLX
->fGetCurrentContext() == mContext
;
610 Maybe
<SymbolLoader
> GLContextGLX::GetSymbolLoader() const {
611 const auto pfn
= sGLXLibrary
.GetGetProcAddress();
612 return Some(SymbolLoader(pfn
));
615 bool GLContextGLX::IsDoubleBuffered() const { return mDoubleBuffered
; }
617 bool GLContextGLX::SwapBuffers() {
618 if (!mDoubleBuffered
) return false;
619 mGLX
->fSwapBuffers(mDisplay
, mDrawable
);
623 void GLContextGLX::GetWSIInfo(nsCString
* const out
) const {
624 Display
* display
= DefaultXDisplay();
625 int screen
= DefaultScreen(display
);
627 int majorVersion
, minorVersion
;
628 sGLXLibrary
.fQueryVersion(display
, &majorVersion
, &minorVersion
);
630 out
->Append(nsPrintfCString("GLX %u.%u", majorVersion
, minorVersion
));
632 out
->AppendLiteral("\nGLX_VENDOR(client): ");
633 out
->Append(sGLXLibrary
.fGetClientString(display
, LOCAL_GLX_VENDOR
));
635 out
->AppendLiteral("\nGLX_VENDOR(server): ");
637 sGLXLibrary
.fQueryServerString(display
, screen
, LOCAL_GLX_VENDOR
));
639 out
->AppendLiteral("\nExtensions: ");
640 out
->Append(sGLXLibrary
.fQueryExtensionsString(display
, screen
));
643 bool GLContextGLX::OverrideDrawable(GLXDrawable drawable
) {
644 if (Screen()) Screen()->AssureBlitted();
645 Bool result
= mGLX
->fMakeCurrent(mDisplay
, drawable
, mContext
);
649 bool GLContextGLX::RestoreDrawable() {
650 return mGLX
->fMakeCurrent(mDisplay
, mDrawable
, mContext
);
653 GLContextGLX::GLContextGLX(CreateContextFlags flags
, const SurfaceCaps
& caps
,
654 bool isOffscreen
, Display
* aDisplay
,
655 GLXDrawable aDrawable
, GLXContext aContext
,
656 bool aDeleteDrawable
, bool aDoubleBuffered
,
657 gfxXlibSurface
* aPixmap
)
658 : GLContext(flags
, caps
, nullptr, isOffscreen
),
661 mDrawable(aDrawable
),
662 mDeleteDrawable(aDeleteDrawable
),
663 mDoubleBuffered(aDoubleBuffered
),
667 static bool AreCompatibleVisuals(Visual
* one
, Visual
* two
) {
668 if (one
->c_class
!= two
->c_class
) {
672 if (one
->red_mask
!= two
->red_mask
|| one
->green_mask
!= two
->green_mask
||
673 one
->blue_mask
!= two
->blue_mask
) {
677 if (one
->bits_per_rgb
!= two
->bits_per_rgb
) {
684 already_AddRefed
<GLContext
> GLContextProviderGLX::CreateWrappingExisting(
685 void* aContext
, void* aSurface
) {
686 if (!sGLXLibrary
.EnsureInitialized()) {
690 if (aContext
&& aSurface
) {
691 SurfaceCaps caps
= SurfaceCaps::Any();
692 RefPtr
<GLContextGLX
> glContext
=
693 new GLContextGLX(CreateContextFlags::NONE
, caps
,
695 (Display
*)DefaultXDisplay(), // Display
696 (GLXDrawable
)aSurface
, (GLXContext
)aContext
,
697 false, // aDeleteDrawable,
698 true, (gfxXlibSurface
*)nullptr);
700 glContext
->mOwnsContext
= false;
701 return glContext
.forget();
707 already_AddRefed
<GLContext
> CreateForWidget(Display
* aXDisplay
, Window aXWindow
,
709 bool aForceAccelerated
) {
710 if (!sGLXLibrary
.EnsureInitialized()) {
714 // Currently, we take whatever Visual the window already has, and
715 // try to create an fbconfig for that visual. This isn't
716 // necessarily what we want in the long run; an fbconfig may not
717 // be available for the existing visual, or if it is, the GL
718 // performance might be suboptimal. But using the existing visual
719 // is a relatively safe intermediate step.
722 NS_ERROR("X Display required for GLX Context provider");
726 int xscreen
= DefaultScreen(aXDisplay
);
728 ScopedXFree
<GLXFBConfig
> cfgs
;
731 if (!GLContextGLX::FindFBConfigForWindow(aXDisplay
, xscreen
, aXWindow
, &cfgs
,
732 &config
, &visid
, aWebRender
)) {
736 CreateContextFlags flags
;
738 flags
= CreateContextFlags::NONE
; // WR needs GL3.2+
740 flags
= CreateContextFlags::REQUIRE_COMPAT_PROFILE
;
742 return GLContextGLX::CreateGLContext(flags
, SurfaceCaps::Any(), false,
743 aXDisplay
, aXWindow
, config
, false,
747 already_AddRefed
<GLContext
> GLContextProviderGLX::CreateForCompositorWidget(
748 CompositorWidget
* aCompositorWidget
, bool aWebRender
,
749 bool aForceAccelerated
) {
750 if (!aCompositorWidget
) {
754 GtkCompositorWidget
* compWidget
= aCompositorWidget
->AsX11();
755 MOZ_ASSERT(compWidget
);
757 return CreateForWidget(compWidget
->XDisplay(), compWidget
->XWindow(),
758 aWebRender
, aForceAccelerated
);
761 already_AddRefed
<GLContext
> GLContextProviderGLX::CreateForWindow(
762 nsIWidget
* aWidget
, bool aWebRender
, bool aForceAccelerated
) {
764 (Display
*)aWidget
->GetNativeData(NS_NATIVE_COMPOSITOR_DISPLAY
);
765 Window window
= GET_NATIVE_WINDOW(aWidget
);
767 return CreateForWidget(display
, window
, aWebRender
, aForceAccelerated
);
770 static bool ChooseConfig(GLXLibrary
* glx
, Display
* display
, int screen
,
771 const SurfaceCaps
& minCaps
,
772 ScopedXFree
<GLXFBConfig
>* const out_scopedConfigArr
,
773 GLXFBConfig
* const out_config
, int* const out_visid
) {
774 ScopedXFree
<GLXFBConfig
>& scopedConfigArr
= *out_scopedConfigArr
;
776 if (minCaps
.antialias
) return false;
778 int attribs
[] = {LOCAL_GLX_DRAWABLE_TYPE
,
779 LOCAL_GLX_PIXMAP_BIT
,
780 LOCAL_GLX_X_RENDERABLE
,
784 LOCAL_GLX_GREEN_SIZE
,
788 LOCAL_GLX_ALPHA_SIZE
,
789 minCaps
.alpha
? 8 : 0,
790 LOCAL_GLX_DEPTH_SIZE
,
791 minCaps
.depth
? 16 : 0,
792 LOCAL_GLX_STENCIL_SIZE
,
793 minCaps
.stencil
? 8 : 0,
797 scopedConfigArr
= glx
->fChooseFBConfig(display
, screen
, attribs
, &numConfigs
);
798 if (!scopedConfigArr
|| !numConfigs
) return false;
800 // Issues with glxChooseFBConfig selection and sorting:
801 // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't
803 // alpha bits, we'll probably get RGBA anyways, since 32 is more than 24.
804 // * DEPTH_SIZE is sorted largest first, including for `0` inputs.
805 // * STENCIL_SIZE is smallest first, but it might return `8` even though we
809 // For now, we don't care about these. We *will* care when we do XPixmap
812 for (int i
= 0; i
< numConfigs
; ++i
) {
813 GLXFBConfig curConfig
= scopedConfigArr
[i
];
816 if (glx
->fGetFBConfigAttrib(display
, curConfig
, LOCAL_GLX_VISUAL_ID
,
817 &visid
) != Success
) {
821 if (!visid
) continue;
823 *out_config
= curConfig
;
831 bool GLContextGLX::FindVisual(Display
* display
, int screen
, bool useWebRender
,
832 bool useAlpha
, int* const out_visualId
) {
833 if (!sGLXLibrary
.EnsureInitialized()) {
837 XVisualInfo visualTemplate
;
838 visualTemplate
.screen
= screen
;
840 // Get all visuals of screen
843 XVisualInfo
* xVisuals
=
844 XGetVisualInfo(display
, VisualScreenMask
, &visualTemplate
, &visualsLen
);
848 const Range
<XVisualInfo
> visualInfos(xVisuals
, visualsLen
);
849 auto cleanupVisuals
= MakeScopeExit([&] { XFree(xVisuals
); });
851 // Get default visual info
853 Visual
* defaultVisual
= DefaultVisual(display
, screen
);
854 const auto defaultVisualInfo
= [&]() -> const XVisualInfo
* {
855 for (const auto& cur
: visualInfos
) {
856 if (cur
.visual
== defaultVisual
) {
862 if (!defaultVisualInfo
) {
867 const int bpp
= useAlpha
? 32 : 24;
868 const int alphaSize
= useAlpha
? 8 : 0;
869 const int depthSize
= useWebRender
? 24 : 0;
871 for (auto& cur
: visualInfos
) {
872 const auto fnConfigMatches
= [&](const int pname
, const int expected
) {
874 if (sGLXLibrary
.fGetConfig(display
, &cur
, pname
, &actual
)) {
877 return actual
== expected
;
880 // Check if visual is compatible.
881 if (cur
.depth
!= bpp
|| cur
.c_class
!= defaultVisualInfo
->c_class
) {
885 // Check if visual is compatible to GL requests.
886 if (fnConfigMatches(LOCAL_GLX_USE_GL
, 1) &&
887 fnConfigMatches(LOCAL_GLX_DOUBLEBUFFER
, 1) &&
888 fnConfigMatches(LOCAL_GLX_RED_SIZE
, 8) &&
889 fnConfigMatches(LOCAL_GLX_GREEN_SIZE
, 8) &&
890 fnConfigMatches(LOCAL_GLX_BLUE_SIZE
, 8) &&
891 fnConfigMatches(LOCAL_GLX_ALPHA_SIZE
, alphaSize
) &&
892 fnConfigMatches(LOCAL_GLX_DEPTH_SIZE
, depthSize
)) {
893 *out_visualId
= cur
.visualid
;
901 bool GLContextGLX::FindFBConfigForWindow(
902 Display
* display
, int screen
, Window window
,
903 ScopedXFree
<GLXFBConfig
>* const out_scopedConfigArr
,
904 GLXFBConfig
* const out_config
, int* const out_visid
, bool aWebRender
) {
905 // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so
906 // we could probably do this first and replace the glXGetFBConfigs
907 // with glXChooseConfigs. Docs are sparklingly clear as always.
908 XWindowAttributes windowAttrs
;
909 if (!XGetWindowAttributes(display
, window
, &windowAttrs
)) {
910 NS_WARNING("[GLX] XGetWindowAttributes() failed");
914 ScopedXFree
<GLXFBConfig
>& cfgs
= *out_scopedConfigArr
;
916 const int webrenderAttribs
[] = {LOCAL_GLX_ALPHA_SIZE
,
917 windowAttrs
.depth
== 32 ? 8 : 0,
918 LOCAL_GLX_DEPTH_SIZE
,
920 LOCAL_GLX_DOUBLEBUFFER
,
925 cfgs
= sGLXLibrary
.fChooseFBConfig(display
, screen
, webrenderAttribs
,
928 cfgs
= sGLXLibrary
.fGetFBConfigs(display
, screen
, &numConfigs
);
932 NS_WARNING("[GLX] glXGetFBConfigs() failed");
935 NS_ASSERTION(numConfigs
> 0, "No FBConfigs found!");
937 const VisualID windowVisualID
= XVisualIDFromVisual(windowAttrs
.visual
);
939 printf("[GLX] window %lx has VisualID 0x%lx\n", window
, windowVisualID
);
942 for (int i
= 0; i
< numConfigs
; i
++) {
944 sGLXLibrary
.fGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_VISUAL_ID
,
947 // WebRender compatible GLX visual is configured
948 // at nsWindow::Create() by GLContextGLX::FindVisual(),
949 // just reuse it here.
950 if (windowVisualID
== static_cast<VisualID
>(visid
)) {
951 *out_config
= cfgs
[i
];
958 // We don't have a frame buffer visual which matches the GLX visual
959 // from GLContextGLX::FindVisual(). Let's try to find a near one and hope
960 // we're not on NVIDIA (Bug 1478454) as it causes X11 BadMatch error there.
961 for (int i
= 0; i
< numConfigs
; i
++) {
963 sGLXLibrary
.fGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_VISUAL_ID
,
968 FindVisualAndDepth(display
, visid
, &visual
, &depth
);
969 if (depth
== windowAttrs
.depth
&&
970 AreCompatibleVisuals(windowAttrs
.visual
, visual
)) {
971 *out_config
= cfgs
[i
];
978 NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual");
982 static already_AddRefed
<GLContextGLX
> CreateOffscreenPixmapContext(
983 CreateContextFlags flags
, const IntSize
& size
, const SurfaceCaps
& minCaps
,
984 nsACString
* const out_failureId
) {
985 GLXLibrary
* glx
= &sGLXLibrary
;
986 if (!glx
->EnsureInitialized()) return nullptr;
988 Display
* display
= DefaultXDisplay();
989 int screen
= DefaultScreen(display
);
991 ScopedXFree
<GLXFBConfig
> scopedConfigArr
;
994 if (!ChooseConfig(glx
, display
, screen
, minCaps
, &scopedConfigArr
, &config
,
996 NS_WARNING("Failed to find a compatible config.");
1002 FindVisualAndDepth(display
, visid
, &visual
, &depth
);
1004 OffMainThreadScopedXErrorHandler xErrorHandler
;
1007 gfx::IntSize
dummySize(16, 16);
1008 RefPtr
<gfxXlibSurface
> surface
= gfxXlibSurface::Create(
1009 DefaultScreenOfDisplay(display
), visual
, dummySize
);
1010 if (surface
->CairoStatus() != 0) {
1011 mozilla::Unused
<< xErrorHandler
.SyncAndGetError(display
);
1015 // Handle slightly different signature between glXCreatePixmap and
1016 // its pre-GLX-1.3 extension equivalent (though given the ABI, we
1017 // might not need to).
1018 const auto drawable
= surface
->XDrawable();
1019 const auto pixmap
= glx
->fCreatePixmap(display
, config
, drawable
, nullptr);
1024 bool serverError
= xErrorHandler
.SyncAndGetError(display
);
1025 if (error
|| serverError
) return nullptr;
1027 return GLContextGLX::CreateGLContext(flags
, minCaps
, true, display
, pixmap
,
1028 config
, true, surface
);
1032 already_AddRefed
<GLContext
> GLContextProviderGLX::CreateHeadless(
1033 CreateContextFlags flags
, nsACString
* const out_failureId
) {
1034 IntSize dummySize
= IntSize(16, 16);
1035 SurfaceCaps dummyCaps
= SurfaceCaps::Any();
1036 return CreateOffscreenPixmapContext(flags
, dummySize
, dummyCaps
,
1041 already_AddRefed
<GLContext
> GLContextProviderGLX::CreateOffscreen(
1042 const IntSize
& size
, const SurfaceCaps
& minCaps
, CreateContextFlags flags
,
1043 nsACString
* const out_failureId
) {
1044 SurfaceCaps minBackbufferCaps
= minCaps
;
1045 if (minCaps
.antialias
) {
1046 minBackbufferCaps
.antialias
= false;
1047 minBackbufferCaps
.depth
= false;
1048 minBackbufferCaps
.stencil
= false;
1051 RefPtr
<GLContext
> gl
;
1052 gl
= CreateOffscreenPixmapContext(flags
, size
, minBackbufferCaps
,
1054 if (!gl
) return nullptr;
1056 if (!gl
->InitOffscreen(size
, minCaps
)) {
1057 *out_failureId
= NS_LITERAL_CSTRING("FEATURE_FAILURE_GLX_INIT");
1065 GLContext
* GLContextProviderGLX::GetGlobalContext() {
1066 // Context sharing not supported.
1071 void GLContextProviderGLX::Shutdown() {}
1073 } /* namespace gl */
1074 } /* namespace mozilla */