/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifdef MOZ_WIDGET_GTK#include<gdk/gdk.h>#include<gdk/gdkx.h>#define GET_NATIVE_WINDOW(aWidget) GDK_WINDOW_XID((GdkWindow*) aWidget->GetNativeData(NS_NATIVE_WINDOW))#endif#include<X11/Xlib.h>#include<X11/Xutil.h>#include"X11UndefineNone.h"#include"mozilla/MathAlgorithms.h"#include"mozilla/StaticPtr.h"#include"mozilla/layers/CompositorOptions.h"#include"mozilla/widget/CompositorWidget.h"#include"mozilla/widget/X11CompositorWidget.h"#include"mozilla/Unused.h"#include"prenv.h"#include"GLContextProvider.h"#include"GLLibraryLoader.h"#include"nsDebug.h"#include"nsIWidget.h"#include"GLXLibrary.h"#include"gfxXlibSurface.h"#include"gfxContext.h"#include"gfxEnv.h"#include"gfxPlatform.h"#include"GLContextGLX.h"#include"gfxUtils.h"#include"gfx2DGlue.h"#include"GLScreenBuffer.h"#include"gfxPrefs.h"#include"gfxCrashReporterUtils.h"#ifdef MOZ_WIDGET_GTK#include"gfxPlatformGtk.h"#endifnamespacemozilla{namespacegl{usingnamespacemozilla::gfx;usingnamespacemozilla::widget;GLXLibrarysGLXLibrary;staticinlineboolHasExtension(constchar*aExtensions,constchar*aRequiredExtension){returnGLContext::ListHasExtension(reinterpret_cast<constGLubyte*>(aExtensions),aRequiredExtension);}boolGLXLibrary::EnsureInitialized(){if(mInitialized){returntrue;}// Don't repeatedly try to initialize.if(mTriedInitializing){returnfalse;}mTriedInitializing=true;// Force enabling s3 texture compression. (Bug 774134)PR_SetEnv("force_s3tc_enable=true");if(!mOGLLibrary){constchar*libGLfilename=nullptr;boolforceFeatureReport=false;// see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1// because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls,// which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225#ifdef __OpenBSD__libGLfilename="libGL.so";#elselibGLfilename="libGL.so.1";#endifScopedGfxFeatureReporterreporter(libGLfilename,forceFeatureReport);mOGLLibrary=PR_LoadLibrary(libGLfilename);if(!mOGLLibrary){NS_WARNING("Couldn't load OpenGL shared library.");returnfalse;}reporter.SetSuccessful();}if(gfxEnv::GlxDebug()){mDebug=true;}#define SYMBOL(X) { (PRFuncPtr*)&mSymbols.f##X, { "glX" #X, nullptr } }#define END_OF_SYMBOLS { nullptr, { nullptr } }constGLLibraryLoader::SymLoadStructsymbols[]={/* functions that were in GLX 1.0 */SYMBOL(DestroyContext),SYMBOL(MakeCurrent),SYMBOL(SwapBuffers),SYMBOL(QueryVersion),SYMBOL(GetCurrentContext),SYMBOL(WaitGL),SYMBOL(WaitX),/* functions introduced in GLX 1.1 */SYMBOL(QueryExtensionsString),SYMBOL(GetClientString),SYMBOL(QueryServerString),/* functions introduced in GLX 1.3 */SYMBOL(ChooseFBConfig),SYMBOL(GetFBConfigAttrib),SYMBOL(GetFBConfigs),SYMBOL(CreatePixmap),SYMBOL(DestroyPixmap),SYMBOL(CreateNewContext),// Core in GLX 1.4, ARB extension before.{(PRFuncPtr*)&mSymbols.fGetProcAddress,{"glXGetProcAddress","glXGetProcAddressARB",nullptr}},END_OF_SYMBOLS};if(!GLLibraryLoader::LoadSymbols(mOGLLibrary,symbols)){NS_WARNING("Couldn't load required GLX symbols.");returnfalse;}Display*display=DefaultXDisplay();intscreen=DefaultScreen(display);{intmajor,minor;if(!fQueryVersion(display,&major,&minor)||major!=1||minor<3){NS_ERROR("GLX version older than 1.3. (released in 1998)");returnfalse;}}constGLLibraryLoader::SymLoadStructsymbols_texturefrompixmap[]={SYMBOL(BindTexImageEXT),SYMBOL(ReleaseTexImageEXT),END_OF_SYMBOLS};constGLLibraryLoader::SymLoadStructsymbols_createcontext[]={SYMBOL(CreateContextAttribsARB),END_OF_SYMBOLS};constGLLibraryLoader::SymLoadStructsymbols_videosync[]={SYMBOL(GetVideoSyncSGI),SYMBOL(WaitVideoSyncSGI),END_OF_SYMBOLS};constGLLibraryLoader::SymLoadStructsymbols_swapcontrol[]={SYMBOL(SwapIntervalEXT),END_OF_SYMBOLS};constautolookupFunction=(GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress;constautofnLoadSymbols=[&](constGLLibraryLoader::SymLoadStruct*symbols){if(GLLibraryLoader::LoadSymbols(mOGLLibrary,symbols,lookupFunction))returntrue;GLLibraryLoader::ClearSymbols(symbols);returnfalse;};constchar*clientVendor=fGetClientString(display,LOCAL_GLX_VENDOR);constchar*serverVendor=fQueryServerString(display,screen,LOCAL_GLX_VENDOR);constchar*extensionsStr=fQueryExtensionsString(display,screen);if(HasExtension(extensionsStr,"GLX_EXT_texture_from_pixmap")&&fnLoadSymbols(symbols_texturefrompixmap)){mUseTextureFromPixmap=gfxPrefs::UseGLXTextureFromPixmap();}else{mUseTextureFromPixmap=false;NS_WARNING("Texture from pixmap disabled");}if(HasExtension(extensionsStr,"GLX_ARB_create_context")&&HasExtension(extensionsStr,"GLX_ARB_create_context_profile")&&fnLoadSymbols(symbols_createcontext)){mHasCreateContextAttribs=true;}if(HasExtension(extensionsStr,"GLX_ARB_create_context_robustness")){mHasRobustness=true;}if(HasExtension(extensionsStr,"GLX_SGI_video_sync")&&fnLoadSymbols(symbols_videosync)){mHasVideoSync=true;}if(!HasExtension(extensionsStr,"GLX_EXT_swap_control")||!fnLoadSymbols(symbols_swapcontrol)){NS_WARNING("GLX_swap_control unsupported, ASAP mode may still block on buffer swaps.");}mIsATI=serverVendor&&DoesStringMatch(serverVendor,"ATI");mIsNVIDIA=serverVendor&&DoesStringMatch(serverVendor,"NVIDIA Corporation");mClientIsMesa=clientVendor&&DoesStringMatch(clientVendor,"Mesa");mInitialized=true;returntrue;}boolGLXLibrary::SupportsTextureFromPixmap(gfxASurface*aSurface){if(!EnsureInitialized()){returnfalse;}if(aSurface->GetType()!=gfxSurfaceType::Xlib||!mUseTextureFromPixmap){returnfalse;}returntrue;}boolGLXLibrary::SupportsVideoSync(){if(!EnsureInitialized()){returnfalse;}returnmHasVideoSync;}GLXPixmapGLXLibrary::CreatePixmap(gfxASurface*aSurface){if(!SupportsTextureFromPixmap(aSurface)){returnX11None;}gfxXlibSurface*xs=static_cast<gfxXlibSurface*>(aSurface);constXRenderPictFormat*format=xs->XRenderFormat();if(!format||format->type!=PictTypeDirect){returnX11None;}constXRenderDirectFormat&direct=format->direct;intalphaSize=FloorLog2(direct.alphaMask+1);NS_ASSERTION((1<<alphaSize)-1==direct.alphaMask,"Unexpected render format with non-adjacent alpha bits");intattribs[]={LOCAL_GLX_DOUBLEBUFFER,False,LOCAL_GLX_DRAWABLE_TYPE,LOCAL_GLX_PIXMAP_BIT,LOCAL_GLX_ALPHA_SIZE,alphaSize,(alphaSize?LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT:LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT),True,LOCAL_GLX_RENDER_TYPE,LOCAL_GLX_RGBA_BIT,X11None};intnumConfigs=0;Display*display=xs->XDisplay();intxscreen=DefaultScreen(display);ScopedXFree<GLXFBConfig>cfgs(fChooseFBConfig(display,xscreen,attribs,&numConfigs));// Find an fbconfig that matches the pixel format used on the Pixmap.intmatchIndex=-1;unsignedlongredMask=static_cast<unsignedlong>(direct.redMask)<<direct.red;unsignedlonggreenMask=static_cast<unsignedlong>(direct.greenMask)<<direct.green;unsignedlongblueMask=static_cast<unsignedlong>(direct.blueMask)<<direct.blue;// This is true if the Pixmap has bits for alpha or unused bits.boolhaveNonColorBits=~(redMask|greenMask|blueMask)!=-1UL<<format->depth;for(inti=0;i<numConfigs;i++){intid=X11None;sGLXLibrary.fGetFBConfigAttrib(display,cfgs[i],LOCAL_GLX_VISUAL_ID,&id);Visual*visual;intdepth;FindVisualAndDepth(display,id,&visual,&depth);if(!visual||visual->c_class!=TrueColor||visual->red_mask!=redMask||visual->green_mask!=greenMask||visual->blue_mask!=blueMask){continue;}// Historically Xlib Visuals did not try to represent an alpha channel// and there was no means to use an alpha channel on a Pixmap. The// Xlib Visual from the fbconfig was not intended to have any// information about alpha bits.//// Since then, RENDER has added formats for 32 bit depth Pixmaps.// Some of these formats have bits for alpha and some have unused// bits.//// Then the Composite extension added a 32 bit depth Visual intended// for Windows with an alpha channel, so bits not in the visual color// masks were expected to be treated as alpha bits.//// Usually GLX counts only color bits in the Visual depth, but the// depth of Composite's ARGB Visual includes alpha bits. However,// bits not in the color masks are not necessarily alpha bits because// sometimes (NVIDIA) 32 bit Visuals are added for fbconfigs with 32// bit BUFFER_SIZE but zero alpha bits and 24 color bits (NVIDIA// again).//// This checks that the depth matches in one of the two ways.// NVIDIA now forces format->depth == depth so only the first way// is checked for NVIDIAif(depth!=format->depth&&(mIsNVIDIA||depth!=format->depth-alphaSize)){continue;}// If all bits of the Pixmap are color bits and the Pixmap depth// matches the depth of the fbconfig visual, then we can assume that// the driver will do whatever is necessary to ensure that any// GLXPixmap alpha bits are treated as set. We can skip the// ALPHA_SIZE check in this situation. We need to skip this check for// situations (ATI) where there are no fbconfigs without alpha bits.//// glXChooseFBConfig should prefer configs with smaller// LOCAL_GLX_BUFFER_SIZE, so we should still get zero alpha bits if// available, except perhaps with NVIDIA drivers where buffer size is// not the specified sum of the component sizes.if(haveNonColorBits){// There are bits in the Pixmap format that haven't been matched// against the fbconfig visual. These bits could either represent// alpha or be unused, so just check that the number of alpha bits// matches.intsize=0;sGLXLibrary.fGetFBConfigAttrib(display,cfgs[i],LOCAL_GLX_ALPHA_SIZE,&size);if(size!=alphaSize){continue;}}matchIndex=i;break;}if(matchIndex==-1){// GLX can't handle A8 surfaces, so this is not really unexpected. The// caller should deal with this situation.NS_WARNING_ASSERTION(format->depth==8,"[GLX] Couldn't find a FBConfig matching Pixmap format");returnX11None;}intpixmapAttribs[]={LOCAL_GLX_TEXTURE_TARGET_EXT,LOCAL_GLX_TEXTURE_2D_EXT,LOCAL_GLX_TEXTURE_FORMAT_EXT,(alphaSize?LOCAL_GLX_TEXTURE_FORMAT_RGBA_EXT:LOCAL_GLX_TEXTURE_FORMAT_RGB_EXT),X11None};GLXPixmapglxpixmap=fCreatePixmap(display,cfgs[matchIndex],xs->XDrawable(),pixmapAttribs);returnglxpixmap;}voidGLXLibrary::DestroyPixmap(Display*aDisplay,GLXPixmapaPixmap){if(!mUseTextureFromPixmap){return;}fDestroyPixmap(aDisplay,aPixmap);}voidGLXLibrary::BindTexImage(Display*aDisplay,GLXPixmapaPixmap){if(!mUseTextureFromPixmap){return;}// Make sure all X drawing to the surface has finished before binding to a texture.if(mClientIsMesa){// Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a// noop when direct rendering unless the current drawable is a// single-buffer window.FinishX(aDisplay);}else{fWaitX();}fBindTexImage(aDisplay,aPixmap,LOCAL_GLX_FRONT_LEFT_EXT,nullptr);}voidGLXLibrary::ReleaseTexImage(Display*aDisplay,GLXPixmapaPixmap){if(!mUseTextureFromPixmap){return;}fReleaseTexImage(aDisplay,aPixmap,LOCAL_GLX_FRONT_LEFT_EXT);}voidGLXLibrary::UpdateTexImage(Display*aDisplay,GLXPixmapaPixmap){// NVIDIA drivers don't require a rebind of the pixmap in order// to display an updated image, and it's faster not to do it.if(mIsNVIDIA){fWaitX();return;}ReleaseTexImage(aDisplay,aPixmap);BindTexImage(aDisplay,aPixmap);}staticint(*sOldErrorHandler)(Display*,XErrorEvent*);ScopedXErrorHandler::ErrorEventsErrorEvent;staticintGLXErrorHandler(Display*display,XErrorEvent*ev){if(!sErrorEvent.mError.error_code){sErrorEvent.mError=*ev;}return0;}voidGLXLibrary::BeforeGLXCall()const{if(mDebug){sOldErrorHandler=XSetErrorHandler(GLXErrorHandler);}}voidGLXLibrary::AfterGLXCall()const{if(mDebug){FinishX(DefaultXDisplay());if(sErrorEvent.mError.error_code){charbuffer[2048];XGetErrorText(DefaultXDisplay(),sErrorEvent.mError.error_code,buffer,sizeof(buffer));printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %lu",buffer,sErrorEvent.mError.error_code,sErrorEvent.mError.request_code,sErrorEvent.mError.minor_code,sErrorEvent.mError.serial);NS_ABORT();}XSetErrorHandler(sOldErrorHandler);}}already_AddRefed<GLContextGLX>GLContextGLX::CreateGLContext(CreateContextFlagsflags,constSurfaceCaps&caps,boolisOffscreen,Display*display,GLXDrawabledrawable,GLXFBConfigcfg,booldeleteDrawable,gfxXlibSurface*pixmap){GLXLibrary&glx=sGLXLibrary;intdb=0;interr=glx.fGetFBConfigAttrib(display,cfg,LOCAL_GLX_DOUBLEBUFFER,&db);if(LOCAL_GLX_BAD_ATTRIBUTE!=err){if(ShouldSpew()){printf("[GLX] FBConfig is %sdouble-buffered\n",db?"":"not ");}}GLXContextcontext;RefPtr<GLContextGLX>glContext;boolerror;OffMainThreadScopedXErrorHandlerxErrorHandler;do{error=false;if(glx.HasCreateContextAttribs()){AutoTArray<int,11>attrib_list;if(glx.HasRobustness()){constintrobust_attribs[]={LOCAL_GLX_CONTEXT_FLAGS_ARB,LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB,};attrib_list.AppendElements(robust_attribs,MOZ_ARRAY_LENGTH(robust_attribs));}if(!(flags&CreateContextFlags::REQUIRE_COMPAT_PROFILE)){intcore_attribs[]={LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB,3,LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB,2,LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB,LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB,};attrib_list.AppendElements(core_attribs,MOZ_ARRAY_LENGTH(core_attribs));};attrib_list.AppendElement(0);context=glx.fCreateContextAttribs(display,cfg,nullptr,True,attrib_list.Elements());}else{context=glx.fCreateNewContext(display,cfg,LOCAL_GLX_RGBA_TYPE,nullptr,True);}if(context){glContext=newGLContextGLX(flags,caps,isOffscreen,display,drawable,context,deleteDrawable,db,pixmap);if(!glContext->Init())error=true;}else{error=true;}error|=xErrorHandler.SyncAndGetError(display);if(error){NS_WARNING("Failed to create GLXContext!");glContext=nullptr;// note: this must be done while the graceful X error handler is set,// because glxMakeCurrent can give a GLXBadDrawable error}returnglContext.forget();}while(true);}GLContextGLX::~GLContextGLX(){MarkDestroyed();// Wrapped context should not destroy glxContext/Surfaceif(!mOwnsContext){return;}// see bug 659842 comment 76#ifdef DEBUGboolsuccess=#endifmGLX->fMakeCurrent(mDisplay,X11None,nullptr);MOZ_ASSERT(success,"glXMakeCurrent failed to release GL context before we call ""glXDestroyContext!");mGLX->fDestroyContext(mDisplay,mContext);if(mDeleteDrawable){mGLX->fDestroyPixmap(mDisplay,mDrawable);}}boolGLContextGLX::Init(){SetupLookupFunction();if(!InitWithPrefix("gl",true)){returnfalse;}// EXT_framebuffer_object is not supported on Core contexts// so we'll also check for ARB_framebuffer_objectif(!IsExtensionSupported(EXT_framebuffer_object)&&!IsSupported(GLFeature::framebuffer_object))returnfalse;returntrue;}boolGLContextGLX::MakeCurrentImpl(boolaForce){boolsucceeded=true;// With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change.// (This is not the case with other drivers such as NVIDIA).// So avoid calling it more than necessary. Since GLX documentation says that:// "glXGetCurrentContext returns client-side information.// It does not make a round trip to the server."// I assume that it's not worth using our own TLS slot here.if(aForce||mGLX->fGetCurrentContext()!=mContext){if(mGLX->IsMesa()){// Read into the event queue to ensure that Mesa receives a// DRI2InvalidateBuffers event before drawing. See bug 1280653.Unused<<XPending(mDisplay);}succeeded=mGLX->fMakeCurrent(mDisplay,mDrawable,mContext);NS_ASSERTION(succeeded,"Failed to make GL context current!");if(!IsOffscreen()&&mGLX->SupportsSwapControl()){// Many GLX implementations default to blocking until the next// VBlank when calling glXSwapBuffers. We want to run unthrottled// in ASAP mode. See bug 1280744.constboolisASAP=(gfxPrefs::LayoutFrameRate()==0);mGLX->fSwapInterval(mDisplay,mDrawable,isASAP?0:1);}}returnsucceeded;}boolGLContextGLX::IsCurrent(){returnmGLX->fGetCurrentContext()==mContext;}boolGLContextGLX::SetupLookupFunction(){mLookupFunc=(PlatformLookupFunction)sGLXLibrary.GetGetProcAddress();returntrue;}boolGLContextGLX::IsDoubleBuffered()const{returnmDoubleBuffered;}boolGLContextGLX::SwapBuffers(){if(!mDoubleBuffered)returnfalse;mGLX->fSwapBuffers(mDisplay,mDrawable);returntrue;}voidGLContextGLX::GetWSIInfo(nsCString*constout)const{Display*display=DefaultXDisplay();intscreen=DefaultScreen(display);intmajorVersion,minorVersion;sGLXLibrary.fQueryVersion(display,&majorVersion,&minorVersion);out->Append(nsPrintfCString("GLX %u.%u",majorVersion,minorVersion));out->AppendLiteral("\nGLX_VENDOR(client): ");out->Append(sGLXLibrary.fGetClientString(display,LOCAL_GLX_VENDOR));out->AppendLiteral("\nGLX_VENDOR(server): ");out->Append(sGLXLibrary.fQueryServerString(display,screen,LOCAL_GLX_VENDOR));out->AppendLiteral("\nExtensions: ");out->Append(sGLXLibrary.fQueryExtensionsString(display,screen));}boolGLContextGLX::OverrideDrawable(GLXDrawabledrawable){if(Screen())Screen()->AssureBlitted();Boolresult=mGLX->fMakeCurrent(mDisplay,drawable,mContext);returnresult;}boolGLContextGLX::RestoreDrawable(){returnmGLX->fMakeCurrent(mDisplay,mDrawable,mContext);}GLContextGLX::GLContextGLX(CreateContextFlagsflags,constSurfaceCaps&caps,boolisOffscreen,Display*aDisplay,GLXDrawableaDrawable,GLXContextaContext,boolaDeleteDrawable,boolaDoubleBuffered,gfxXlibSurface*aPixmap):GLContext(flags,caps,nullptr,isOffscreen),mContext(aContext),mDisplay(aDisplay),mDrawable(aDrawable),mDeleteDrawable(aDeleteDrawable),mDoubleBuffered(aDoubleBuffered),mGLX(&sGLXLibrary),mPixmap(aPixmap),mOwnsContext(true){}staticboolAreCompatibleVisuals(Visual*one,Visual*two){if(one->c_class!=two->c_class){returnfalse;}if(one->red_mask!=two->red_mask||one->green_mask!=two->green_mask||one->blue_mask!=two->blue_mask){returnfalse;}if(one->bits_per_rgb!=two->bits_per_rgb){returnfalse;}returntrue;}already_AddRefed<GLContext>GLContextProviderGLX::CreateWrappingExisting(void*aContext,void*aSurface){if(!sGLXLibrary.EnsureInitialized()){returnnullptr;}if(aContext&&aSurface){SurfaceCapscaps=SurfaceCaps::Any();RefPtr<GLContextGLX>glContext=newGLContextGLX(CreateContextFlags::NONE,caps,false,// Offscreen(Display*)DefaultXDisplay(),// Display(GLXDrawable)aSurface,(GLXContext)aContext,false,// aDeleteDrawable,true,(gfxXlibSurface*)nullptr);glContext->mOwnsContext=false;returnglContext.forget();}returnnullptr;}already_AddRefed<GLContext>CreateForWidget(Display*aXDisplay,WindowaXWindow,boolaWebRender,boolaForceAccelerated){if(!sGLXLibrary.EnsureInitialized()){returnnullptr;}// Currently, we take whatever Visual the window already has, and// try to create an fbconfig for that visual. This isn't// necessarily what we want in the long run; an fbconfig may not// be available for the existing visual, or if it is, the GL// performance might be suboptimal. But using the existing visual// is a relatively safe intermediate step.if(!aXDisplay){NS_ERROR("X Display required for GLX Context provider");returnnullptr;}intxscreen=DefaultScreen(aXDisplay);ScopedXFree<GLXFBConfig>cfgs;GLXFBConfigconfig;intvisid;if(!GLContextGLX::FindFBConfigForWindow(aXDisplay,xscreen,aXWindow,&cfgs,&config,&visid,aWebRender)){returnnullptr;}CreateContextFlagsflags;if(aWebRender){flags=CreateContextFlags::NONE;// WR needs GL3.2+}else{flags=CreateContextFlags::REQUIRE_COMPAT_PROFILE;}returnGLContextGLX::CreateGLContext(flags,SurfaceCaps::Any(),false,aXDisplay,aXWindow,config,false,nullptr);}already_AddRefed<GLContext>GLContextProviderGLX::CreateForCompositorWidget(CompositorWidget*aCompositorWidget,boolaForceAccelerated){X11CompositorWidget*compWidget=aCompositorWidget->AsX11();MOZ_ASSERT(compWidget);returnCreateForWidget(compWidget->XDisplay(),compWidget->XWindow(),compWidget->GetCompositorOptions().UseWebRender(),aForceAccelerated);}already_AddRefed<GLContext>GLContextProviderGLX::CreateForWindow(nsIWidget*aWidget,boolaWebRender,boolaForceAccelerated){Display*display=(Display*)aWidget->GetNativeData(NS_NATIVE_COMPOSITOR_DISPLAY);Windowwindow=GET_NATIVE_WINDOW(aWidget);returnCreateForWidget(display,window,aWebRender,aForceAccelerated);}staticboolChooseConfig(GLXLibrary*glx,Display*display,intscreen,constSurfaceCaps&minCaps,ScopedXFree<GLXFBConfig>*constout_scopedConfigArr,GLXFBConfig*constout_config,int*constout_visid){ScopedXFree<GLXFBConfig>&scopedConfigArr=*out_scopedConfigArr;if(minCaps.antialias)returnfalse;intattribs[]={LOCAL_GLX_DRAWABLE_TYPE,LOCAL_GLX_PIXMAP_BIT,LOCAL_GLX_X_RENDERABLE,True,LOCAL_GLX_RED_SIZE,8,LOCAL_GLX_GREEN_SIZE,8,LOCAL_GLX_BLUE_SIZE,8,LOCAL_GLX_ALPHA_SIZE,minCaps.alpha?8:0,LOCAL_GLX_DEPTH_SIZE,minCaps.depth?16:0,LOCAL_GLX_STENCIL_SIZE,minCaps.stencil?8:0,0};intnumConfigs=0;scopedConfigArr=glx->fChooseFBConfig(display,screen,attribs,&numConfigs);if(!scopedConfigArr||!numConfigs)returnfalse;// Issues with glxChooseFBConfig selection and sorting:// * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't request// alpha bits, we'll probably get RGBA anyways, since 32 is more than 24.// * DEPTH_SIZE is sorted largest first, including for `0` inputs.// * STENCIL_SIZE is smallest first, but it might return `8` even though we ask for// `0`.// For now, we don't care about these. We *will* care when we do XPixmap sharing.for(inti=0;i<numConfigs;++i){GLXFBConfigcurConfig=scopedConfigArr[i];intvisid;if(glx->fGetFBConfigAttrib(display,curConfig,LOCAL_GLX_VISUAL_ID,&visid)!=Success){continue;}if(!visid)continue;*out_config=curConfig;*out_visid=visid;returntrue;}returnfalse;}boolGLContextGLX::FindFBConfigForWindow(Display*display,intscreen,Windowwindow,ScopedXFree<GLXFBConfig>*constout_scopedConfigArr,GLXFBConfig*constout_config,int*constout_visid,boolaWebRender){ScopedXFree<GLXFBConfig>&cfgs=*out_scopedConfigArr;intnumConfigs;constintwebrenderAttribs[]={LOCAL_GLX_DEPTH_SIZE,24,LOCAL_GLX_DOUBLEBUFFER,True,0};if(aWebRender){cfgs=sGLXLibrary.fChooseFBConfig(display,screen,webrenderAttribs,&numConfigs);}else{cfgs=sGLXLibrary.fGetFBConfigs(display,screen,&numConfigs);}if(!cfgs){NS_WARNING("[GLX] glXGetFBConfigs() failed");returnfalse;}NS_ASSERTION(numConfigs>0,"No FBConfigs found!");// XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so// we could probably do this first and replace the glXGetFBConfigs// with glXChooseConfigs. Docs are sparklingly clear as always.XWindowAttributeswindowAttrs;if(!XGetWindowAttributes(display,window,&windowAttrs)){NS_WARNING("[GLX] XGetWindowAttributes() failed");returnfalse;}constVisualIDwindowVisualID=XVisualIDFromVisual(windowAttrs.visual);#ifdef DEBUGprintf("[GLX] window %lx has VisualID 0x%lx\n",window,windowVisualID);#endifif(aWebRender){for(inti=0;i<numConfigs;i++){intvisid=X11None;sGLXLibrary.fGetFBConfigAttrib(display,cfgs[i],LOCAL_GLX_VISUAL_ID,&visid);if(!visid){continue;}intdepth;Visual*visual;FindVisualAndDepth(display,visid,&visual,&depth);if(depth==windowAttrs.depth&&AreCompatibleVisuals(windowAttrs.visual,visual)){*out_config=cfgs[i];*out_visid=visid;returntrue;}}}else{for(inti=0;i<numConfigs;i++){intvisid=X11None;sGLXLibrary.fGetFBConfigAttrib(display,cfgs[i],LOCAL_GLX_VISUAL_ID,&visid);if(!visid){continue;}if(sGLXLibrary.IsATI()){intdepth;Visual*visual;FindVisualAndDepth(display,visid,&visual,&depth);if(depth==windowAttrs.depth&&AreCompatibleVisuals(windowAttrs.visual,visual)){*out_config=cfgs[i];*out_visid=visid;returntrue;}}else{if(windowVisualID==static_cast<VisualID>(visid)){*out_config=cfgs[i];*out_visid=visid;returntrue;}}}}NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual");returnfalse;}staticalready_AddRefed<GLContextGLX>CreateOffscreenPixmapContext(CreateContextFlagsflags,constIntSize&size,constSurfaceCaps&minCaps,nsACString*constout_failureId){GLXLibrary*glx=&sGLXLibrary;if(!glx->EnsureInitialized())returnnullptr;Display*display=DefaultXDisplay();intscreen=DefaultScreen(display);ScopedXFree<GLXFBConfig>scopedConfigArr;GLXFBConfigconfig;intvisid;if(!ChooseConfig(glx,display,screen,minCaps,&scopedConfigArr,&config,&visid)){NS_WARNING("Failed to find a compatible config.");returnnullptr;}Visual*visual;intdepth;FindVisualAndDepth(display,visid,&visual,&depth);OffMainThreadScopedXErrorHandlerxErrorHandler;boolerror=false;gfx::IntSizedummySize(16,16);RefPtr<gfxXlibSurface>surface=gfxXlibSurface::Create(DefaultScreenOfDisplay(display),visual,dummySize);if(surface->CairoStatus()!=0){mozilla::Unused<<xErrorHandler.SyncAndGetError(display);returnnullptr;}// Handle slightly different signature between glXCreatePixmap and// its pre-GLX-1.3 extension equivalent (though given the ABI, we// might not need to).constautodrawable=surface->XDrawable();constautopixmap=glx->fCreatePixmap(display,config,drawable,nullptr);if(pixmap==0){error=true;}boolserverError=xErrorHandler.SyncAndGetError(display);if(error||serverError)returnnullptr;returnGLContextGLX::CreateGLContext(flags,minCaps,true,display,pixmap,config,true,surface);}/*static*/already_AddRefed<GLContext>GLContextProviderGLX::CreateHeadless(CreateContextFlagsflags,nsACString*constout_failureId){IntSizedummySize=IntSize(16,16);SurfaceCapsdummyCaps=SurfaceCaps::Any();returnCreateOffscreenPixmapContext(flags,dummySize,dummyCaps,out_failureId);}/*static*/already_AddRefed<GLContext>GLContextProviderGLX::CreateOffscreen(constIntSize&size,constSurfaceCaps&minCaps,CreateContextFlagsflags,nsACString*constout_failureId){SurfaceCapsminBackbufferCaps=minCaps;if(minCaps.antialias){minBackbufferCaps.antialias=false;minBackbufferCaps.depth=false;minBackbufferCaps.stencil=false;}RefPtr<GLContext>gl;gl=CreateOffscreenPixmapContext(flags,size,minBackbufferCaps,out_failureId);if(!gl)returnnullptr;if(!gl->InitOffscreen(size,minCaps)){*out_failureId=NS_LITERAL_CSTRING("FEATURE_FAILURE_GLX_INIT");returnnullptr;}returngl.forget();}/*static*/GLContext*GLContextProviderGLX::GetGlobalContext(){// Context sharing not supported.returnnullptr;}/*static*/voidGLContextProviderGLX::Shutdown(){}}/* namespace gl */}/* namespace mozilla */