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;
}
예제 #3
0
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();
}
예제 #4
0
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;
}
예제 #5
0
    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();
    }