예제 #1
0
static Bool
glamor_check_instruction_count(int gl_version)
{
    GLint max_native_alu_instructions;

    /* Avoid using glamor if the reported instructions limit is too low,
     * as this would cause glamor to fallback on sw due to large shaders
     * which ends up being unbearably slow.
     */
    if (gl_version < 30) {
        if (!epoxy_has_gl_extension("GL_ARB_fragment_program")) {
            ErrorF("GL_ARB_fragment_program required\n");
            return FALSE;
        }

        glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
                          GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB,
                          &max_native_alu_instructions);
        if (max_native_alu_instructions < GLAMOR_MIN_ALU_INSTRUCTIONS) {
            LogMessage(X_WARNING,
                       "glamor requires at least %d instructions (%d reported)\n",
                       GLAMOR_MIN_ALU_INSTRUCTIONS, max_native_alu_instructions);
            return FALSE;
        }
    }

    return TRUE;
}
예제 #2
0
파일: gskglprofiler.c 프로젝트: GNOME/gtk
static void
gsk_gl_profiler_init (GskGLProfiler *self)
{
  glGenQueries (N_QUERIES, self->gl_queries);

  self->first_frame = TRUE;
  self->has_timer = epoxy_has_gl_extension ("GL_ARB_timer_query");
}
예제 #3
0
static void
xwl_drm_init_egl(struct xwl_screen *xwl_screen)
{
    EGLint major, minor;
    const char *version;

    if (xwl_screen->egl_display)
        return;

    xwl_screen->expecting_event--;

    xwl_screen->gbm = gbm_create_device(xwl_screen->drm_fd);
    if (xwl_screen->gbm == NULL) {
        ErrorF("couldn't get display device\n");
        return;
    }

    xwl_screen->egl_display = eglGetDisplay(xwl_screen->gbm);
    if (xwl_screen->egl_display == EGL_NO_DISPLAY) {
        ErrorF("eglGetDisplay() failed\n");
        return;
    }

    eglBindAPI(EGL_OPENGL_API);
    if (!eglInitialize(xwl_screen->egl_display, &major, &minor)) {
        ErrorF("eglInitialize() failed\n");
        return;
    }

    version = eglQueryString(xwl_screen->egl_display, EGL_VERSION);
    ErrorF("glamor: EGL version %s:\n", version);

    xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display,
                                               NULL, EGL_NO_CONTEXT, NULL);
    if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
        ErrorF("Failed to create EGL context\n");
        return;
    }

    if (!eglMakeCurrent(xwl_screen->egl_display,
                        EGL_NO_SURFACE, EGL_NO_SURFACE,
                        xwl_screen->egl_context)) {
        ErrorF("Failed to make EGL context current\n");
        return;
    }

    if (!epoxy_has_gl_extension("GL_OES_EGL_image")) {
        ErrorF("GL_OES_EGL_image not available\n");
        return;
    }

    return;
}
예제 #4
0
/**
 * Configures GL_ARB_debug_output to give us immediate callbacks when
 * GL errors occur, so that we can log them.
 */
static void
glamor_setup_debug_output(ScreenPtr screen)
{
    if (!epoxy_has_gl_extension("GL_ARB_debug_output"))
        return;

    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
    /* Disable debugging messages other than GL API errors */
    glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL,
                          GL_FALSE);
    glDebugMessageControl(GL_DEBUG_SOURCE_API,
                          GL_DEBUG_TYPE_ERROR,
                          GL_DONT_CARE,
                          0, NULL, GL_TRUE);
    glDebugMessageCallback(glamor_debug_output_callback,
                           screen);

    /* If KHR_debug is present, all debug output is disabled by
     * default on non-debug contexts.
     */
    if (epoxy_has_gl_extension("GL_KHR_debug"))
        glEnable(GL_DEBUG_OUTPUT);
}
예제 #5
0
/** Set up glamor for an already-configured GL context. */
Bool
glamor_init(ScreenPtr screen, unsigned int flags)
{
    glamor_screen_private *glamor_priv;
    int gl_version;
    int max_viewport_size[2];

#ifdef RENDER
    PictureScreenPtr ps = GetPictureScreenIfSet(screen);
#endif
    if (flags & ~GLAMOR_VALID_FLAGS) {
        ErrorF("glamor_init: Invalid flags %x\n", flags);
        return FALSE;
    }
    glamor_priv = calloc(1, sizeof(*glamor_priv));
    if (glamor_priv == NULL)
        return FALSE;

    glamor_priv->flags = flags;

    if (!dixRegisterPrivateKey(&glamor_screen_private_key, PRIVATE_SCREEN, 0)) {
        LogMessage(X_WARNING,
                   "glamor%d: Failed to allocate screen private\n",
                   screen->myNum);
        goto fail;
    }

    glamor_set_screen_private(screen, glamor_priv);

    if (!dixRegisterPrivateKey(&glamor_pixmap_private_key, PRIVATE_PIXMAP, 0)) {
        LogMessage(X_WARNING,
                   "glamor%d: Failed to allocate pixmap private\n",
                   screen->myNum);
        goto fail;
    }

    if (!dixRegisterPrivateKey(&glamor_gc_private_key, PRIVATE_GC,
                               sizeof (glamor_gc_private))) {
        LogMessage(X_WARNING,
                   "glamor%d: Failed to allocate gc private\n",
                   screen->myNum);
        goto fail;
    }

    if (epoxy_is_desktop_gl())
        glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP;
    else
        glamor_priv->gl_flavor = GLAMOR_GL_ES2;

    gl_version = epoxy_gl_version();

    /* Would be nice to have a cleaner test for GLSL 1.30 support,
     * but for now this should suffice
     */
    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && gl_version >= 30)
        glamor_priv->glsl_version = 130;
    else
        glamor_priv->glsl_version = 120;


    /* We'd like to require GL_ARB_map_buffer_range or
     * GL_OES_map_buffer_range, since it offers more information to
     * the driver than plain old glMapBuffer() or glBufferSubData().
     * It's been supported on Mesa on the desktop since 2009 and on
     * GLES2 since October 2012.  It's supported on Apple's iOS
     * drivers for SGX535 and A7, but apparently not on most Android
     * devices (the OES extension spec wasn't released until June
     * 2012).
     *
     * 82% of 0 A.D. players (desktop GL) submitting hardware reports
     * have support for it, with most of the ones lacking it being on
     * Windows with Intel 4-series (G45) graphics or older.
     */
    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
        if (gl_version < 21) {
            ErrorF("Require OpenGL version 2.1 or later.\n");
            goto fail;
        }
    } else {
        if (gl_version < 20) {
            ErrorF("Require Open GLES2.0 or later.\n");
            goto fail;
        }

        if (!epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) {
            ErrorF("GL_EXT_texture_format_BGRA8888 required\n");
            goto fail;
        }
    }

    glamor_priv->has_rw_pbo = FALSE;
    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
        glamor_priv->has_rw_pbo = TRUE;

    glamor_priv->has_khr_debug = epoxy_has_gl_extension("GL_KHR_debug");
    glamor_priv->has_pack_invert =
        epoxy_has_gl_extension("GL_MESA_pack_invert");
    glamor_priv->has_fbo_blit =
        epoxy_has_gl_extension("GL_EXT_framebuffer_blit");
    glamor_priv->has_map_buffer_range =
        epoxy_has_gl_extension("GL_ARB_map_buffer_range");
    glamor_priv->has_buffer_storage =
        epoxy_has_gl_extension("GL_ARB_buffer_storage");
    glamor_priv->has_nv_texture_barrier =
        epoxy_has_gl_extension("GL_NV_texture_barrier");

    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size);
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glamor_priv->max_fbo_size);
    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
    glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[0]);
    glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[1]);
#ifdef MAX_FBO_SIZE
    glamor_priv->max_fbo_size = MAX_FBO_SIZE;
#endif

    glamor_set_debug_level(&glamor_debug_level);

    /* If we are using egl screen, call egl screen init to
     * register correct close screen function. */
    if (flags & GLAMOR_USE_EGL_SCREEN) {
        glamor_egl_screen_init(screen, &glamor_priv->ctx);
    } else {
        if (!glamor_glx_screen_init(&glamor_priv->ctx))
            goto fail;
    }

    glamor_priv->saved_procs.close_screen = screen->CloseScreen;
    screen->CloseScreen = glamor_close_screen;

    glamor_priv->saved_procs.create_screen_resources =
        screen->CreateScreenResources;
    screen->CreateScreenResources = glamor_create_screen_resources;

    if (!glamor_font_init(screen))
        goto fail;

    if (flags & GLAMOR_USE_SCREEN) {
        if (!RegisterBlockAndWakeupHandlers(_glamor_block_handler,
                                            _glamor_wakeup_handler,
                                            glamor_priv)) {
            goto fail;
        }

        glamor_priv->saved_procs.create_gc = screen->CreateGC;
        screen->CreateGC = glamor_create_gc;

        glamor_priv->saved_procs.create_pixmap = screen->CreatePixmap;
        screen->CreatePixmap = glamor_create_pixmap;

        glamor_priv->saved_procs.destroy_pixmap = screen->DestroyPixmap;
        screen->DestroyPixmap = glamor_destroy_pixmap;

        glamor_priv->saved_procs.get_spans = screen->GetSpans;
        screen->GetSpans = glamor_get_spans;

        glamor_priv->saved_procs.get_image = screen->GetImage;
        screen->GetImage = glamor_get_image;

        glamor_priv->saved_procs.change_window_attributes =
            screen->ChangeWindowAttributes;
        screen->ChangeWindowAttributes = glamor_change_window_attributes;

        glamor_priv->saved_procs.copy_window = screen->CopyWindow;
        screen->CopyWindow = glamor_copy_window;

        glamor_priv->saved_procs.bitmap_to_region = screen->BitmapToRegion;
        screen->BitmapToRegion = glamor_bitmap_to_region;
    }
#ifdef RENDER
    if (flags & GLAMOR_USE_PICTURE_SCREEN) {
        glamor_priv->saved_procs.composite = ps->Composite;
        ps->Composite = glamor_composite;

        glamor_priv->saved_procs.trapezoids = ps->Trapezoids;
        ps->Trapezoids = glamor_trapezoids;

        glamor_priv->saved_procs.triangles = ps->Triangles;
        ps->Triangles = glamor_triangles;

        glamor_priv->saved_procs.addtraps = ps->AddTraps;
        ps->AddTraps = glamor_add_traps;

    }

    glamor_priv->saved_procs.composite_rects = ps->CompositeRects;
    ps->CompositeRects = glamor_composite_rectangles;

    glamor_priv->saved_procs.glyphs = ps->Glyphs;
    ps->Glyphs = glamor_glyphs;

    glamor_priv->saved_procs.unrealize_glyph = ps->UnrealizeGlyph;
    ps->UnrealizeGlyph = glamor_glyph_unrealize;

    glamor_priv->saved_procs.create_picture = ps->CreatePicture;
    ps->CreatePicture = glamor_create_picture;

    glamor_priv->saved_procs.destroy_picture = ps->DestroyPicture;
    ps->DestroyPicture = glamor_destroy_picture;
    glamor_init_composite_shaders(screen);
#endif
    glamor_priv->saved_procs.set_window_pixmap = screen->SetWindowPixmap;
    screen->SetWindowPixmap = glamor_set_window_pixmap;

    glamor_init_vbo(screen);
    glamor_init_pixmap_fbo(screen);
#ifdef GLAMOR_TRAPEZOID_SHADER
    glamor_init_trapezoid_shader(screen);
#endif
    glamor_init_finish_access_shaders(screen);
#ifdef GLAMOR_GRADIENT_SHADER
    glamor_init_gradient_shader(screen);
#endif
    glamor_pixmap_init(screen);
    glamor_glyphs_init(screen);
    glamor_sync_init(screen);

    glamor_priv->screen = screen;

    return TRUE;

 fail:
    free(glamor_priv);
    glamor_set_screen_private(screen, NULL);
    return FALSE;
}
예제 #6
0
/** Set up glamor for an already-configured GL context. */
Bool
glamor_init(ScreenPtr screen, unsigned int flags)
{
    glamor_screen_private *glamor_priv;
    int gl_version;
    int glsl_major, glsl_minor;
    int max_viewport_size[2];
    const char *shading_version_string;
    int shading_version_offset;

    PictureScreenPtr ps = GetPictureScreenIfSet(screen);

    if (flags & ~GLAMOR_VALID_FLAGS) {
        ErrorF("glamor_init: Invalid flags %x\n", flags);
        return FALSE;
    }
    glamor_priv = calloc(1, sizeof(*glamor_priv));
    if (glamor_priv == NULL)
        return FALSE;

    glamor_priv->flags = flags;

    if (!dixRegisterPrivateKey(&glamor_screen_private_key, PRIVATE_SCREEN, 0)) {
        LogMessage(X_WARNING,
                   "glamor%d: Failed to allocate screen private\n",
                   screen->myNum);
        goto fail;
    }

    glamor_set_screen_private(screen, glamor_priv);

    if (!dixRegisterPrivateKey(&glamor_pixmap_private_key, PRIVATE_PIXMAP,
                               sizeof(struct glamor_pixmap_private))) {
        LogMessage(X_WARNING,
                   "glamor%d: Failed to allocate pixmap private\n",
                   screen->myNum);
        goto fail;
    }

    if (!dixRegisterPrivateKey(&glamor_gc_private_key, PRIVATE_GC,
                               sizeof (glamor_gc_private))) {
        LogMessage(X_WARNING,
                   "glamor%d: Failed to allocate gc private\n",
                   screen->myNum);
        goto fail;
    }

    glamor_priv->saved_procs.close_screen = screen->CloseScreen;
    screen->CloseScreen = glamor_close_screen;

    /* If we are using egl screen, call egl screen init to
     * register correct close screen function. */
    if (flags & GLAMOR_USE_EGL_SCREEN) {
        glamor_egl_screen_init(screen, &glamor_priv->ctx);
    } else {
        if (!glamor_glx_screen_init(&glamor_priv->ctx))
            goto fail;
    }

    glamor_make_current(glamor_priv);

    if (epoxy_is_desktop_gl())
        glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP;
    else
        glamor_priv->gl_flavor = GLAMOR_GL_ES2;

    gl_version = epoxy_gl_version();

    shading_version_string = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);

    if (!shading_version_string) {
        LogMessage(X_WARNING,
                   "glamor%d: Failed to get GLSL version\n",
                   screen->myNum);
        goto fail;
    }

    shading_version_offset = 0;
    if (strncmp("OpenGL ES GLSL ES ", shading_version_string, 18) == 0)
        shading_version_offset = 18;

    if (sscanf(shading_version_string + shading_version_offset,
               "%i.%i",
               &glsl_major,
               &glsl_minor) != 2) {
        LogMessage(X_WARNING,
                   "glamor%d: Failed to parse GLSL version string %s\n",
                   screen->myNum, shading_version_string);
        goto fail;
    }
    glamor_priv->glsl_version = glsl_major * 100 + glsl_minor;

    if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
        /* Force us back to the base version of our programs on an ES
         * context, anyway.  Basically glamor only uses desktop 1.20
         * or 1.30 currently.  1.30's new features are also present in
         * ES 3.0, but our glamor_program.c constructions use a lot of
         * compatibility features (to reduce the diff between 1.20 and
         * 1.30 programs).
         */
        glamor_priv->glsl_version = 120;
    }

    /* We'd like to require GL_ARB_map_buffer_range or
     * GL_OES_map_buffer_range, since it offers more information to
     * the driver than plain old glMapBuffer() or glBufferSubData().
     * It's been supported on Mesa on the desktop since 2009 and on
     * GLES2 since October 2012.  It's supported on Apple's iOS
     * drivers for SGX535 and A7, but apparently not on most Android
     * devices (the OES extension spec wasn't released until June
     * 2012).
     *
     * 82% of 0 A.D. players (desktop GL) submitting hardware reports
     * have support for it, with most of the ones lacking it being on
     * Windows with Intel 4-series (G45) graphics or older.
     */
    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
        if (gl_version < 21) {
            ErrorF("Require OpenGL version 2.1 or later.\n");
            goto fail;
        }

        if (!glamor_check_instruction_count(gl_version))
            goto fail;
    } else {
        if (gl_version < 20) {
            ErrorF("Require Open GLES2.0 or later.\n");
            goto fail;
        }

        if (!epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) {
            ErrorF("GL_EXT_texture_format_BGRA8888 required\n");
            goto fail;
        }
    }

    glamor_priv->has_rw_pbo = FALSE;
    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
        glamor_priv->has_rw_pbo = TRUE;

    glamor_priv->has_khr_debug = epoxy_has_gl_extension("GL_KHR_debug");
    glamor_priv->has_pack_invert =
        epoxy_has_gl_extension("GL_MESA_pack_invert");
    glamor_priv->has_fbo_blit =
        epoxy_has_gl_extension("GL_EXT_framebuffer_blit");
    glamor_priv->has_map_buffer_range =
        epoxy_has_gl_extension("GL_ARB_map_buffer_range") ||
        epoxy_has_gl_extension("GL_EXT_map_buffer_range");
    glamor_priv->has_buffer_storage =
        epoxy_has_gl_extension("GL_ARB_buffer_storage");
    glamor_priv->has_nv_texture_barrier =
        epoxy_has_gl_extension("GL_NV_texture_barrier");
    glamor_priv->has_unpack_subimage =
        glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP ||
        epoxy_gl_version() >= 30 ||
        epoxy_has_gl_extension("GL_EXT_unpack_subimage");
    glamor_priv->has_pack_subimage =
        glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP ||
        epoxy_gl_version() >= 30 ||
        epoxy_has_gl_extension("GL_NV_pack_subimage");
    glamor_priv->has_vertex_array_object =
        epoxy_has_gl_extension("GL_ARB_vertex_array_object");
    glamor_priv->has_dual_blend =
        epoxy_has_gl_extension("GL_ARB_blend_func_extended");

    /* assume a core profile if we are GL 3.1 and don't have ARB_compatibility */
    glamor_priv->is_core_profile =
        gl_version >= 31 && !epoxy_has_gl_extension("GL_ARB_compatibility");

    glamor_setup_debug_output(screen);

    glamor_priv->use_quads = (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) &&
                             !glamor_priv->is_core_profile;

    /* Driver-specific hack: Avoid using GL_QUADS on VC4, where
     * they'll be emulated more expensively than we can with our
     * cached IB.
     */
    if (strstr((char *)glGetString(GL_VENDOR), "Broadcom") &&
        strstr((char *)glGetString(GL_RENDERER), "VC4"))
        glamor_priv->use_quads = FALSE;

    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size);
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glamor_priv->max_fbo_size);
    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
    glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[0]);
    glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[1]);
#ifdef MAX_FBO_SIZE
    glamor_priv->max_fbo_size = MAX_FBO_SIZE;
#endif

    glamor_priv->one_channel_format = GL_ALPHA;
    if (epoxy_has_gl_extension("GL_ARB_texture_rg") && epoxy_has_gl_extension("GL_ARB_texture_swizzle"))
        glamor_priv->one_channel_format = GL_RED;

    glamor_set_debug_level(&glamor_debug_level);

    glamor_priv->saved_procs.create_screen_resources =
        screen->CreateScreenResources;
    screen->CreateScreenResources = glamor_create_screen_resources;

    if (!glamor_font_init(screen))
        goto fail;

    glamor_priv->saved_procs.block_handler = screen->BlockHandler;
    screen->BlockHandler = _glamor_block_handler;

    if (!glamor_composite_glyphs_init(screen)) {
        ErrorF("Failed to initialize composite masks\n");
        goto fail;
    }

    glamor_priv->saved_procs.create_gc = screen->CreateGC;
    screen->CreateGC = glamor_create_gc;

    glamor_priv->saved_procs.create_pixmap = screen->CreatePixmap;
    screen->CreatePixmap = glamor_create_pixmap;

    glamor_priv->saved_procs.destroy_pixmap = screen->DestroyPixmap;
    screen->DestroyPixmap = glamor_destroy_pixmap;

    glamor_priv->saved_procs.get_spans = screen->GetSpans;
    screen->GetSpans = glamor_get_spans;

    glamor_priv->saved_procs.get_image = screen->GetImage;
    screen->GetImage = glamor_get_image;

    glamor_priv->saved_procs.change_window_attributes =
        screen->ChangeWindowAttributes;
    screen->ChangeWindowAttributes = glamor_change_window_attributes;

    glamor_priv->saved_procs.copy_window = screen->CopyWindow;
    screen->CopyWindow = glamor_copy_window;

    glamor_priv->saved_procs.bitmap_to_region = screen->BitmapToRegion;
    screen->BitmapToRegion = glamor_bitmap_to_region;

    glamor_priv->saved_procs.composite = ps->Composite;
    ps->Composite = glamor_composite;

    glamor_priv->saved_procs.trapezoids = ps->Trapezoids;
    ps->Trapezoids = glamor_trapezoids;

    glamor_priv->saved_procs.triangles = ps->Triangles;
    ps->Triangles = glamor_triangles;

    glamor_priv->saved_procs.addtraps = ps->AddTraps;
    ps->AddTraps = glamor_add_traps;

    glamor_priv->saved_procs.composite_rects = ps->CompositeRects;
    ps->CompositeRects = glamor_composite_rectangles;

    glamor_priv->saved_procs.glyphs = ps->Glyphs;
    ps->Glyphs = glamor_composite_glyphs;

    glamor_init_vbo(screen);
    glamor_init_pixmap_fbo(screen);
    glamor_init_finish_access_shaders(screen);

#ifdef GLAMOR_GRADIENT_SHADER
    glamor_init_gradient_shader(screen);
#endif
    glamor_pixmap_init(screen);
    glamor_sync_init(screen);

    glamor_priv->screen = screen;

    return TRUE;

 fail:
    free(glamor_priv);
    glamor_set_screen_private(screen, NULL);
    return FALSE;
}
예제 #7
0
struct ephyr_glamor *
ephyr_glamor_glx_screen_init(xcb_window_t win)
{
    int (*oldErrorHandler) (Display *, XErrorEvent *);
    static const float position[] = {
        -1, -1,
         1, -1,
         1,  1,
        -1,  1,
        0, 1,
        1, 1,
        1, 0,
        0, 0,
    };
    GLint old_vao;

    GLXContext ctx;
    struct ephyr_glamor *glamor;
    GLXWindow glx_win;

    glamor = calloc(1, sizeof(struct ephyr_glamor));
    if (!glamor) {
        FatalError("malloc");
        return NULL;
    }

    glx_win = glXCreateWindow(dpy, fb_config, win, NULL);

    if (ephyr_glamor_gles2) {
        static const int context_attribs[] = {
            GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
            GLX_CONTEXT_MINOR_VERSION_ARB, 0,
            GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES_PROFILE_BIT_EXT,
            0,
        };
        if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy),
                                    "GLX_EXT_create_context_es2_profile")) {
            ctx = glXCreateContextAttribsARB(dpy, fb_config, NULL, True,
                                             context_attribs);
        } else {
            FatalError("Xephyr -glamor_gles2 rquires "
                       "GLX_EXT_create_context_es2_profile\n");
        }
    } else {
        if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy),
                                    "GLX_ARB_create_context")) {
            static const int context_attribs[] = {
                GLX_CONTEXT_PROFILE_MASK_ARB,
                GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
                GLX_CONTEXT_MAJOR_VERSION_ARB,
                GLAMOR_GL_CORE_VER_MAJOR,
                GLX_CONTEXT_MINOR_VERSION_ARB,
                GLAMOR_GL_CORE_VER_MINOR,
                0,
            };
            oldErrorHandler = XSetErrorHandler(ephyr_glx_error_handler);
            ctx = glXCreateContextAttribsARB(dpy, fb_config, NULL, True,
                                             context_attribs);
            XSync(dpy, False);
            XSetErrorHandler(oldErrorHandler);
        } else {
            ctx = NULL;
        }

        if (!ctx)
            ctx = glXCreateContext(dpy, visual_info, NULL, True);
    }
    if (ctx == NULL)
        FatalError("glXCreateContext failed\n");

    if (!glXMakeCurrent(dpy, glx_win, ctx))
        FatalError("glXMakeCurrent failed\n");

    glamor->ctx = ctx;
    glamor->win = win;
    glamor->glx_win = glx_win;
    ephyr_glamor_setup_texturing_shader(glamor);

    if (epoxy_has_gl_extension("GL_ARB_vertex_array_object")) {
        glGenVertexArrays(1, &glamor->vao);
        glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
        glBindVertexArray(glamor->vao);
    } else
        glamor->vao = 0;

    glGenBuffers(1, &glamor->vbo);

    glBindBuffer(GL_ARRAY_BUFFER, glamor->vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);

    if (glamor->vao) {
        ephyr_glamor_set_vertices(glamor);
        glBindVertexArray(old_vao);
    } else
        glBindBuffer(GL_ARRAY_BUFFER, 0);

    return glamor;
}