already_AddRefed<GLContextGLX>
GLContextGLX::CreateGLContext(
                  const SurfaceCaps& caps,
                  GLContextGLX* shareContext,
                  bool isOffscreen,
                  Display* display,
                  GLXDrawable drawable,
                  GLXFBConfig cfg,
                  bool deleteDrawable,
                  gfxXlibSurface* pixmap)
{
    GLXLibrary& glx = sGLXLibrary;

    int db = 0;
    int err = glx.xGetFBConfigAttrib(display, cfg,
                                      LOCAL_GLX_DOUBLEBUFFER, &db);
    if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
#ifdef DEBUG
        if (DebugMode()) {
            printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
        }
#endif
    }

    GLXContext context;
    nsRefPtr<GLContextGLX> glContext;
    bool error;

    ScopedXErrorHandler xErrorHandler;

TRY_AGAIN_NO_SHARING:

    error = false;

    GLXContext glxContext = shareContext ? shareContext->mContext : nullptr;
    if (glx.HasRobustness()) {
        int attrib_list[] = {
            LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
            LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB,
            0,
        };

        context = glx.xCreateContextAttribs(
            display,
            cfg,
            glxContext,
            True,
            attrib_list);
    } else {
        context = glx.xCreateNewContext(
            display,
            cfg,
            LOCAL_GLX_RGBA_TYPE,
            glxContext,
            True);
    }

    if (context) {
        glContext = new GLContextGLX(caps,
                                      shareContext,
                                      isOffscreen,
                                      display,
                                      drawable,
                                      context,
                                      deleteDrawable,
                                      db,
                                      pixmap);
        if (!glContext->Init())
            error = true;
    } else {
        error = true;
    }

    error |= xErrorHandler.SyncAndGetError(display);

    if (error) {
        if (shareContext) {
            shareContext = nullptr;
            goto TRY_AGAIN_NO_SHARING;
        }

        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
    }

    return glContext.forget();
}
already_AddRefed<GLContextGLX>
GLContextGLX::CreateGLContext(CreateContextFlags flags, const SurfaceCaps& caps,
                              GLContextGLX* shareContext, bool isOffscreen,
                              Display* display, GLXDrawable drawable, GLXFBConfig cfg,
                              bool deleteDrawable, gfxXlibSurface* pixmap,
                              ContextProfile profile)
{
    GLXLibrary& glx = sGLXLibrary;

    int db = 0;
    int err = glx.xGetFBConfigAttrib(display, cfg,
                                      LOCAL_GLX_DOUBLEBUFFER, &db);
    if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
        if (ShouldSpew()) {
            printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
        }
    }

    GLXContext context;
    RefPtr<GLContextGLX> glContext;
    bool error;

    ScopedXErrorHandler xErrorHandler;

TRY_AGAIN_NO_SHARING:

    error = false;

    GLXContext glxContext = shareContext ? shareContext->mContext : nullptr;
    if (glx.HasCreateContextAttribs()) {
        AutoTArray<int, 11> attrib_list;
        if (glx.HasRobustness()) {
            int robust_attribs[] = {
                LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
                LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB,
            };
            attrib_list.AppendElements(robust_attribs, MOZ_ARRAY_LENGTH(robust_attribs));
        }
        if (profile == ContextProfile::OpenGLCore) {
            int core_attribs[] = {
                LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
                LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB, 2,
                LOCAL_GLX_CONTEXT_FLAGS_ARB, LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
            };
            attrib_list.AppendElements(core_attribs, MOZ_ARRAY_LENGTH(core_attribs));
        };
        attrib_list.AppendElement(0);

        context = glx.xCreateContextAttribs(
            display,
            cfg,
            glxContext,
            True,
            attrib_list.Elements());
    } else {
        context = glx.xCreateNewContext(
            display,
            cfg,
            LOCAL_GLX_RGBA_TYPE,
            glxContext,
            True);
    }

    if (context) {
        glContext = new GLContextGLX(flags, caps, shareContext, isOffscreen, display,
                                     drawable, context, deleteDrawable, db, pixmap,
                                     profile);
        if (!glContext->Init())
            error = true;
    } else {
        error = true;
    }

    error |= xErrorHandler.SyncAndGetError(display);

    if (error) {
        if (shareContext) {
            shareContext = nullptr;
            goto TRY_AGAIN_NO_SHARING;
        }

        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
    }

    return glContext.forget();
}
static already_AddRefed<GLContextGLX>
CreateOffscreenPixmapContext(const gfxIntSize& size)
{
    GLXLibrary& glx = sGLXLibrary;
    if (!glx.EnsureInitialized()) {
        return nullptr;
    }

    Display *display = DefaultXDisplay();
    int xscreen = DefaultScreen(display);

    int attribs[] = {
        LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
        LOCAL_GLX_X_RENDERABLE, True,
        0
    };
    int numConfigs = 0;

    ScopedXFree<GLXFBConfig> cfgs;
    cfgs = glx.xChooseFBConfig(display,
                               xscreen,
                               attribs,
                               &numConfigs);
    if (!cfgs) {
        return nullptr;
    }

    MOZ_ASSERT(numConfigs > 0,
               "glXChooseFBConfig() failed to match our requested format and "
               "violated its spec!");

    int visid = None;
    int chosenIndex = 0;

    for (int i = 0; i < numConfigs; ++i) {
        int dtype;

        if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_DRAWABLE_TYPE, &dtype) != Success
            || !(dtype & LOCAL_GLX_PIXMAP_BIT))
        {
            continue;
        }
        if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid) != Success
            || visid == 0)
        {
            continue;
        }

        chosenIndex = i;
        break;
    }

    if (!visid) {
        NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
        return nullptr;
    }

    Visual *visual;
    int depth;
    FindVisualAndDepth(display, visid, &visual, &depth);
    ScopedXErrorHandler xErrorHandler;
    GLXPixmap glxpixmap = 0;
    bool error = false;

    gfxIntSize dummySize(16, 16);
    nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
                                                               visual,
                                                               dummySize);
    if (xsurface->CairoStatus() != 0) {
        error = true;
        goto DONE_CREATING_PIXMAP;
    }

    // Handle slightly different signature between glXCreatePixmap and
    // its pre-GLX-1.3 extension equivalent (though given the ABI, we
    // might not need to).
    if (glx.GLXVersionCheck(1, 3)) {
        glxpixmap = glx.xCreatePixmap(display,
                                          cfgs[chosenIndex],
                                          xsurface->XDrawable(),
                                          nullptr);
    } else {
        glxpixmap = glx.xCreateGLXPixmapWithConfig(display,
                                                       cfgs[chosenIndex],
                                                       xsurface->
                                                       XDrawable());
    }
    if (glxpixmap == 0) {
        error = true;
    }

DONE_CREATING_PIXMAP:

    nsRefPtr<GLContextGLX> glContext;
    bool serverError = xErrorHandler.SyncAndGetError(display);

    if (!error && // earlier recorded error
        !serverError)
    {
        // We might have an alpha channel, but it doesn't matter.
        SurfaceCaps dummyCaps = SurfaceCaps::Any();
        GLContextGLX* shareContext = GetGlobalContextGLX();

        glContext = GLContextGLX::CreateGLContext(dummyCaps,
                                                  shareContext,
                                                  true,
                                                  display,
                                                  glxpixmap,
                                                  cfgs[chosenIndex],
                                                  true,
                                                  xsurface);
    }

    return glContext.forget();
}
static already_AddRefed<GLContextGLX>
CreateOffscreenPixmapContext(CreateContextFlags flags, const IntSize& size,
                             const SurfaceCaps& minCaps, nsACString* const out_failureId,
                             ContextProfile profile = ContextProfile::OpenGLCompatibility)
{
    GLXLibrary* glx = &sGLXLibrary;
    if (!glx->EnsureInitialized())
        return nullptr;

    Display* display = DefaultXDisplay();
    int screen = DefaultScreen(display);

    ScopedXFree<GLXFBConfig> scopedConfigArr;
    GLXFBConfig config;
    int visid;
    if (!ChooseConfig(glx, display, screen, minCaps, &scopedConfigArr, &config, &visid)) {
        NS_WARNING("Failed to find a compatible config.");
        return nullptr;
    }

    Visual* visual;
    int depth;
    FindVisualAndDepth(display, visid, &visual, &depth);

    ScopedXErrorHandler xErrorHandler;
    bool error = false;
    // Must be declared before goto:
    Drawable drawable;
    GLXPixmap pixmap;

    gfx::IntSize dummySize(16, 16);
    RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
                                                            visual,
                                                            dummySize);
    if (surface->CairoStatus() != 0) {
        error = true;
        goto DONE_CREATING_PIXMAP;
    }

    // Handle slightly different signature between glXCreatePixmap and
    // its pre-GLX-1.3 extension equivalent (though given the ABI, we
    // might not need to).
    drawable = surface->XDrawable();
    if (glx->GLXVersionCheck(1, 3)) {
        pixmap = glx->xCreatePixmap(display, config, drawable, nullptr);
    } else {
        pixmap = glx->xCreateGLXPixmapWithConfig(display, config, drawable);
    }

    if (pixmap == 0) {
        error = true;
    }

DONE_CREATING_PIXMAP:

    bool serverError = xErrorHandler.SyncAndGetError(display);
    if (error || serverError)
        return nullptr;

    GLContextGLX* shareContext = GetGlobalContextGLX();
    return GLContextGLX::CreateGLContext(flags, minCaps, shareContext, true, display,
                                         pixmap, config, true, surface, profile);
}