Path: blob/21.2-virgl/src/egl/drivers/dri2/platform_x11.c
4570 views
/*1* Copyright © 2011 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT18* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,19* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,20* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER21* DEALINGS IN THE SOFTWARE.22*23* Authors:24* Kristian Høgsberg <[email protected]>25*/2627#include <stdbool.h>28#include <stdint.h>29#include <stdlib.h>30#include <string.h>31#include <stdio.h>32#include <limits.h>33#include <dlfcn.h>34#include <fcntl.h>35#include <errno.h>36#include <unistd.h>37#ifdef HAVE_LIBDRM38#include <xf86drm.h>39#endif40#include <sys/types.h>41#include <sys/stat.h>42#include "util/debug.h"43#include "util/macros.h"44#include "util/bitscan.h"4546#include "egl_dri2.h"47#include "loader.h"4849#ifdef HAVE_DRI350#include "platform_x11_dri3.h"51#endif5253static EGLBoolean54dri2_x11_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval);5556uint32_t57dri2_format_for_depth(struct dri2_egl_display *dri2_dpy, uint32_t depth);5859static void60swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,61struct dri2_egl_surface * dri2_surf)62{63uint32_t mask;64const uint32_t function = GXcopy;65uint32_t valgc[2];6667/* create GC's */68dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);69mask = XCB_GC_FUNCTION;70xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function);7172dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);73mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;74valgc[0] = function;75valgc[1] = False;76xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc);77switch (dri2_surf->depth) {78case 32:79case 30:80case 24:81dri2_surf->bytes_per_pixel = 4;82break;83case 16:84dri2_surf->bytes_per_pixel = 2;85break;86case 8:87dri2_surf->bytes_per_pixel = 1;88break;89case 0:90dri2_surf->bytes_per_pixel = 0;91break;92default:93_eglLog(_EGL_WARNING, "unsupported depth %d", dri2_surf->depth);94}95}9697static void98swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,99struct dri2_egl_surface * dri2_surf)100{101xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);102xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);103}104105static bool106x11_get_drawable_info(__DRIdrawable * draw,107int *x, int *y, int *w, int *h,108void *loaderPrivate)109{110struct dri2_egl_surface *dri2_surf = loaderPrivate;111struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);112113xcb_get_geometry_cookie_t cookie;114xcb_get_geometry_reply_t *reply;115xcb_generic_error_t *error;116bool ret;117118cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);119reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);120if (reply == NULL)121return false;122123if (error != NULL) {124ret = false;125_eglLog(_EGL_WARNING, "error in xcb_get_geometry");126free(error);127} else {128*x = reply->x;129*y = reply->y;130*w = reply->width;131*h = reply->height;132ret = true;133}134free(reply);135return ret;136}137138static void139swrastGetDrawableInfo(__DRIdrawable * draw,140int *x, int *y, int *w, int *h,141void *loaderPrivate)142{143*x = *y = *w = *h = 0;144x11_get_drawable_info(draw, x, y, w, h, loaderPrivate);145}146147static void148swrastPutImage(__DRIdrawable * draw, int op,149int x, int y, int w, int h,150char *data, void *loaderPrivate)151{152struct dri2_egl_surface *dri2_surf = loaderPrivate;153struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);154155xcb_gcontext_t gc;156157switch (op) {158case __DRI_SWRAST_IMAGE_OP_DRAW:159gc = dri2_surf->gc;160break;161case __DRI_SWRAST_IMAGE_OP_SWAP:162gc = dri2_surf->swapgc;163break;164default:165return;166}167168xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable,169gc, w, h, x, y, 0, dri2_surf->depth,170w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data);171}172173static void174swrastGetImage(__DRIdrawable * read,175int x, int y, int w, int h,176char *data, void *loaderPrivate)177{178struct dri2_egl_surface *dri2_surf = loaderPrivate;179struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);180181xcb_get_image_cookie_t cookie;182xcb_get_image_reply_t *reply;183xcb_generic_error_t *error;184185cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,186dri2_surf->drawable, x, y, w, h, ~0);187reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error);188if (reply == NULL)189return;190191if (error != NULL) {192_eglLog(_EGL_WARNING, "error in xcb_get_image");193free(error);194} else {195uint32_t bytes = xcb_get_image_data_length(reply);196uint8_t *idata = xcb_get_image_data(reply);197memcpy(data, idata, bytes);198}199free(reply);200}201202203static xcb_screen_t *204get_xcb_screen(xcb_screen_iterator_t iter, int screen)205{206for (; iter.rem; --screen, xcb_screen_next(&iter))207if (screen == 0)208return iter.data;209210return NULL;211}212213static xcb_visualtype_t *214get_xcb_visualtype_for_depth(struct dri2_egl_display *dri2_dpy, int depth)215{216xcb_visualtype_iterator_t visual_iter;217xcb_screen_t *screen = dri2_dpy->screen;218xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen);219220for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {221if (depth_iter.data->depth != depth)222continue;223224visual_iter = xcb_depth_visuals_iterator(depth_iter.data);225if (visual_iter.rem)226return visual_iter.data;227}228229return NULL;230}231232/* Get red channel mask for given depth. */233unsigned int234dri2_x11_get_red_mask_for_depth(struct dri2_egl_display *dri2_dpy, int depth)235{236xcb_visualtype_t *visual = get_xcb_visualtype_for_depth(dri2_dpy, depth);237238if (visual)239return visual->red_mask;240241return 0;242}243244/**245* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().246*/247static _EGLSurface *248dri2_x11_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,249void *native_surface, const EGLint *attrib_list)250{251struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);252struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);253struct dri2_egl_surface *dri2_surf;254xcb_get_geometry_cookie_t cookie;255xcb_get_geometry_reply_t *reply;256xcb_generic_error_t *error;257const __DRIconfig *config;258259dri2_surf = calloc(1, sizeof *dri2_surf);260if (!dri2_surf) {261_eglError(EGL_BAD_ALLOC, "dri2_create_surface");262return NULL;263}264265if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,266false, native_surface))267goto cleanup_surf;268269dri2_surf->region = XCB_NONE;270if (type == EGL_PBUFFER_BIT) {271dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);272xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,273dri2_surf->drawable, dri2_dpy->screen->root,274dri2_surf->base.Width, dri2_surf->base.Height);275} else {276STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));277dri2_surf->drawable = (uintptr_t) native_surface;278}279280config = dri2_get_dri_config(dri2_conf, type,281dri2_surf->base.GLColorspace);282283if (!config) {284_eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");285goto cleanup_pixmap;286}287288if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))289goto cleanup_pixmap;290291if (type != EGL_PBUFFER_BIT) {292cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);293reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);294if (error != NULL) {295if (error->error_code == BadAlloc)296_eglError(EGL_BAD_ALLOC, "xcb_get_geometry");297else if (type == EGL_WINDOW_BIT)298_eglError(EGL_BAD_NATIVE_WINDOW, "xcb_get_geometry");299else300_eglError(EGL_BAD_NATIVE_PIXMAP, "xcb_get_geometry");301free(error);302free(reply);303goto cleanup_dri_drawable;304} else if (reply == NULL) {305_eglError(EGL_BAD_ALLOC, "xcb_get_geometry");306goto cleanup_dri_drawable;307}308309dri2_surf->base.Width = reply->width;310dri2_surf->base.Height = reply->height;311dri2_surf->depth = reply->depth;312free(reply);313}314315if (dri2_dpy->dri2) {316xcb_void_cookie_t cookie;317int conn_error;318319cookie = xcb_dri2_create_drawable_checked(dri2_dpy->conn,320dri2_surf->drawable);321error = xcb_request_check(dri2_dpy->conn, cookie);322conn_error = xcb_connection_has_error(dri2_dpy->conn);323if (conn_error || error != NULL) {324if (type == EGL_PBUFFER_BIT || conn_error || error->error_code == BadAlloc)325_eglError(EGL_BAD_ALLOC, "xcb_dri2_create_drawable_checked");326else if (type == EGL_WINDOW_BIT)327_eglError(EGL_BAD_NATIVE_WINDOW,328"xcb_dri2_create_drawable_checked");329else330_eglError(EGL_BAD_NATIVE_PIXMAP,331"xcb_dri2_create_drawable_checked");332free(error);333goto cleanup_dri_drawable;334}335} else {336if (type == EGL_PBUFFER_BIT) {337dri2_surf->depth = conf->BufferSize;338}339swrastCreateDrawable(dri2_dpy, dri2_surf);340}341342/* we always copy the back buffer to front */343dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE;344345return &dri2_surf->base;346347cleanup_dri_drawable:348dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);349cleanup_pixmap:350if (type == EGL_PBUFFER_BIT)351xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);352cleanup_surf:353free(dri2_surf);354355return NULL;356}357358/**359* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().360*/361static _EGLSurface *362dri2_x11_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,363void *native_window, const EGLint *attrib_list)364{365struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);366_EGLSurface *surf;367368surf = dri2_x11_create_surface(disp, EGL_WINDOW_BIT, conf,369native_window, attrib_list);370if (surf != NULL) {371/* When we first create the DRI2 drawable, its swap interval on the372* server side is 1.373*/374surf->SwapInterval = 1;375376/* Override that with a driconf-set value. */377dri2_x11_swap_interval(disp, surf, dri2_dpy->default_swap_interval);378}379380return surf;381}382383static _EGLSurface *384dri2_x11_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,385void *native_pixmap, const EGLint *attrib_list)386{387return dri2_x11_create_surface(disp, EGL_PIXMAP_BIT, conf,388native_pixmap, attrib_list);389}390391static _EGLSurface *392dri2_x11_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,393const EGLint *attrib_list)394{395return dri2_x11_create_surface(disp, EGL_PBUFFER_BIT, conf,396NULL, attrib_list);397}398399static EGLBoolean400dri2_x11_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)401{402struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);403struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);404405dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);406407if (dri2_dpy->dri2) {408xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);409} else {410assert(dri2_dpy->swrast);411swrastDestroyDrawable(dri2_dpy, dri2_surf);412}413414if (surf->Type == EGL_PBUFFER_BIT)415xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);416417dri2_fini_surface(surf);418free(surf);419420return EGL_TRUE;421}422423/**424* Function utilizes swrastGetDrawableInfo to get surface425* geometry from x server and calls default query surface426* implementation that returns the updated values.427*428* In case of errors we still return values that we currently429* have.430*/431static EGLBoolean432dri2_query_surface(_EGLDisplay *disp, _EGLSurface *surf,433EGLint attribute, EGLint *value)434{435struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);436struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);437int x, y, w, h;438439__DRIdrawable *drawable = dri2_dpy->vtbl->get_dri_drawable(surf);440441switch (attribute) {442case EGL_WIDTH:443case EGL_HEIGHT:444if (x11_get_drawable_info(drawable, &x, &y, &w, &h, dri2_surf)) {445surf->Width = w;446surf->Height = h;447}448break;449default:450break;451}452return _eglQuerySurface(disp, surf, attribute, value);453}454455/**456* Process list of buffer received from the server457*458* Processes the list of buffers received in a reply from the server to either459* \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.460*/461static void462dri2_x11_process_buffers(struct dri2_egl_surface *dri2_surf,463xcb_dri2_dri2_buffer_t *buffers, unsigned count)464{465struct dri2_egl_display *dri2_dpy =466dri2_egl_display(dri2_surf->base.Resource.Display);467xcb_rectangle_t rectangle;468469dri2_surf->have_fake_front = false;470471/* This assumes the DRI2 buffer attachment tokens matches the472* __DRIbuffer tokens. */473for (unsigned i = 0; i < count; i++) {474dri2_surf->buffers[i].attachment = buffers[i].attachment;475dri2_surf->buffers[i].name = buffers[i].name;476dri2_surf->buffers[i].pitch = buffers[i].pitch;477dri2_surf->buffers[i].cpp = buffers[i].cpp;478dri2_surf->buffers[i].flags = buffers[i].flags;479480/* We only use the DRI drivers single buffer configs. This481* means that if we try to render to a window, DRI2 will give us482* the fake front buffer, which we'll use as a back buffer.483* Note that EGL doesn't require that several clients rendering484* to the same window must see the same aux buffers. */485if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)486dri2_surf->have_fake_front = true;487}488489if (dri2_surf->region != XCB_NONE)490xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);491492rectangle.x = 0;493rectangle.y = 0;494rectangle.width = dri2_surf->base.Width;495rectangle.height = dri2_surf->base.Height;496dri2_surf->region = xcb_generate_id(dri2_dpy->conn);497xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);498}499500static __DRIbuffer *501dri2_x11_get_buffers(__DRIdrawable * driDrawable,502int *width, int *height,503unsigned int *attachments, int count,504int *out_count, void *loaderPrivate)505{506struct dri2_egl_surface *dri2_surf = loaderPrivate;507struct dri2_egl_display *dri2_dpy =508dri2_egl_display(dri2_surf->base.Resource.Display);509xcb_dri2_dri2_buffer_t *buffers;510xcb_dri2_get_buffers_reply_t *reply;511xcb_dri2_get_buffers_cookie_t cookie;512513(void) driDrawable;514515cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,516dri2_surf->drawable,517count, count, attachments);518reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);519if (reply == NULL)520return NULL;521buffers = xcb_dri2_get_buffers_buffers (reply);522if (buffers == NULL) {523free(reply);524return NULL;525}526527*out_count = reply->count;528dri2_surf->base.Width = *width = reply->width;529dri2_surf->base.Height = *height = reply->height;530dri2_x11_process_buffers(dri2_surf, buffers, *out_count);531532free(reply);533534return dri2_surf->buffers;535}536537static __DRIbuffer *538dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,539int *width, int *height,540unsigned int *attachments, int count,541int *out_count, void *loaderPrivate)542{543struct dri2_egl_surface *dri2_surf = loaderPrivate;544struct dri2_egl_display *dri2_dpy =545dri2_egl_display(dri2_surf->base.Resource.Display);546xcb_dri2_dri2_buffer_t *buffers;547xcb_dri2_get_buffers_with_format_reply_t *reply;548xcb_dri2_get_buffers_with_format_cookie_t cookie;549xcb_dri2_attach_format_t *format_attachments;550551(void) driDrawable;552553format_attachments = (xcb_dri2_attach_format_t *) attachments;554cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,555dri2_surf->drawable,556count, count,557format_attachments);558559reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,560cookie, NULL);561if (reply == NULL)562return NULL;563564buffers = xcb_dri2_get_buffers_with_format_buffers (reply);565dri2_surf->base.Width = *width = reply->width;566dri2_surf->base.Height = *height = reply->height;567*out_count = reply->count;568dri2_x11_process_buffers(dri2_surf, buffers, *out_count);569570free(reply);571572return dri2_surf->buffers;573}574575static void576dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)577{578(void) driDrawable;579580/* FIXME: Does EGL support front buffer rendering at all? */581582#if 0583struct dri2_egl_surface *dri2_surf = loaderPrivate;584585dri2WaitGL(dri2_surf);586#else587(void) loaderPrivate;588#endif589}590591static int592dri2_x11_do_authenticate(struct dri2_egl_display *dri2_dpy, uint32_t id)593{594xcb_dri2_authenticate_reply_t *authenticate;595xcb_dri2_authenticate_cookie_t authenticate_cookie;596int ret = 0;597598authenticate_cookie =599xcb_dri2_authenticate_unchecked(dri2_dpy->conn, dri2_dpy->screen->root, id);600authenticate =601xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);602603if (authenticate == NULL || !authenticate->authenticated)604ret = -1;605606free(authenticate);607608return ret;609}610611static EGLBoolean612dri2_x11_local_authenticate(struct dri2_egl_display *dri2_dpy)613{614#ifdef HAVE_LIBDRM615drm_magic_t magic;616617if (drmGetMagic(dri2_dpy->fd, &magic)) {618_eglLog(_EGL_WARNING, "DRI2: failed to get drm magic");619return EGL_FALSE;620}621622if (dri2_x11_do_authenticate(dri2_dpy, magic) < 0) {623_eglLog(_EGL_WARNING, "DRI2: failed to authenticate");624return EGL_FALSE;625}626#endif627return EGL_TRUE;628}629630static EGLBoolean631dri2_x11_connect(struct dri2_egl_display *dri2_dpy)632{633xcb_xfixes_query_version_reply_t *xfixes_query;634xcb_xfixes_query_version_cookie_t xfixes_query_cookie;635xcb_dri2_query_version_reply_t *dri2_query;636xcb_dri2_query_version_cookie_t dri2_query_cookie;637xcb_dri2_connect_reply_t *connect;638xcb_dri2_connect_cookie_t connect_cookie;639xcb_generic_error_t *error;640char *driver_name, *loader_driver_name, *device_name;641const xcb_query_extension_reply_t *extension;642643xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);644xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);645646extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);647if (!(extension && extension->present))648return EGL_FALSE;649650extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id);651if (!(extension && extension->present))652return EGL_FALSE;653654xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,655XCB_XFIXES_MAJOR_VERSION,656XCB_XFIXES_MINOR_VERSION);657658dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,659XCB_DRI2_MAJOR_VERSION,660XCB_DRI2_MINOR_VERSION);661662connect_cookie = xcb_dri2_connect_unchecked(dri2_dpy->conn, dri2_dpy->screen->root,663XCB_DRI2_DRIVER_TYPE_DRI);664665xfixes_query =666xcb_xfixes_query_version_reply (dri2_dpy->conn,667xfixes_query_cookie, &error);668if (xfixes_query == NULL ||669error != NULL || xfixes_query->major_version < 2) {670_eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");671free(error);672free(xfixes_query);673return EGL_FALSE;674}675free(xfixes_query);676677dri2_query =678xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);679if (dri2_query == NULL || error != NULL) {680_eglLog(_EGL_WARNING, "DRI2: failed to query version");681free(error);682free(dri2_query);683return EGL_FALSE;684}685dri2_dpy->dri2_major = dri2_query->major_version;686dri2_dpy->dri2_minor = dri2_query->minor_version;687free(dri2_query);688689connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);690if (connect == NULL ||691connect->driver_name_length + connect->device_name_length == 0) {692_eglLog(_EGL_WARNING, "DRI2: failed to authenticate");693free(connect);694return EGL_FALSE;695}696697device_name = xcb_dri2_connect_device_name (connect);698699dri2_dpy->fd = loader_open_device(device_name);700if (dri2_dpy->fd == -1) {701_eglLog(_EGL_WARNING,702"DRI2: could not open %s (%s)", device_name, strerror(errno));703free(connect);704return EGL_FALSE;705}706707if (!dri2_x11_local_authenticate(dri2_dpy)) {708close(dri2_dpy->fd);709free(connect);710return EGL_FALSE;711}712713driver_name = xcb_dri2_connect_driver_name (connect);714715/* If Mesa knows about the appropriate driver for this fd, then trust it.716* Otherwise, default to the server's value.717*/718loader_driver_name = loader_get_driver_for_fd(dri2_dpy->fd);719if (loader_driver_name) {720dri2_dpy->driver_name = loader_driver_name;721} else {722dri2_dpy->driver_name =723strndup(driver_name,724xcb_dri2_connect_driver_name_length(connect));725}726727if (dri2_dpy->driver_name == NULL) {728close(dri2_dpy->fd);729free(connect);730return EGL_FALSE;731}732733#ifdef HAVE_WAYLAND_PLATFORM734dri2_dpy->device_name =735strndup(device_name,736xcb_dri2_connect_device_name_length(connect));737#endif738739free(connect);740741return EGL_TRUE;742}743744static int745dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id)746{747struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);748749return dri2_x11_do_authenticate(dri2_dpy, id);750}751752static EGLBoolean753dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,754_EGLDisplay *disp, bool supports_preserved)755{756xcb_depth_iterator_t d;757xcb_visualtype_t *visuals;758int config_count = 0;759EGLint surface_type;760761d = xcb_screen_allowed_depths_iterator(dri2_dpy->screen);762763surface_type =764EGL_WINDOW_BIT |765EGL_PIXMAP_BIT |766EGL_PBUFFER_BIT;767768if (supports_preserved)769surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT;770771while (d.rem > 0) {772EGLBoolean class_added[6] = { 0, };773774visuals = xcb_depth_visuals(d.data);775776for (int i = 0; i < xcb_depth_visuals_length(d.data); i++) {777if (class_added[visuals[i]._class])778continue;779780class_added[visuals[i]._class] = EGL_TRUE;781782for (int j = 0; dri2_dpy->driver_configs[j]; j++) {783struct dri2_egl_config *dri2_conf;784const __DRIconfig *config = dri2_dpy->driver_configs[j];785786const EGLint config_attrs[] = {787EGL_NATIVE_VISUAL_ID, visuals[i].visual_id,788EGL_NATIVE_VISUAL_TYPE, visuals[i]._class,789EGL_NONE790};791792int rgba_shifts[4] = {793ffs(visuals[i].red_mask) - 1,794ffs(visuals[i].green_mask) - 1,795ffs(visuals[i].blue_mask) - 1,796-1,797};798799unsigned int rgba_sizes[4] = {800util_bitcount(visuals[i].red_mask),801util_bitcount(visuals[i].green_mask),802util_bitcount(visuals[i].blue_mask),8030,804};805806dri2_conf = dri2_add_config(disp, config, config_count + 1,807surface_type, config_attrs,808rgba_shifts, rgba_sizes);809if (dri2_conf)810if (dri2_conf->base.ConfigID == config_count + 1)811config_count++;812813/* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig.814* Ditto for 30-bit RGB visuals to match a 32-bit RGBA EGLConfig.815* Otherwise it will only match a 32-bit RGBA visual. On a816* composited window manager on X11, this will make all of the817* EGLConfigs with destination alpha get blended by the818* compositor. This is probably not what the application819* wants... especially on drivers that only have 32-bit RGBA820* EGLConfigs! */821if (d.data->depth == 24 || d.data->depth == 30) {822unsigned int rgba_mask = ~(visuals[i].red_mask |823visuals[i].green_mask |824visuals[i].blue_mask);825rgba_shifts[3] = ffs(rgba_mask) - 1;826rgba_sizes[3] = util_bitcount(rgba_mask);827dri2_conf = dri2_add_config(disp, config, config_count + 1,828surface_type, config_attrs,829rgba_shifts, rgba_sizes);830if (dri2_conf)831if (dri2_conf->base.ConfigID == config_count + 1)832config_count++;833}834}835}836837xcb_depth_next(&d);838}839840if (!config_count) {841_eglLog(_EGL_WARNING, "DRI2: failed to create any config");842return EGL_FALSE;843}844845return EGL_TRUE;846}847848static EGLBoolean849dri2_copy_region(_EGLDisplay *disp,850_EGLSurface *draw, xcb_xfixes_region_t region)851{852struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);853struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);854enum xcb_dri2_attachment_t render_attachment;855xcb_dri2_copy_region_cookie_t cookie;856857/* No-op for a pixmap or pbuffer surface */858if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)859return EGL_TRUE;860861dri2_dpy->flush->flush(dri2_surf->dri_drawable);862863if (dri2_surf->have_fake_front)864render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;865else866render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;867868cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,869dri2_surf->drawable,870region,871XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,872render_attachment);873free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));874875return EGL_TRUE;876}877878static int64_t879dri2_x11_swap_buffers_msc(_EGLDisplay *disp, _EGLSurface *draw,880int64_t msc, int64_t divisor, int64_t remainder)881{882struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);883struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);884uint32_t msc_hi = msc >> 32;885uint32_t msc_lo = msc & 0xffffffff;886uint32_t divisor_hi = divisor >> 32;887uint32_t divisor_lo = divisor & 0xffffffff;888uint32_t remainder_hi = remainder >> 32;889uint32_t remainder_lo = remainder & 0xffffffff;890xcb_dri2_swap_buffers_cookie_t cookie;891xcb_dri2_swap_buffers_reply_t *reply;892int64_t swap_count = -1;893894if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available) {895swap_count = dri2_copy_region(disp, draw, dri2_surf->region) ? 0 : -1;896} else {897dri2_flush_drawable_for_swapbuffers(disp, draw);898899cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn,900dri2_surf->drawable, msc_hi,901msc_lo, divisor_hi, divisor_lo,902remainder_hi, remainder_lo);903904reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL);905906if (reply) {907swap_count = combine_u32_into_u64(reply->swap_hi, reply->swap_lo);908free(reply);909}910}911912/* Since we aren't watching for the server's invalidate events like we're913* supposed to (due to XCB providing no mechanism for filtering the events914* the way xlib does), and SwapBuffers is a common cause of invalidate915* events, just shove one down to the driver, even though we haven't told916* the driver that we're the kind of loader that provides reliable917* invalidate events. This causes the driver to request buffers again at918* its next draw, so that we get the correct buffers if a pageflip919* happened. The driver should still be using the viewport hack to catch920* window resizes.921*/922if (dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)923dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);924925return swap_count;926}927928static EGLBoolean929dri2_x11_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)930{931struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);932struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);933934if (!dri2_dpy->flush) {935dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);936return EGL_TRUE;937}938939if (dri2_x11_swap_buffers_msc(disp, draw, 0, 0, 0) == -1) {940/* Swap failed with a window drawable. */941return _eglError(EGL_BAD_NATIVE_WINDOW, __func__);942}943return EGL_TRUE;944}945946static EGLBoolean947dri2_x11_swap_buffers_region(_EGLDisplay *disp, _EGLSurface *draw,948EGLint numRects, const EGLint *rects)949{950struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);951struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);952EGLBoolean ret;953xcb_xfixes_region_t region;954xcb_rectangle_t rectangles[16];955956if (numRects > (int)ARRAY_SIZE(rectangles))957return dri2_copy_region(disp, draw, dri2_surf->region);958959for (int i = 0; i < numRects; i++) {960rectangles[i].x = rects[i * 4];961rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3];962rectangles[i].width = rects[i * 4 + 2];963rectangles[i].height = rects[i * 4 + 3];964}965966region = xcb_generate_id(dri2_dpy->conn);967xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);968ret = dri2_copy_region(disp, draw, region);969xcb_xfixes_destroy_region(dri2_dpy->conn, region);970971return ret;972}973974static EGLBoolean975dri2_x11_post_sub_buffer(_EGLDisplay *disp, _EGLSurface *draw,976EGLint x, EGLint y, EGLint width, EGLint height)977{978const EGLint rect[4] = { x, y, width, height };979980if (x < 0 || y < 0 || width < 0 || height < 0)981_eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");982983return dri2_x11_swap_buffers_region(disp, draw, 1, rect);984}985986static EGLBoolean987dri2_x11_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)988{989struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);990struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);991992if (dri2_dpy->swap_available)993xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval);994995return EGL_TRUE;996}997998static EGLBoolean999dri2_x11_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)1000{1001struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);1002struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);1003xcb_gcontext_t gc;1004xcb_pixmap_t target;10051006STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));1007target = (uintptr_t) native_pixmap_target;10081009dri2_dpy->flush->flush(dri2_surf->dri_drawable);10101011gc = xcb_generate_id(dri2_dpy->conn);1012xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);1013xcb_copy_area(dri2_dpy->conn,1014dri2_surf->drawable,1015target,1016gc,10170, 0,10180, 0,1019dri2_surf->base.Width,1020dri2_surf->base.Height);1021xcb_free_gc(dri2_dpy->conn, gc);10221023return EGL_TRUE;1024}10251026uint32_t1027dri2_format_for_depth(struct dri2_egl_display *dri2_dpy, uint32_t depth)1028{1029switch (depth) {1030case 16:1031return __DRI_IMAGE_FORMAT_RGB565;1032case 24:1033return __DRI_IMAGE_FORMAT_XRGB8888;1034case 30:1035/* Different preferred formats for different hw */1036if (dri2_x11_get_red_mask_for_depth(dri2_dpy, 30) == 0x3ff)1037return __DRI_IMAGE_FORMAT_XBGR2101010;1038else1039return __DRI_IMAGE_FORMAT_XRGB2101010;1040case 32:1041return __DRI_IMAGE_FORMAT_ARGB8888;1042default:1043return __DRI_IMAGE_FORMAT_NONE;1044}1045}10461047static _EGLImage *1048dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,1049EGLClientBuffer buffer, const EGLint *attr_list)1050{1051struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);1052struct dri2_egl_image *dri2_img;1053unsigned int attachments[1];1054xcb_drawable_t drawable;1055xcb_dri2_get_buffers_cookie_t buffers_cookie;1056xcb_dri2_get_buffers_reply_t *buffers_reply;1057xcb_dri2_dri2_buffer_t *buffers;1058xcb_get_geometry_cookie_t geometry_cookie;1059xcb_get_geometry_reply_t *geometry_reply;1060xcb_generic_error_t *error;1061int stride, format;10621063(void) ctx;10641065drawable = (xcb_drawable_t) (uintptr_t) buffer;1066xcb_dri2_create_drawable (dri2_dpy->conn, drawable);1067attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;1068buffers_cookie =1069xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,1070drawable, 1, 1, attachments);1071geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);1072buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,1073buffers_cookie, NULL);1074if (buffers_reply == NULL)1075return NULL;10761077buffers = xcb_dri2_get_buffers_buffers (buffers_reply);1078if (buffers == NULL) {1079free(buffers_reply);1080return NULL;1081}10821083geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,1084geometry_cookie, &error);1085if (geometry_reply == NULL || error != NULL) {1086_eglError(EGL_BAD_ALLOC, "xcb_get_geometry");1087free(error);1088free(buffers_reply);1089free(geometry_reply);1090return NULL;1091}10921093format = dri2_format_for_depth(dri2_dpy, geometry_reply->depth);1094if (format == __DRI_IMAGE_FORMAT_NONE) {1095_eglError(EGL_BAD_PARAMETER,1096"dri2_create_image_khr: unsupported pixmap depth");1097free(buffers_reply);1098free(geometry_reply);1099return NULL;1100}11011102dri2_img = malloc(sizeof *dri2_img);1103if (!dri2_img) {1104free(buffers_reply);1105free(geometry_reply);1106_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");1107return EGL_NO_IMAGE_KHR;1108}11091110_eglInitImage(&dri2_img->base, disp);11111112stride = buffers[0].pitch / buffers[0].cpp;1113dri2_img->dri_image =1114dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,1115buffers_reply->width,1116buffers_reply->height,1117format,1118buffers[0].name,1119stride,1120dri2_img);11211122free(buffers_reply);1123free(geometry_reply);11241125return &dri2_img->base;1126}11271128static _EGLImage *1129dri2_x11_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,1130EGLClientBuffer buffer, const EGLint *attr_list)1131{1132switch (target) {1133case EGL_NATIVE_PIXMAP_KHR:1134return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);1135default:1136return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);1137}1138}11391140static EGLBoolean1141dri2_x11_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,1142EGLuint64KHR *ust, EGLuint64KHR *msc,1143EGLuint64KHR *sbc)1144{1145struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);1146struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);1147xcb_dri2_get_msc_cookie_t cookie;1148xcb_dri2_get_msc_reply_t *reply;11491150cookie = xcb_dri2_get_msc(dri2_dpy->conn, dri2_surf->drawable);1151reply = xcb_dri2_get_msc_reply(dri2_dpy->conn, cookie, NULL);11521153if (!reply)1154return _eglError(EGL_BAD_ACCESS, __func__);11551156*ust = ((EGLuint64KHR) reply->ust_hi << 32) | reply->ust_lo;1157*msc = ((EGLuint64KHR) reply->msc_hi << 32) | reply->msc_lo;1158*sbc = ((EGLuint64KHR) reply->sbc_hi << 32) | reply->sbc_lo;1159free(reply);11601161return EGL_TRUE;1162}11631164static const struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = {1165.authenticate = NULL,1166.create_window_surface = dri2_x11_create_window_surface,1167.create_pixmap_surface = dri2_x11_create_pixmap_surface,1168.create_pbuffer_surface = dri2_x11_create_pbuffer_surface,1169.destroy_surface = dri2_x11_destroy_surface,1170.create_image = dri2_create_image_khr,1171.swap_buffers = dri2_x11_swap_buffers,1172/* XXX: should really implement this since X11 has pixmaps */1173.query_surface = dri2_query_surface,1174.get_dri_drawable = dri2_surface_get_dri_drawable,1175};11761177static const struct dri2_egl_display_vtbl dri2_x11_display_vtbl = {1178.authenticate = dri2_x11_authenticate,1179.create_window_surface = dri2_x11_create_window_surface,1180.create_pixmap_surface = dri2_x11_create_pixmap_surface,1181.create_pbuffer_surface = dri2_x11_create_pbuffer_surface,1182.destroy_surface = dri2_x11_destroy_surface,1183.create_image = dri2_x11_create_image_khr,1184.swap_interval = dri2_x11_swap_interval,1185.swap_buffers = dri2_x11_swap_buffers,1186.swap_buffers_region = dri2_x11_swap_buffers_region,1187.post_sub_buffer = dri2_x11_post_sub_buffer,1188.copy_buffers = dri2_x11_copy_buffers,1189.query_surface = dri2_query_surface,1190.get_sync_values = dri2_x11_get_sync_values,1191.get_dri_drawable = dri2_surface_get_dri_drawable,1192};11931194static const __DRIswrastLoaderExtension swrast_loader_extension = {1195.base = { __DRI_SWRAST_LOADER, 1 },11961197.getDrawableInfo = swrastGetDrawableInfo,1198.putImage = swrastPutImage,1199.getImage = swrastGetImage,1200};12011202static const __DRIextension *swrast_loader_extensions[] = {1203&swrast_loader_extension.base,1204&image_lookup_extension.base,1205NULL,1206};12071208static int1209dri2_find_screen_for_display(const _EGLDisplay *disp, int fallback_screen)1210{1211const EGLAttrib *attr;12121213if (!disp->Options.Attribs)1214return fallback_screen;12151216for (attr = disp->Options.Attribs; attr[0] != EGL_NONE; attr += 2) {1217if (attr[0] == EGL_PLATFORM_X11_SCREEN_EXT ||1218attr[0] == EGL_PLATFORM_XCB_SCREEN_EXT)1219return attr[1];1220}12211222return fallback_screen;1223}12241225static EGLBoolean1226dri2_get_xcb_connection(_EGLDisplay *disp,1227struct dri2_egl_display *dri2_dpy)1228{1229xcb_screen_iterator_t s;1230int screen;1231const char *msg;12321233disp->DriverData = (void *) dri2_dpy;1234if (disp->PlatformDisplay == NULL) {1235dri2_dpy->conn = xcb_connect(NULL, &screen);1236dri2_dpy->own_device = true;1237screen = dri2_find_screen_for_display(disp, screen);1238} else if (disp->Platform == _EGL_PLATFORM_X11) {1239Display *dpy = disp->PlatformDisplay;1240dri2_dpy->conn = XGetXCBConnection(dpy);1241screen = DefaultScreen(dpy);1242} else {1243/* _EGL_PLATFORM_XCB */1244dri2_dpy->conn = disp->PlatformDisplay;1245screen = dri2_find_screen_for_display(disp, 0);1246}12471248if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) {1249msg = "xcb_connect failed";1250goto disconnect;1251}12521253s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));1254dri2_dpy->screen = get_xcb_screen(s, screen);1255if (!dri2_dpy->screen) {1256msg = "failed to get xcb screen";1257goto disconnect;1258}12591260return EGL_TRUE;1261disconnect:1262if (disp->PlatformDisplay == NULL)1263xcb_disconnect(dri2_dpy->conn);12641265return _eglError(EGL_BAD_ALLOC, msg);1266}12671268static EGLBoolean1269dri2_initialize_x11_swrast(_EGLDisplay *disp)1270{1271_EGLDevice *dev;1272struct dri2_egl_display *dri2_dpy;12731274dri2_dpy = calloc(1, sizeof *dri2_dpy);1275if (!dri2_dpy)1276return _eglError(EGL_BAD_ALLOC, "eglInitialize");12771278dri2_dpy->fd = -1;1279if (!dri2_get_xcb_connection(disp, dri2_dpy))1280goto cleanup;12811282dev = _eglAddDevice(dri2_dpy->fd, true);1283if (!dev) {1284_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");1285goto cleanup;1286}12871288disp->Device = dev;12891290/*1291* Every hardware driver_name is set using strdup. Doing the same in1292* here will allow is to simply free the memory at dri2_terminate().1293*/1294dri2_dpy->driver_name = strdup("swrast");1295if (!dri2_load_driver_swrast(disp))1296goto cleanup;12971298dri2_dpy->loader_extensions = swrast_loader_extensions;12991300if (!dri2_create_screen(disp))1301goto cleanup;13021303if (!dri2_setup_extensions(disp))1304goto cleanup;13051306dri2_setup_screen(disp);13071308if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true))1309goto cleanup;13101311/* Fill vtbl last to prevent accidentally calling virtual function during1312* initialization.1313*/1314dri2_dpy->vtbl = &dri2_x11_swrast_display_vtbl;13151316return EGL_TRUE;13171318cleanup:1319dri2_display_destroy(disp);1320return EGL_FALSE;1321}13221323static void1324dri2_x11_setup_swap_interval(_EGLDisplay *disp)1325{1326struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);1327int arbitrary_max_interval = 1000;13281329/* default behavior for no SwapBuffers support: no vblank syncing1330* either.1331*/1332dri2_dpy->min_swap_interval = 0;1333dri2_dpy->max_swap_interval = 0;1334dri2_dpy->default_swap_interval = 0;13351336if (!dri2_dpy->swap_available)1337return;13381339/* If we do have swapbuffers, then we can support pretty much any swap1340* interval.1341*/1342dri2_setup_swap_interval(disp, arbitrary_max_interval);1343}13441345#ifdef HAVE_DRI313461347static const __DRIextension *dri3_image_loader_extensions[] = {1348&dri3_image_loader_extension.base,1349&image_lookup_extension.base,1350&use_invalidate.base,1351&background_callable_extension.base,1352NULL,1353};13541355static EGLBoolean1356dri2_initialize_x11_dri3(_EGLDisplay *disp)1357{1358_EGLDevice *dev;1359struct dri2_egl_display *dri2_dpy;13601361dri2_dpy = calloc(1, sizeof *dri2_dpy);1362if (!dri2_dpy)1363return _eglError(EGL_BAD_ALLOC, "eglInitialize");13641365dri2_dpy->fd = -1;1366if (!dri2_get_xcb_connection(disp, dri2_dpy))1367goto cleanup;13681369if (!dri3_x11_connect(dri2_dpy))1370goto cleanup;13711372dev = _eglAddDevice(dri2_dpy->fd, false);1373if (!dev) {1374_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");1375goto cleanup;1376}13771378disp->Device = dev;13791380if (!dri2_load_driver_dri3(disp))1381goto cleanup;13821383dri2_dpy->loader_extensions = dri3_image_loader_extensions;13841385dri2_dpy->swap_available = true;1386dri2_dpy->invalidate_available = true;13871388if (!dri2_create_screen(disp))1389goto cleanup;13901391if (!dri2_setup_extensions(disp))1392goto cleanup;13931394dri2_setup_screen(disp);13951396dri2_x11_setup_swap_interval(disp);13971398if (!dri2_dpy->is_different_gpu)1399disp->Extensions.KHR_image_pixmap = EGL_TRUE;1400disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;1401disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;1402disp->Extensions.EXT_buffer_age = EGL_TRUE;1403disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;14041405dri2_set_WL_bind_wayland_display(disp);14061407if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false))1408goto cleanup;14091410dri2_dpy->loader_dri3_ext.core = dri2_dpy->core;1411dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver;1412dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush;1413dri2_dpy->loader_dri3_ext.tex_buffer = dri2_dpy->tex_buffer;1414dri2_dpy->loader_dri3_ext.image = dri2_dpy->image;1415dri2_dpy->loader_dri3_ext.config = dri2_dpy->config;14161417/* Fill vtbl last to prevent accidentally calling virtual function during1418* initialization.1419*/1420dri2_dpy->vtbl = &dri3_x11_display_vtbl;14211422_eglLog(_EGL_INFO, "Using DRI3");14231424return EGL_TRUE;14251426cleanup:1427dri2_display_destroy(disp);1428return EGL_FALSE;1429}1430#endif14311432static const __DRIdri2LoaderExtension dri2_loader_extension_old = {1433.base = { __DRI_DRI2_LOADER, 2 },14341435.getBuffers = dri2_x11_get_buffers,1436.flushFrontBuffer = dri2_x11_flush_front_buffer,1437.getBuffersWithFormat = NULL,1438};14391440static const __DRIdri2LoaderExtension dri2_loader_extension = {1441.base = { __DRI_DRI2_LOADER, 3 },14421443.getBuffers = dri2_x11_get_buffers,1444.flushFrontBuffer = dri2_x11_flush_front_buffer,1445.getBuffersWithFormat = dri2_x11_get_buffers_with_format,1446};14471448static const __DRIextension *dri2_loader_extensions_old[] = {1449&dri2_loader_extension_old.base,1450&image_lookup_extension.base,1451&background_callable_extension.base,1452NULL,1453};14541455static const __DRIextension *dri2_loader_extensions[] = {1456&dri2_loader_extension.base,1457&image_lookup_extension.base,1458&use_invalidate.base,1459&background_callable_extension.base,1460NULL,1461};14621463static EGLBoolean1464dri2_initialize_x11_dri2(_EGLDisplay *disp)1465{1466_EGLDevice *dev;1467struct dri2_egl_display *dri2_dpy;14681469dri2_dpy = calloc(1, sizeof *dri2_dpy);1470if (!dri2_dpy)1471return _eglError(EGL_BAD_ALLOC, "eglInitialize");14721473dri2_dpy->fd = -1;1474if (!dri2_get_xcb_connection(disp, dri2_dpy))1475goto cleanup;14761477if (!dri2_x11_connect(dri2_dpy))1478goto cleanup;14791480dev = _eglAddDevice(dri2_dpy->fd, false);1481if (!dev) {1482_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");1483goto cleanup;1484}14851486disp->Device = dev;14871488if (!dri2_load_driver(disp))1489goto cleanup;14901491if (dri2_dpy->dri2_minor >= 1)1492dri2_dpy->loader_extensions = dri2_loader_extensions;1493else1494dri2_dpy->loader_extensions = dri2_loader_extensions_old;14951496dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);1497dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);14981499if (!dri2_create_screen(disp))1500goto cleanup;15011502if (!dri2_setup_extensions(disp))1503goto cleanup;15041505dri2_setup_screen(disp);15061507dri2_x11_setup_swap_interval(disp);15081509disp->Extensions.KHR_image_pixmap = EGL_TRUE;1510disp->Extensions.NOK_swap_region = EGL_TRUE;1511disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;1512disp->Extensions.NV_post_sub_buffer = EGL_TRUE;1513disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;15141515dri2_set_WL_bind_wayland_display(disp);15161517if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true))1518goto cleanup;15191520/* Fill vtbl last to prevent accidentally calling virtual function during1521* initialization.1522*/1523dri2_dpy->vtbl = &dri2_x11_display_vtbl;15241525_eglLog(_EGL_INFO, "Using DRI2");15261527return EGL_TRUE;15281529cleanup:1530dri2_display_destroy(disp);1531return EGL_FALSE;1532}15331534EGLBoolean1535dri2_initialize_x11(_EGLDisplay *disp)1536{1537if (disp->Options.ForceSoftware)1538return dri2_initialize_x11_swrast(disp);15391540#ifdef HAVE_DRI31541if (!env_var_as_boolean("LIBGL_DRI3_DISABLE", false))1542if (dri2_initialize_x11_dri3(disp))1543return EGL_TRUE;1544#endif15451546if (!env_var_as_boolean("LIBGL_DRI2_DISABLE", false))1547if (dri2_initialize_x11_dri2(disp))1548return EGL_TRUE;15491550return EGL_FALSE;1551}15521553void1554dri2_teardown_x11(struct dri2_egl_display *dri2_dpy)1555{1556if (dri2_dpy->own_device)1557xcb_disconnect(dri2_dpy->conn);1558}155915601561