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/Sprintf.h"
23 #include "mozilla/StaticPrefs_gfx.h"
24 #include "mozilla/StaticPrefs_layout.h"
25 #include "mozilla/widget/CompositorWidget.h"
26 #include "mozilla/widget/GtkCompositorWidget.h"
27 #include "mozilla/Unused.h"
30 #include "GLContextProvider.h"
31 #include "GLLibraryLoader.h"
33 #include "nsIWidget.h"
34 #include "GLXLibrary.h"
35 #include "gfxContext.h"
37 #include "gfxPlatform.h"
38 #include "GLContextGLX.h"
40 #include "gfx2DGlue.h"
41 #include "GLScreenBuffer.h"
43 #include "gfxCrashReporterUtils.h"
46 # include "gfxPlatformGtk.h"
49 namespace mozilla::gl
{
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(Display
* aDisplay
) {
67 // Don't repeatedly try to initialize.
68 if (mTriedInitializing
) {
71 mTriedInitializing
= true;
78 // Force enabling s3 texture compression. (Bug 774134)
79 PR_SetEnv("force_s3tc_enable=true");
82 // see e.g. bug 608526: it is intrinsically interesting to know whether we
83 // have dynamically linked to libGL.so.1 because at least the NVIDIA
84 // implementation requires an executable stack, which causes mprotect calls,
85 // which trigger glibc bug
86 // http://sourceware.org/bugzilla/show_bug.cgi?id=12225
87 const char* libGLfilename
= "libGL.so.1";
88 #if defined(__OpenBSD__) || defined(__NetBSD__)
89 libGLfilename
= "libGL.so";
92 const bool forceFeatureReport
= false;
93 ScopedGfxFeatureReporter
reporter(libGLfilename
, forceFeatureReport
);
94 mOGLLibrary
= PR_LoadLibrary(libGLfilename
);
96 NS_WARNING("Couldn't load OpenGL shared library.");
99 reporter
.SetSuccessful();
102 if (gfxEnv::MOZ_GLX_DEBUG()) {
108 (PRFuncPtr*)&mSymbols.f##X, { \
112 #define END_OF_SYMBOLS \
117 const SymLoadStruct symbols
[] = {
118 /* functions that were in GLX 1.0 */
119 SYMBOL(DestroyContext
),
122 SYMBOL(QueryVersion
),
124 SYMBOL(GetCurrentContext
),
128 /* functions introduced in GLX 1.1 */
129 SYMBOL(QueryExtensionsString
),
130 SYMBOL(GetClientString
),
131 SYMBOL(QueryServerString
),
133 /* functions introduced in GLX 1.3 */
134 SYMBOL(ChooseFBConfig
),
135 SYMBOL(ChooseVisual
),
136 SYMBOL(GetFBConfigAttrib
),
137 SYMBOL(GetFBConfigs
),
138 SYMBOL(CreatePixmap
),
139 SYMBOL(DestroyPixmap
),
140 SYMBOL(CreateNewContext
),
142 // Core in GLX 1.4, ARB extension before.
143 {(PRFuncPtr
*)&mSymbols
.fGetProcAddress
,
144 {{"glXGetProcAddress", "glXGetProcAddressARB"}}},
148 const SymbolLoader
libLoader(*mOGLLibrary
);
149 if (!libLoader
.LoadSymbols(symbols
)) {
150 NS_WARNING("Couldn't load required GLX symbols.");
154 const SymbolLoader
pfnLoader(mSymbols
.fGetProcAddress
);
156 int screen
= DefaultScreen(aDisplay
);
160 if (!fQueryVersion(aDisplay
, &major
, &minor
) || major
!= 1 || minor
< 3) {
161 NS_ERROR("GLX version older than 1.3. (released in 1998)");
166 const SymLoadStruct symbols_createcontext
[] = {
167 SYMBOL(CreateContextAttribsARB
), END_OF_SYMBOLS
};
169 const SymLoadStruct symbols_videosync
[] = {
170 SYMBOL(GetVideoSyncSGI
), SYMBOL(WaitVideoSyncSGI
), END_OF_SYMBOLS
};
172 const SymLoadStruct symbols_swapcontrol
[] = {SYMBOL(SwapIntervalEXT
),
175 const SymLoadStruct symbols_querydrawable
[] = {SYMBOL(QueryDrawable
),
178 const auto fnLoadSymbols
= [&](const SymLoadStruct
* symbols
) {
179 if (pfnLoader
.LoadSymbols(symbols
)) return true;
181 ClearSymbols(symbols
);
185 const char* clientVendor
= fGetClientString(aDisplay
, LOCAL_GLX_VENDOR
);
186 const char* serverVendor
=
187 fQueryServerString(aDisplay
, screen
, LOCAL_GLX_VENDOR
);
188 const char* extensionsStr
= fQueryExtensionsString(aDisplay
, screen
);
190 if (HasExtension(extensionsStr
, "GLX_ARB_create_context") &&
191 HasExtension(extensionsStr
, "GLX_ARB_create_context_profile") &&
192 fnLoadSymbols(symbols_createcontext
)) {
193 mHasCreateContextAttribs
= true;
196 if (HasExtension(extensionsStr
, "GLX_ARB_create_context_robustness")) {
197 mHasRobustness
= true;
200 if (HasExtension(extensionsStr
, "GLX_NV_robustness_video_memory_purge")) {
201 mHasVideoMemoryPurge
= true;
204 if (HasExtension(extensionsStr
, "GLX_SGI_video_sync") &&
205 fnLoadSymbols(symbols_videosync
)) {
206 mHasVideoSync
= true;
209 if (!HasExtension(extensionsStr
, "GLX_EXT_swap_control") ||
210 !fnLoadSymbols(symbols_swapcontrol
)) {
212 "GLX_swap_control unsupported, ASAP mode may still block on buffer "
216 if (HasExtension(extensionsStr
, "GLX_EXT_buffer_age") &&
217 fnLoadSymbols(symbols_querydrawable
)) {
218 mHasBufferAge
= true;
221 mIsATI
= serverVendor
&& DoesStringMatch(serverVendor
, "ATI");
223 serverVendor
&& DoesStringMatch(serverVendor
, "NVIDIA Corporation");
224 mClientIsMesa
= clientVendor
&& DoesStringMatch(clientVendor
, "Mesa");
228 // This needs to be after `fQueryServerString` is called so that the
230 MesaMemoryLeakWorkaround();
235 bool GLXLibrary::SupportsVideoSync(Display
* aDisplay
) {
236 if (!EnsureInitialized(aDisplay
)) {
240 return mHasVideoSync
;
243 static int (*sOldErrorHandler
)(Display
*, XErrorEvent
*);
244 static XErrorEvent sErrorEvent
= {};
246 static int GLXErrorHandler(Display
* display
, XErrorEvent
* ev
) {
247 if (!sErrorEvent
.error_code
) {
253 GLXLibrary::WrapperScope::WrapperScope(const GLXLibrary
& glx
,
254 const char* const funcName
,
256 : mGlx(glx
), mFuncName(funcName
), mDisplay(aDisplay
) {
258 sOldErrorHandler
= XSetErrorHandler(GLXErrorHandler
);
262 GLXLibrary::WrapperScope::~WrapperScope() {
267 if (sErrorEvent
.error_code
) {
268 char buffer
[100] = {};
270 XGetErrorText(mDisplay
, sErrorEvent
.error_code
, buffer
, sizeof(buffer
));
272 SprintfLiteral(buffer
, "%d", sErrorEvent
.error_code
);
274 printf_stderr("X ERROR after %s: %s (%i) - Request: %i.%i, Serial: %lu",
275 mFuncName
, buffer
, sErrorEvent
.error_code
,
276 sErrorEvent
.request_code
, sErrorEvent
.minor_code
,
278 MOZ_ASSERT_UNREACHABLE("AfterGLXCall sErrorEvent");
280 const auto was
= XSetErrorHandler(sOldErrorHandler
);
281 if (was
!= GLXErrorHandler
) {
282 NS_WARNING("Concurrent XSetErrorHandlers");
287 // Returns the GTK display if available; otherwise, if a display was
288 // previously opened by this method and is still open, returns a
289 // reference to it; otherwise, opens a new connection. (The non-GTK
290 // cases are similar to what we do for EGL.)
291 std::shared_ptr
<XlibDisplay
> GLXLibrary::GetDisplay() {
292 std::shared_ptr
<XlibDisplay
> display
;
294 #ifdef MOZ_WIDGET_GTK
295 static const bool kHaveGtk
= !!gdk_display_get_default();
297 display
= XlibDisplay::Borrow(DefaultXDisplay());
304 auto ownDisplay
= mOwnDisplay
.Lock();
305 display
= ownDisplay
->lock();
310 display
= XlibDisplay::Open(nullptr);
311 if (NS_WARN_IF(!display
)) {
314 *ownDisplay
= display
;
318 already_AddRefed
<GLContextGLX
> GLContextGLX::CreateGLContext(
319 const GLContextDesc
& desc
, std::shared_ptr
<XlibDisplay
> display
,
320 GLXDrawable drawable
, GLXFBConfig cfg
, Drawable ownedPixmap
) {
321 GLXLibrary
& glx
= sGLXLibrary
;
323 int isDoubleBuffered
= 0;
324 int err
= glx
.fGetFBConfigAttrib(*display
, cfg
, LOCAL_GLX_DOUBLEBUFFER
,
326 if (LOCAL_GLX_BAD_ATTRIBUTE
!= err
) {
328 printf("[GLX] FBConfig is %sdouble-buffered\n",
329 isDoubleBuffered
? "" : "not ");
333 if (!glx
.HasCreateContextAttribs()) {
334 NS_WARNING("Cannot create GLContextGLX without glxCreateContextAttribs");
340 const auto CreateWithAttribs
=
341 [&](const std::vector
<int>& attribs
) -> RefPtr
<GLContextGLX
> {
342 auto terminated
= attribs
;
343 terminated
.push_back(0);
345 const auto glxContext
= glx
.fCreateContextAttribs(
346 *display
, cfg
, nullptr, X11True
, terminated
.data());
347 if (!glxContext
) return nullptr;
348 const RefPtr
<GLContextGLX
> ret
= new GLContextGLX(
349 desc
, display
, drawable
, glxContext
, isDoubleBuffered
, ownedPixmap
);
351 if (!ret
->Init()) return nullptr;
358 RefPtr
<GLContextGLX
> glContext
;
360 std::vector
<int> attribs
;
361 attribs
.insert(attribs
.end(), {
362 LOCAL_GLX_RENDER_TYPE
,
365 if (glx
.HasVideoMemoryPurge()) {
366 attribs
.insert(attribs
.end(),
368 LOCAL_GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
,
373 !(desc
.flags
& CreateContextFlags::REQUIRE_COMPAT_PROFILE
);
375 attribs
.insert(attribs
.end(), {
376 LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB
,
378 LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB
,
380 LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB
,
381 LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB
,
385 if (glx
.HasRobustness()) {
386 auto withRobustness
= attribs
;
387 withRobustness
.insert(withRobustness
.end(),
389 LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
,
390 LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB
,
394 auto withRBAB
= withRobustness
;
395 withRBAB
.insert(withRBAB
.end(),
397 LOCAL_GLX_CONTEXT_FLAGS_ARB
,
398 LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB
,
401 glContext
= CreateWithAttribs(withRBAB
);
403 NS_WARNING("Failed to create+init GLContextGLX with RBAB");
409 glContext
= CreateWithAttribs(withRobustness
);
411 NS_WARNING("Failed to create+init GLContextGLX with Robustness");
417 glContext
= CreateWithAttribs(attribs
);
419 NS_WARNING("Failed to create+init GLContextGLX with required attribs");
423 return glContext
.forget();
426 GLContextGLX::~GLContextGLX() {
429 // Wrapped context should not destroy glxContext/Surface
434 // see bug 659842 comment 76
435 bool success
= mGLX
->fMakeCurrent(*mDisplay
, X11None
, nullptr);
438 "glXMakeCurrent failed to release GL context before we call "
439 "glXDestroyContext!");
442 mGLX
->fDestroyContext(*mDisplay
, mContext
);
444 // If we own the enclosed X pixmap, then free it after we free the enclosing
447 mGLX
->fDestroyPixmap(*mDisplay
, mDrawable
);
448 XFreePixmap(*mDisplay
, mOwnedPixmap
);
452 bool GLContextGLX::Init() {
453 if (!GLContext::Init()) {
457 // EXT_framebuffer_object is not supported on Core contexts
458 // so we'll also check for ARB_framebuffer_object
459 if (!IsExtensionSupported(EXT_framebuffer_object
) &&
460 !IsSupported(GLFeature::framebuffer_object
))
466 bool GLContextGLX::MakeCurrentImpl() const {
467 if (mGLX
->IsMesa()) {
468 // Read into the event queue to ensure that Mesa receives a
469 // DRI2InvalidateBuffers event before drawing. See bug 1280653.
470 Unused
<< XPending(*mDisplay
);
473 const bool succeeded
= mGLX
->fMakeCurrent(*mDisplay
, mDrawable
, mContext
);
475 NS_WARNING("Failed to make GL context current!");
478 if (!IsOffscreen() && mGLX
->SupportsSwapControl()) {
479 // Many GLX implementations default to blocking until the next
480 // VBlank when calling glXSwapBuffers. We want to run unthrottled
481 // in ASAP mode. See bug 1280744.
482 const bool swapInterval
= gfxVars::SwapIntervalGLX();
483 const bool isASAP
= (StaticPrefs::layout_frame_rate() == 0);
484 const int interval
= (swapInterval
&& !isASAP
) ? 1 : 0;
485 mGLX
->fSwapInterval(*mDisplay
, mDrawable
, interval
);
490 bool GLContextGLX::IsCurrentImpl() const {
491 return mGLX
->fGetCurrentContext() == mContext
;
494 Maybe
<SymbolLoader
> GLContextGLX::GetSymbolLoader() const {
495 const auto pfn
= sGLXLibrary
.GetGetProcAddress();
496 return Some(SymbolLoader(pfn
));
499 bool GLContextGLX::IsDoubleBuffered() const { return mDoubleBuffered
; }
501 bool GLContextGLX::SwapBuffers() {
502 if (!mDoubleBuffered
) return false;
503 mGLX
->fSwapBuffers(*mDisplay
, mDrawable
);
507 GLint
GLContextGLX::GetBufferAge() const {
508 if (!sGLXLibrary
.SupportsBufferAge()) {
513 mGLX
->fQueryDrawable(*mDisplay
, mDrawable
, LOCAL_GLX_BACK_BUFFER_AGE_EXT
,
515 if (result
> INT32_MAX
) {
516 // If the result can't fit, just assume the buffer cannot be reused.
522 void GLContextGLX::GetWSIInfo(nsCString
* const out
) const {
523 int screen
= DefaultScreen(mDisplay
->get());
525 int majorVersion
, minorVersion
;
526 sGLXLibrary
.fQueryVersion(*mDisplay
, &majorVersion
, &minorVersion
);
528 out
->Append(nsPrintfCString("GLX %u.%u", majorVersion
, minorVersion
));
530 out
->AppendLiteral("\nGLX_VENDOR(client): ");
531 out
->Append(sGLXLibrary
.fGetClientString(*mDisplay
, LOCAL_GLX_VENDOR
));
533 out
->AppendLiteral("\nGLX_VENDOR(server): ");
535 sGLXLibrary
.fQueryServerString(*mDisplay
, screen
, LOCAL_GLX_VENDOR
));
537 out
->AppendLiteral("\nExtensions: ");
538 out
->Append(sGLXLibrary
.fQueryExtensionsString(*mDisplay
, screen
));
541 bool GLContextGLX::OverrideDrawable(GLXDrawable drawable
) {
542 return mGLX
->fMakeCurrent(*mDisplay
, drawable
, mContext
);
545 bool GLContextGLX::RestoreDrawable() {
546 return mGLX
->fMakeCurrent(*mDisplay
, mDrawable
, mContext
);
549 GLContextGLX::GLContextGLX(const GLContextDesc
& desc
,
550 std::shared_ptr
<XlibDisplay
> aDisplay
,
551 GLXDrawable aDrawable
, GLXContext aContext
,
552 bool aDoubleBuffered
, Drawable aOwnedPixmap
)
553 : GLContext(desc
, nullptr),
556 mDrawable(aDrawable
),
557 mOwnedPixmap(aOwnedPixmap
),
558 mDoubleBuffered(aDoubleBuffered
),
559 mGLX(&sGLXLibrary
) {}
561 static bool AreCompatibleVisuals(Visual
* one
, Visual
* two
) {
562 if (one
->c_class
!= two
->c_class
) {
566 if (one
->red_mask
!= two
->red_mask
|| one
->green_mask
!= two
->green_mask
||
567 one
->blue_mask
!= two
->blue_mask
) {
571 if (one
->bits_per_rgb
!= two
->bits_per_rgb
) {
578 already_AddRefed
<GLContext
> CreateForWidget(Display
* aXDisplay
, Window aXWindow
,
579 bool aHardwareWebRender
,
580 bool aForceAccelerated
) {
581 if (!sGLXLibrary
.EnsureInitialized(aXDisplay
)) {
585 // Currently, we take whatever Visual the window already has, and
586 // try to create an fbconfig for that visual. This isn't
587 // necessarily what we want in the long run; an fbconfig may not
588 // be available for the existing visual, or if it is, the GL
589 // performance might be suboptimal. But using the existing visual
590 // is a relatively safe intermediate step.
593 NS_ERROR("X Display required for GLX Context provider");
598 NS_ERROR("X window required for GLX Context provider");
602 int xscreen
= DefaultScreen(aXDisplay
);
606 if (!GLContextGLX::FindFBConfigForWindow(aXDisplay
, xscreen
, aXWindow
,
608 aHardwareWebRender
)) {
612 CreateContextFlags flags
;
613 if (aHardwareWebRender
) {
614 flags
= CreateContextFlags::NONE
; // WR needs GL3.2+
616 flags
= CreateContextFlags::REQUIRE_COMPAT_PROFILE
;
618 return GLContextGLX::CreateGLContext(
619 {{flags
}, false}, XlibDisplay::Borrow(aXDisplay
), aXWindow
, config
);
622 already_AddRefed
<GLContext
> GLContextProviderGLX::CreateForCompositorWidget(
623 CompositorWidget
* aCompositorWidget
, bool aHardwareWebRender
,
624 bool aForceAccelerated
) {
625 if (!aCompositorWidget
) {
629 GtkCompositorWidget
* compWidget
= aCompositorWidget
->AsGTK();
630 MOZ_ASSERT(compWidget
);
632 return CreateForWidget(DefaultXDisplay(), compWidget
->XWindow(),
633 aHardwareWebRender
, aForceAccelerated
);
636 static bool ChooseConfig(GLXLibrary
* glx
, Display
* display
, int screen
,
637 GLXFBConfig
* const out_config
, int* const out_visid
) {
638 const int attribs
[] = {
639 LOCAL_GLX_RENDER_TYPE
,
641 LOCAL_GLX_DRAWABLE_TYPE
,
642 LOCAL_GLX_PIXMAP_BIT
,
643 LOCAL_GLX_X_RENDERABLE
,
647 LOCAL_GLX_GREEN_SIZE
,
651 LOCAL_GLX_ALPHA_SIZE
,
653 LOCAL_GLX_DEPTH_SIZE
,
655 LOCAL_GLX_STENCIL_SIZE
,
661 const auto scopedConfigArr
= glx
->fChooseFBConfig(display
, screen
, attribs
, &numConfigs
);
662 const auto freeConfigList
= MakeScopeExit([&]() {
663 if (scopedConfigArr
) {
664 XFree(scopedConfigArr
);
667 if (!scopedConfigArr
|| !numConfigs
) return false;
669 // Issues with glxChooseFBConfig selection and sorting:
670 // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't
672 // alpha bits, we'll probably get RGBA anyways, since 32 is more than 24.
673 // * DEPTH_SIZE is sorted largest first, including for `0` inputs.
674 // * STENCIL_SIZE is smallest first, but it might return `8` even though we
678 // For now, we don't care about these. We *will* care when we do XPixmap
681 for (int i
= 0; i
< numConfigs
; ++i
) {
682 GLXFBConfig curConfig
= scopedConfigArr
[i
];
685 if (glx
->fGetFBConfigAttrib(display
, curConfig
, LOCAL_GLX_VISUAL_ID
,
686 &visid
) != Success
) {
690 if (!visid
) continue;
692 *out_config
= curConfig
;
700 bool GLContextGLX::FindVisual(Display
* display
, int screen
,
701 int* const out_visualId
) {
702 if (!sGLXLibrary
.EnsureInitialized(display
)) {
706 XVisualInfo visualTemplate
;
707 visualTemplate
.screen
= screen
;
709 // Get all visuals of screen
712 XVisualInfo
* xVisuals
=
713 XGetVisualInfo(display
, VisualScreenMask
, &visualTemplate
, &visualsLen
);
717 const Range
<XVisualInfo
> visualInfos(xVisuals
, visualsLen
);
718 auto cleanupVisuals
= MakeScopeExit([&] { XFree(xVisuals
); });
720 // Get default visual info
722 Visual
* defaultVisual
= DefaultVisual(display
, screen
);
723 const auto defaultVisualInfo
= [&]() -> const XVisualInfo
* {
724 for (const auto& cur
: visualInfos
) {
725 if (cur
.visual
== defaultVisual
) {
731 if (!defaultVisualInfo
) {
738 for (auto& cur
: visualInfos
) {
739 const auto fnConfigMatches
= [&](const int pname
, const int expected
) {
741 if (sGLXLibrary
.fGetConfig(display
, &cur
, pname
, &actual
)) {
744 return actual
== expected
;
747 // Check if visual is compatible.
748 if (cur
.depth
!= bpp
|| cur
.c_class
!= defaultVisualInfo
->c_class
) {
752 // Check if visual is compatible to GL requests.
753 if (fnConfigMatches(LOCAL_GLX_USE_GL
, 1) &&
754 fnConfigMatches(LOCAL_GLX_DOUBLEBUFFER
, 1) &&
755 fnConfigMatches(LOCAL_GLX_RED_SIZE
, 8) &&
756 fnConfigMatches(LOCAL_GLX_GREEN_SIZE
, 8) &&
757 fnConfigMatches(LOCAL_GLX_BLUE_SIZE
, 8) &&
758 fnConfigMatches(LOCAL_GLX_ALPHA_SIZE
, 8)) {
759 *out_visualId
= cur
.visualid
;
767 bool GLContextGLX::FindFBConfigForWindow(
768 Display
* display
, int screen
, Window window
,
769 GLXFBConfig
* const out_config
, int* const out_visid
, bool aWebRender
) {
770 // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so
771 // we could probably do this first and replace the glXGetFBConfigs
772 // with glXChooseConfigs. Docs are sparklingly clear as always.
773 XWindowAttributes windowAttrs
;
774 if (!XGetWindowAttributes(display
, window
, &windowAttrs
)) {
775 NS_WARNING("[GLX] XGetWindowAttributes() failed");
779 GLXFBConfig
* cfgs
= nullptr;
780 const auto freeConfigList
= MakeScopeExit([&]() {
786 const int webrenderAttribs
[] = {LOCAL_GLX_ALPHA_SIZE
,
787 windowAttrs
.depth
== 32 ? 8 : 0,
788 LOCAL_GLX_DOUBLEBUFFER
, X11True
, 0};
791 cfgs
= sGLXLibrary
.fChooseFBConfig(display
, screen
, webrenderAttribs
,
794 cfgs
= sGLXLibrary
.fGetFBConfigs(display
, screen
, &numConfigs
);
798 NS_WARNING("[GLX] glXGetFBConfigs() failed");
801 NS_ASSERTION(numConfigs
> 0, "No FBConfigs found!");
803 const VisualID windowVisualID
= XVisualIDFromVisual(windowAttrs
.visual
);
805 printf("[GLX] window %lx has VisualID 0x%lx\n", window
, windowVisualID
);
808 for (int i
= 0; i
< numConfigs
; i
++) {
810 sGLXLibrary
.fGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_VISUAL_ID
,
813 // WebRender compatible GLX visual is configured
814 // at nsWindow::Create() by GLContextGLX::FindVisual(),
815 // just reuse it here.
816 if (windowVisualID
== static_cast<VisualID
>(visid
)) {
817 *out_config
= cfgs
[i
];
824 // We don't have a frame buffer visual which matches the GLX visual
825 // from GLContextGLX::FindVisual(). Let's try to find a near one and hope
826 // we're not on NVIDIA (Bug 1478454) as it causes X11 BadMatch error there.
827 for (int i
= 0; i
< numConfigs
; i
++) {
829 sGLXLibrary
.fGetFBConfigAttrib(display
, cfgs
[i
], LOCAL_GLX_VISUAL_ID
,
834 FindVisualAndDepth(display
, visid
, &visual
, &depth
);
835 if (depth
== windowAttrs
.depth
&&
836 AreCompatibleVisuals(windowAttrs
.visual
, visual
)) {
837 *out_config
= cfgs
[i
];
844 NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual");
848 static already_AddRefed
<GLContextGLX
> CreateOffscreenPixmapContext(
849 const GLContextCreateDesc
& desc
, const IntSize
& size
,
850 nsACString
* const out_failureId
) {
851 GLXLibrary
* glx
= &sGLXLibrary
;
852 auto display
= glx
->GetDisplay();
854 if (!display
|| !glx
->EnsureInitialized(*display
)) return nullptr;
856 int screen
= DefaultScreen(display
->get());
860 if (!ChooseConfig(glx
, *display
, screen
, &config
, &visid
)) {
861 NS_WARNING("Failed to find a compatible config.");
867 FindVisualAndDepth(*display
, visid
, &visual
, &depth
);
869 gfx::IntSize
dummySize(16, 16);
870 const auto drawable
=
871 XCreatePixmap(*display
, DefaultRootWindow(display
->get()),
872 dummySize
.width
, dummySize
.height
, depth
);
877 // Handle slightly different signature between glXCreatePixmap and
878 // its pre-GLX-1.3 extension equivalent (though given the ABI, we
879 // might not need to).
880 const auto pixmap
= glx
->fCreatePixmap(*display
, config
, drawable
, nullptr);
882 XFreePixmap(*display
, drawable
);
886 auto fullDesc
= GLContextDesc
{desc
};
887 fullDesc
.isOffscreen
= true;
888 return GLContextGLX::CreateGLContext(fullDesc
, display
, pixmap
, config
,
893 already_AddRefed
<GLContext
> GLContextProviderGLX::CreateHeadless(
894 const GLContextCreateDesc
& desc
, nsACString
* const out_failureId
) {
895 IntSize dummySize
= IntSize(16, 16);
896 return CreateOffscreenPixmapContext(desc
, dummySize
, out_failureId
);
900 GLContext
* GLContextProviderGLX::GetGlobalContext() {
901 // Context sharing not supported.
906 void GLContextProviderGLX::Shutdown() {}
908 } // namespace mozilla::gl