already_AddRefed<GLContext> GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget) { if (!sGLXLibrary.EnsureInitialized()) { return nullptr; } // 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. Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY); if (!display) { NS_ERROR("X Display required for GLX Context provider"); return nullptr; } int xscreen = DefaultScreen(display); Window window = GET_NATIVE_WINDOW(aWidget); int numConfigs; ScopedXFree<GLXFBConfig> cfgs; if (sGLXLibrary.IsATI() || !sGLXLibrary.GLXVersionCheck(1, 3)) { const int attribs[] = { LOCAL_GLX_DOUBLEBUFFER, False, 0 }; cfgs = sGLXLibrary.xChooseFBConfig(display, xscreen, attribs, &numConfigs); } else { cfgs = sGLXLibrary.xGetFBConfigs(display, xscreen, &numConfigs); } if (!cfgs) { NS_WARNING("[GLX] glXGetFBConfigs() failed"); return nullptr; } 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. XWindowAttributes widgetAttrs; if (!XGetWindowAttributes(display, window, &widgetAttrs)) { NS_WARNING("[GLX] XGetWindowAttributes() failed"); return nullptr; } const VisualID widgetVisualID = XVisualIDFromVisual(widgetAttrs.visual); #ifdef DEBUG printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID); #endif int matchIndex = -1; for (int i = 0; i < numConfigs; i++) { int visid = None; sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid); if (!visid) { continue; } if (sGLXLibrary.IsATI()) { int depth; Visual *visual; FindVisualAndDepth(display, visid, &visual, &depth); if (depth == widgetAttrs.depth && AreCompatibleVisuals(widgetAttrs.visual, visual)) { matchIndex = i; break; } } else { if (widgetVisualID == static_cast<VisualID>(visid)) { matchIndex = i; break; } } } if (matchIndex == -1) { NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual"); return nullptr; } GLContextGLX *shareContext = GetGlobalContextGLX(); SurfaceCaps caps = SurfaceCaps::Any(); nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(caps, shareContext, false, display, window, cfgs[matchIndex], false); return glContext.forget(); }
GLXPixmap GLXLibrary::CreatePixmap(gfxASurface* aSurface) { if (!SupportsTextureFromPixmap(aSurface)) { return None; } gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface); const XRenderPictFormat *format = xs->XRenderFormat(); if (!format || format->type != PictTypeDirect) { return None; } const XRenderDirectFormat& direct = format->direct; int alphaSize = FloorLog2(direct.alphaMask + 1); NS_ASSERTION((1 << alphaSize) - 1 == direct.alphaMask, "Unexpected render format with non-adjacent alpha bits"); int attribs[] = { 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, None }; int numConfigs = 0; Display *display = xs->XDisplay(); int xscreen = DefaultScreen(display); ScopedXFree<GLXFBConfig> cfgs(xChooseFBConfig(display, xscreen, attribs, &numConfigs)); // Find an fbconfig that matches the pixel format used on the Pixmap. int matchIndex = -1; unsigned long redMask = static_cast<unsigned long>(direct.redMask) << direct.red; unsigned long greenMask = static_cast<unsigned long>(direct.greenMask) << direct.green; unsigned long blueMask = static_cast<unsigned long>(direct.blueMask) << direct.blue; // This is true if the Pixmap has bits for alpha or unused bits. bool haveNonColorBits = ~(redMask | greenMask | blueMask) != -1UL << format->depth; for (int i = 0; i < numConfigs; i++) { int id = None; sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &id); Visual *visual; int depth; 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 NVIDIA if (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. int size = 0; sGLXLibrary.xGetFBConfigAttrib(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_WARN_IF_FALSE(format->depth == 8, "[GLX] Couldn't find a FBConfig matching Pixmap format"); return None; } int pixmapAttribs[] = { 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), None}; GLXPixmap glxpixmap = xCreatePixmap(display, cfgs[matchIndex], xs->XDrawable(), pixmapAttribs); return glxpixmap; }
static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext(const gfxIntSize& aSize, const ContextFormat& aFormat, PRBool aShare) { if (!sGLXLibrary.EnsureInitialized()) { return nsnull; } Display *display = DefaultXDisplay(); int xscreen = DefaultScreen(display); int attribs[] = { GLX_DOUBLEBUFFER, False, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, GLX_X_RENDERABLE, True, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_ALPHA_SIZE, 0, GLX_DEPTH_SIZE, 0, 0 }; int numConfigs = 0; ScopedXFree<GLXFBConfig> cfgs; cfgs = sGLXLibrary.xChooseFBConfig(display, xscreen, attribs, &numConfigs); if (!cfgs) { return nsnull; } NS_ASSERTION(numConfigs > 0, "glXChooseFBConfig() failed to match our requested format and violated its spec (!)"); ScopedXFree<XVisualInfo> vinfo; int chosenIndex; for (int i = 0; i < numConfigs; ++i) { int dtype, visid; if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success || !(dtype & GLX_PIXMAP_BIT)) { continue; } if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success || visid == 0) { continue; } vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]); if (vinfo) { chosenIndex = i; break; } } if (!vinfo) { NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!"); return nsnull; } nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), vinfo->visual, gfxIntSize(16, 16)); if (xsurface->CairoStatus() != 0) { return nsnull; } GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display, cfgs[chosenIndex], xsurface->XDrawable(), NULL); if (glxpixmap == 0) { return nsnull; } GLContextGLX *shareContext = aShare ? GetGlobalContextGLX() : nsnull; nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(aFormat, display, glxpixmap, cfgs[chosenIndex], vinfo, shareContext, PR_TRUE, xsurface); return glContext.forget(); }
bool GLContextGLX::FindFBConfigForWindow(Display* display, int screen, Window window, ScopedXFree<GLXFBConfig>* const out_scopedConfigArr, GLXFBConfig* const out_config, int* const out_visid) { ScopedXFree<GLXFBConfig>& cfgs = *out_scopedConfigArr; int numConfigs; if (sGLXLibrary.IsATI() || !sGLXLibrary.GLXVersionCheck(1, 3)) { const int attribs[] = { LOCAL_GLX_DOUBLEBUFFER, False, 0 }; cfgs = sGLXLibrary.xChooseFBConfig(display, screen, attribs, &numConfigs); } else { cfgs = sGLXLibrary.xGetFBConfigs(display, screen, &numConfigs); } if (!cfgs) { NS_WARNING("[GLX] glXGetFBConfigs() failed"); return false; } 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. XWindowAttributes windowAttrs; if (!XGetWindowAttributes(display, window, &windowAttrs)) { NS_WARNING("[GLX] XGetWindowAttributes() failed"); return false; } const VisualID windowVisualID = XVisualIDFromVisual(windowAttrs.visual); #ifdef DEBUG printf("[GLX] window %lx has VisualID 0x%lx\n", window, windowVisualID); #endif for (int i = 0; i < numConfigs; i++) { int visid = None; sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid); if (!visid) { continue; } if (sGLXLibrary.IsATI()) { int depth; Visual* visual; FindVisualAndDepth(display, visid, &visual, &depth); if (depth == windowAttrs.depth && AreCompatibleVisuals(windowAttrs.visual, visual)) { *out_config = cfgs[i]; *out_visid = visid; return true; } } else { if (windowVisualID == static_cast<VisualID>(visid)) { *out_config = cfgs[i]; *out_visid = visid; return true; } } } NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual"); return false; }
static already_AddRefed<GLContextGLX> CreateGLContext(const ContextFormat& format, Display *display, GLXDrawable drawable, GLXFBConfig cfg, XVisualInfo *vinfo, GLContextGLX *shareContext, PRBool deleteDrawable, gfxXlibSurface *pixmap = nsnull) { int db = 0, err; err = sGLXLibrary.xGetFBConfigAttrib(display, cfg, GLX_DOUBLEBUFFER, &db); if (GLX_BAD_ATTRIBUTE != err) { #ifdef DEBUG printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not "); #endif } ctxErrorOccurred = false; int (*oldHandler)(Display *, XErrorEvent *); GLXContext context; TRY_AGAIN_NO_SHARING: oldHandler = XSetErrorHandler(&ctxErrorHandler); if (gGLXVersion >= 0x0103) { context = sGLXLibrary.xCreateNewContext(display, cfg, GLX_RGBA_TYPE, shareContext ? shareContext->mContext : NULL, True); } else { context = sGLXLibrary.xCreateContext(display, vinfo, shareContext ? shareContext->mContext : NULL, True); } XSync(display, False); XSetErrorHandler(oldHandler); if (!context || ctxErrorOccurred) { if (shareContext) { shareContext = nsnull; goto TRY_AGAIN_NO_SHARING; } NS_WARNING("Failed to create GLXContext!"); return nsnull; } nsRefPtr<GLContextGLX> glContext(new GLContextGLX(format, shareContext, display, drawable, context, deleteDrawable, db, pixmap)); if (!glContext->Init()) { return nsnull; } return glContext.forget(); }