Hi Boyan, Thank you for doing this ! A few suggestions which you might be interesting:
Considering that the backend has handled more than dri2 perhaps we can do a s/dri2/dri/ :-) That obviously is independent of your work. On 01/07/15 16:31, Boyan Ding wrote: > Signed-off-by: Boyan Ding <boyan.j.d...@gmail.com> > --- > configure.ac | 3 + > src/egl/drivers/dri2/Makefile.am | 5 + > src/egl/drivers/dri2/egl_dri2.c | 65 +- > src/egl/drivers/dri2/egl_dri2.h | 12 +- > src/egl/drivers/dri2/platform_x11.c | 127 ++- > src/egl/drivers/dri2/platform_x11_dri3.c | 1591 > ++++++++++++++++++++++++++++++ > src/egl/drivers/dri2/platform_x11_dri3.h | 140 +++ > 7 files changed, 1926 insertions(+), 17 deletions(-) > create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.c > create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.h > > diff --git a/configure.ac b/configure.ac > index af61aa2..090e6c9 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -1545,6 +1545,9 @@ if test "x$enable_egl" = xyes; then > if test "x$enable_shared_glapi" = xno; then > AC_MSG_ERROR([egl_dri2 requires --enable-shared-glapi]) > fi > + if test "x$enable_dri3" = xyes; then > + EGL_LIB_DEPS="$EGL_LIB_DEPS -lxcb-dri3 -lxcb-present > -lXxf86vm -lxshmfence -lxcb-sync" Neither one of these should be a direct -lfoo expression. We should check/use PKG_CHECK_MODULES and foo_{CFLAGS,LIBS}. > + fi > else > # Avoid building an "empty" libEGL. Drop/update this > # when other backends (haiku?) come along. > diff --git a/src/egl/drivers/dri2/Makefile.am > b/src/egl/drivers/dri2/Makefile.am > index 55be4a7..d5b511c 100644 > --- a/src/egl/drivers/dri2/Makefile.am > +++ b/src/egl/drivers/dri2/Makefile.am > @@ -52,6 +52,11 @@ if HAVE_EGL_PLATFORM_X11 > libegl_dri2_la_SOURCES += platform_x11.c > AM_CFLAGS += -DHAVE_X11_PLATFORM > AM_CFLAGS += $(XCB_DRI2_CFLAGS) > +if HAVE_DRI3 > +libegl_dri2_la_SOURCES += \ > + platform_x11_dri3.c \ > + platform_x11_dri3.h > +endif > endif > > if HAVE_EGL_PLATFORM_WAYLAND > diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c > index b1b65f7..052c579 100644 > --- a/src/egl/drivers/dri2/egl_dri2.c > +++ b/src/egl/drivers/dri2/egl_dri2.c > @@ -322,6 +322,12 @@ struct dri2_extension_match { > int offset; > }; > > +static struct dri2_extension_match dri3_driver_extensions[] = { > + { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) }, > + { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) > }, > + { NULL, 0, 0 } > +}; > + > static struct dri2_extension_match dri2_driver_extensions[] = { > { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) }, > { __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) }, > @@ -464,6 +470,24 @@ dri2_open_driver(_EGLDisplay *disp) > } > > EGLBoolean > +dri2_load_driver_dri3(_EGLDisplay *disp) dri3_load_driver perhaps ? > +{ > + struct dri2_egl_display *dri2_dpy = disp->DriverData; > + const __DRIextension **extensions; > + > + extensions = dri2_open_driver(disp); > + if (!extensions) > + return EGL_FALSE; > + > + if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions)) { > + dlclose(dri2_dpy->driver); > + } > + dri2_dpy->driver_extensions = extensions; > + > + return EGL_TRUE; > +} > + > +EGLBoolean > dri2_load_driver(_EGLDisplay *disp) > { > struct dri2_egl_display *dri2_dpy = disp->DriverData; > @@ -507,7 +531,9 @@ dri2_setup_screen(_EGLDisplay *disp) > struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); > unsigned int api_mask; > > - if (dri2_dpy->dri2) { > + if (dri2_dpy->image_driver) { > + api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen); > + } else if (dri2_dpy->dri2) { > api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen); > } else { > assert(dri2_dpy->swrast); > @@ -527,11 +553,12 @@ dri2_setup_screen(_EGLDisplay *disp) > if (api_mask & (1 << __DRI_API_GLES3)) > disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR; > > - assert(dri2_dpy->dri2 || dri2_dpy->swrast); > + assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast); > disp->Extensions.KHR_surfaceless_context = EGL_TRUE; > disp->Extensions.MESA_configless_context = EGL_TRUE; > > - if ((dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) || > + if (dri2_dpy->image_driver || > + (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) || > (dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) { > disp->Extensions.KHR_create_context = EGL_TRUE; > > @@ -591,7 +618,14 @@ dri2_create_screen(_EGLDisplay *disp) > > dri2_dpy = disp->DriverData; > > - if (dri2_dpy->dri2) { > + if (dri2_dpy->image_driver) { > + dri2_dpy->dri_screen = > + dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd, > + dri2_dpy->extensions, > + > dri2_dpy->driver_extensions, > + &dri2_dpy->driver_configs, > + disp); > + } else if (dri2_dpy->dri2) { > if (dri2_dpy->dri2->base.version >= 4) { > dri2_dpy->dri_screen = > dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd, > @@ -627,7 +661,7 @@ dri2_create_screen(_EGLDisplay *disp) > > extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen); > > - if (dri2_dpy->dri2) { > + if (dri2_dpy->image_driver || dri2_dpy->dri2) { > if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions)) > goto cleanup_dri_screen; > } else { > @@ -971,7 +1005,26 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, > _EGLConfig *conf, > else > dri_config = NULL; > > - if (dri2_dpy->dri2) { > + if (dri2_dpy->image_driver) { > + unsigned error; > + unsigned num_attribs = 8; > + uint32_t ctx_attribs[8]; > + > + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs, > + &num_attribs)) > + goto cleanup; > + > + dri2_ctx->dri_context = > + dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen, > + api, > + dri_config, > + shared, > + num_attribs / 2, > + ctx_attribs, > + & error, > + dri2_ctx); > + dri2_create_context_attribs_error(error); > + } else if (dri2_dpy->dri2) { > if (dri2_dpy->dri2->base.version >= 3) { > unsigned error; > unsigned num_attribs = 8; > diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h > index f0cc6da..d258753 100644 > --- a/src/egl/drivers/dri2/egl_dri2.h > +++ b/src/egl/drivers/dri2/egl_dri2.h > @@ -153,11 +153,16 @@ struct dri2_egl_display > > int dri2_major; > int dri2_minor; > + int dri3_major; > + int dri3_minor; > + int present_major; > + int present_minor; Many of these are unused. Same goes for the glx code which was the inspiration for this work :-) > __DRIscreen *dri_screen; > int own_dri_screen; > const __DRIconfig **driver_configs; > void *driver; > const __DRIcoreExtension *core; > + const __DRIimageDriverExtension *image_driver; > const __DRIdri2Extension *dri2; > const __DRIswrastExtension *swrast; > const __DRI2flushExtension *flush; > @@ -189,6 +194,7 @@ struct dri2_egl_display > #ifdef HAVE_X11_PLATFORM > xcb_connection_t *conn; > int screen; > + Display *dpy; If we only loved XF86VIDMODE and/or xcb a bit more we wouldn't need this :'-( > #endif > > #ifdef HAVE_WAYLAND_PLATFORM > @@ -202,8 +208,9 @@ struct dri2_egl_display > int formats; > uint32_t capabilities; > int is_render_node; > - int is_different_gpu; > #endif > + > + int is_different_gpu; This could be a separate patch. > }; > > struct dri2_egl_context > @@ -324,6 +331,9 @@ EGLBoolean > dri2_load_driver_swrast(_EGLDisplay *disp); > > EGLBoolean > +dri2_load_driver_dri3(_EGLDisplay *disp); > + > +EGLBoolean > dri2_create_screen(_EGLDisplay *disp); > > __DRIimage * > diff --git a/src/egl/drivers/dri2/platform_x11.c > b/src/egl/drivers/dri2/platform_x11.c > index ad40bd5..2ce260f 100644 > --- a/src/egl/drivers/dri2/platform_x11.c > +++ b/src/egl/drivers/dri2/platform_x11.c > @@ -45,6 +45,10 @@ > #include "egl_dri2_fallbacks.h" > #include "loader.h" > > +#ifdef HAVE_DRI3 > +#include "platform_x11_dri3.h" > +#endif > + > static EGLBoolean > dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, > EGLint interval); > @@ -1094,13 +1098,17 @@ dri2_initialize_x11_swrast(_EGLDriver *drv, > _EGLDisplay *disp) > > disp->DriverData = (void *) dri2_dpy; > if (disp->PlatformDisplay == NULL) { > - dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen); > + dri2_dpy->dpy = XOpenDisplay(NULL); > + > + dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy); > + dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy); > + > dri2_dpy->own_device = true; > } else { > - Display *dpy = disp->PlatformDisplay; > + dri2_dpy->dpy = disp->PlatformDisplay; > > - dri2_dpy->conn = XGetXCBConnection(dpy); > - dri2_dpy->screen = DefaultScreen(dpy); > + dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy); > + dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy); Why do we need this hunk ? > } > > if (xcb_connection_has_error(dri2_dpy->conn)) { > @@ -1202,6 +1210,94 @@ dri2_x11_setup_swap_interval(struct dri2_egl_display > *dri2_dpy) > } > } > > +#ifdef HAVE_DRI3 > +static EGLBoolean > +dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp) dri3_initialize_x11 ? > +{ > + struct dri2_egl_display *dri2_dpy; > + > + dri2_dpy = calloc(1, sizeof *dri2_dpy); > + if (!dri2_dpy) > + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); > + > + disp->DriverData = (void *) dri2_dpy; > + if (disp->PlatformDisplay == NULL) { > + dri2_dpy->dpy = XOpenDisplay(NULL); > + > + dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy); > + dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy); > + > + dri2_dpy->own_device = true; > + } else { > + dri2_dpy->dpy = disp->PlatformDisplay; > + > + dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy); > + dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy); > + } > + > + if (xcb_connection_has_error(dri2_dpy->conn)) { > + _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed"); > + goto cleanup_dpy; > + } > + > + if (dri2_dpy->conn) { > + if (!dri3_x11_connect(dri2_dpy)) > + goto cleanup_conn; > + } > + > + if (!dri2_load_driver_dri3(disp)) > + goto cleanup_conn; > + > + dri2_dpy->extensions[0] = &dri3_image_loader_extension.base; > + dri2_dpy->extensions[1] = &dri3_system_time_extension.base; > + dri2_dpy->extensions[2] = &use_invalidate.base; > + dri2_dpy->extensions[3] = &image_lookup_extension.base; > + dri2_dpy->extensions[4] = NULL; > + > + dri2_dpy->swap_available = true; > + dri2_dpy->invalidate_available = true; > + > + if (!dri2_create_screen(disp)) > + goto cleanup_fd; > + > + dri2_x11_setup_swap_interval(dri2_dpy); > + > + disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE; > + disp->Extensions.CHROMIUM_sync_control = EGL_TRUE; > + disp->Extensions.EXT_buffer_age = EGL_TRUE; > + > +#ifdef HAVE_WAYLAND_PLATFORM > + disp->Extensions.WL_bind_wayland_display = EGL_TRUE; > +#endif > + > + if (dri2_dpy->conn) { > + if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp)) > + goto cleanup_configs; > + } > + > + /* Fill vtbl last to prevent accidentally calling virtual function during > + * initialization. > + */ > + dri2_dpy->vtbl = &dri3_x11_display_vtbl; > + > + return EGL_TRUE; > + > + cleanup_configs: > + _eglCleanupDisplay(disp); > + dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); > + dlclose(dri2_dpy->driver); > + cleanup_fd: > + close(dri2_dpy->fd); > + cleanup_conn: > + if (disp->PlatformDisplay == NULL) > + xcb_disconnect(dri2_dpy->conn); Considering that we're using XOpenDisplay, the above should be XCloseDisplay ? > + cleanup_dpy: > + free(dri2_dpy); > + > + return EGL_FALSE; > +} > +#endif > + > static EGLBoolean > dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) > { > @@ -1213,13 +1309,17 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay > *disp) > > disp->DriverData = (void *) dri2_dpy; > if (disp->PlatformDisplay == NULL) { > - dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen); > + dri2_dpy->dpy = XOpenDisplay(NULL); > + > + dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy); > + dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy); > + > dri2_dpy->own_device = true; > } else { > - Display *dpy = disp->PlatformDisplay; > + dri2_dpy->dpy = disp->PlatformDisplay; > > - dri2_dpy->conn = XGetXCBConnection(dpy); > - dri2_dpy->screen = DefaultScreen(dpy); > + dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy); > + dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy); Don't think we need this hunk. > } > > if (xcb_connection_has_error(dri2_dpy->conn)) { > @@ -1321,9 +1421,16 @@ dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp) > int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL); > > if (x11_dri2_accel) { > - if (!dri2_initialize_x11_dri2(drv, disp)) { > - initialized = dri2_initialize_x11_swrast(drv, disp); > +#ifdef HAVE_DRI3 > + if (getenv("LIBGL_DRI3_ENABLE") == NULL || > + !dri2_initialize_x11_dri3(drv, disp)) { > +#endif > + if (!dri2_initialize_x11_dri2(drv, disp)) { > + initialized = dri2_initialize_x11_swrast(drv, disp); > + } > +#ifdef HAVE_DRI3 > } > +#endif > } else { > initialized = dri2_initialize_x11_swrast(drv, disp); > } > diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c > b/src/egl/drivers/dri2/platform_x11_dri3.c > new file mode 100644 > index 0000000..dcd7128 > --- /dev/null > +++ b/src/egl/drivers/dri2/platform_x11_dri3.c Considering that this is heavily based on the glx code I'm wondering if we can get some of that into some common helpers ? Something like src/loader/dri3_helper.[ch] perhaps. > @@ -0,0 +1,1591 @@ > +/* > + * Copyright © 2013 Keith Packard > + * > + * Permission to use, copy, modify, distribute, and sell this software and > its > + * documentation for any purpose is hereby granted without fee, provided that > + * the above copyright notice appear in all copies and that both that > copyright > + * notice and this permission notice appear in supporting documentation, and > + * that the name of the copyright holders not be used in advertising or > + * publicity pertaining to distribution of the software without specific, > + * written prior permission. The copyright holders make no representations > + * about the suitability of this software for any purpose. It is provided > "as > + * is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS > SOFTWARE, > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO > + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR > + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF > USE, > + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER > + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR > PERFORMANCE > + * OF THIS SOFTWARE. > + */ > + > +#include <fcntl.h> > +#include <stdbool.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <sys/time.h> > + > +#ifdef XF86VIDMODE > +#include <X11/extensions/xf86vmode.h> > +#endif > +#include <X11/xshmfence.h> > +#include <xcb/xcb.h> > +#include <xcb/dri3.h> > +#include <xcb/present.h> > +#include <xf86drm.h> > + > +#include "egl_dri2.h" > +#include "egl_dri2_fallbacks.h" > +#include "platform_x11_dri3.h" > + > +#include "loader.h" > + > +static inline void > +dri3_fence_reset(xcb_connection_t *c, struct dri3_buffer *buffer) > +{ > + xshmfence_reset(buffer->shm_fence); > +} > + > +static inline void > +dri3_fence_set(struct dri3_buffer *buffer) > +{ > + xshmfence_trigger(buffer->shm_fence); > +} > + > +static inline void > +dri3_fence_trigger(xcb_connection_t *c, struct dri3_buffer *buffer) > +{ > + xcb_sync_trigger_fence(c, buffer->sync_fence); > +} > + > +static inline void > +dri3_fence_await(xcb_connection_t *c, struct dri3_buffer *buffer) > +{ > + xcb_flush(c); > + xshmfence_await(buffer->shm_fence); > +} > + > +static void > +dri3_update_num_back(struct dri3_egl_surface *dri3_surf) > +{ > + dri3_surf->num_back = 1; > + if (dri3_surf->flipping) { > + if (!dri3_surf->is_pixmap && !(dri3_surf->present_capabilities & > XCB_PRESENT_CAPABILITY_ASYNC)) > + dri3_surf->num_back++; > + dri3_surf->num_back++; > + } > + if (dri3_surf->base.SwapInterval == 0) > + dri3_surf->num_back++; > +} > + > +/** dri3_free_render_buffer > + * > + * Free everything associated with one render buffer including pixmap, fence > + * stuff and the driver image > + */ > +static void > +dri3_free_render_buffer(struct dri2_egl_display *dri2_dpy, > + struct dri3_egl_surface *dri3_surf, > + struct dri3_buffer *buffer) > +{ > + if (buffer->own_pixmap) > + xcb_free_pixmap(dri2_dpy->conn, buffer->pixmap); > + xcb_sync_destroy_fence(dri2_dpy->conn, buffer->sync_fence); > + xshmfence_unmap_shm(buffer->shm_fence); > + (*dri2_dpy->image->destroyImage)(buffer->image); > + if (buffer->linear_buffer) > + (*dri2_dpy->image->destroyImage)(buffer->linear_buffer); > + free(buffer); > +} > + > +static EGLBoolean > +dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) > +{ > + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); > + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf); > + int i; > + > + (void) drv; > + > + if (!_eglPutSurface(surf)) > + return EGL_TRUE; > + > + (*dri2_dpy->core->destroyDrawable) (dri3_surf->dri_drawable); > + > + for (i = 0; i < DRI3_NUM_BUFFERS; i++) { > + if (dri3_surf->buffers[i]) > + dri3_free_render_buffer(dri2_dpy, dri3_surf, dri3_surf->buffers[i]); > + } > + > + if (dri3_surf->special_event) > + xcb_unregister_for_special_event(dri2_dpy->conn, > dri3_surf->special_event); > + free(surf); > + > + return EGL_TRUE; > +} > + > +static EGLBoolean > +dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, > + EGLint interval) > +{ > + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf); > + > + if (interval > surf->Config->MaxSwapInterval) > + interval = surf->Config->MaxSwapInterval; > + else if (interval < surf->Config->MinSwapInterval) > + interval = surf->Config->MinSwapInterval; > + > + dri3_surf->base.SwapInterval = interval; > + dri3_update_num_back(dri3_surf); > + > + return EGL_TRUE; > +} > + > +static xcb_screen_t * > +get_xcb_screen(xcb_screen_iterator_t iter, int screen) > +{ > + for (; iter.rem; --screen, xcb_screen_next(&iter)) > + if (screen == 0) > + return iter.data; > + > + return NULL; > +} > + > +/* xDrawable in glx maps to drawable here */ > +static _EGLSurface * > +dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, > + _EGLConfig *conf, void *native_surface, > + const EGLint *attrib_list) > +{ > + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); > + struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); > + struct dri3_egl_surface *dri3_surf; > + xcb_drawable_t drawable; > + xcb_get_geometry_cookie_t cookie; > + xcb_get_geometry_reply_t *reply; > + xcb_screen_iterator_t s; > + xcb_generic_error_t *error; > + xcb_screen_t *screen; > + GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; > + > + STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface)); > + drawable = (uintptr_t) native_surface; > + > + (void) drv; > + > + dri3_surf = calloc(1, sizeof *dri3_surf); > + if (!dri3_surf) { > + _eglError(EGL_BAD_ALLOC, "dri3_create_surface"); > + return NULL; > + } > + > + if (!_eglInitSurface(&dri3_surf->base, disp, type, conf, attrib_list)) > + goto cleanup_surf; > + > + if (type == EGL_PBUFFER_BIT) { > + s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); > + screen = get_xcb_screen(s, dri2_dpy->screen); > + if (!screen) { > + _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_create_surface"); > + goto cleanup_surf; > + } > + > + dri3_surf->drawable = xcb_generate_id(dri2_dpy->conn); > + xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize, > + dri3_surf->drawable, screen->root, > + dri3_surf->base.Width, dri3_surf->base.Height); > + } else { > + dri3_surf->drawable = drawable; > + } > + > + dri3_surf->base.SwapInterval = 1; /* default may be overridden below */ > + dri3_surf->have_back = 0; > + dri3_surf->have_fake_front = 0; > + dri3_surf->first_init = true; > + > + if (dri2_dpy->config) > + dri2_dpy->config->configQueryi(dri2_dpy->dri_screen, > + "vblank_mode", &vblank_mode); > + > + switch (vblank_mode) { > + case DRI_CONF_VBLANK_NEVER: > + case DRI_CONF_VBLANK_DEF_INTERVAL_0: > + dri3_surf->base.SwapInterval = 0; > + break; > + case DRI_CONF_VBLANK_DEF_INTERVAL_1: > + case DRI_CONF_VBLANK_ALWAYS_SYNC: > + default: > + dri3_surf->base.SwapInterval = 1; > + break; > + } > + > + dri3_update_num_back(dri3_surf); > + > + /* Create a new drawable */ > + dri3_surf->dri_drawable = > + (*dri2_dpy->image_driver->createNewDrawable) (dri2_dpy->dri_screen, > + type == EGL_WINDOW_BIT ? > + > dri2_conf->dri_double_config : > + > dri2_conf->dri_single_config, > + dri3_surf); > + > + if (!dri3_surf->dri_drawable) { > + _eglError(EGL_BAD_ALLOC, "dri3->createNewDrawable"); > + goto cleanup_pixmap; > + } > + > + if (type != EGL_PBUFFER_BIT) { > + cookie = xcb_get_geometry (dri2_dpy->conn, dri3_surf->drawable); > + reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error); > + if (reply == NULL || error != NULL) { > + _eglError(EGL_BAD_ALLOC, "xcb_get_geometry"); > + free(error); > + goto cleanup_dri_drawable; > + } > + > + dri3_surf->base.Width = reply->width; > + dri3_surf->base.Height = reply->height; > + dri3_surf->depth = reply->depth; > + free(reply); > + } > + > + /* > + * Make sure server has the same swap interval we do for the new > + * drawable. > + */ > + dri3_set_swap_interval(drv, disp, &dri3_surf->base, > + dri3_surf->base.SwapInterval); > + > + return &dri3_surf->base; > + > + cleanup_dri_drawable: > + dri2_dpy->core->destroyDrawable(dri3_surf->dri_drawable); > + cleanup_pixmap: > + if (type == EGL_PBUFFER_BIT) > + xcb_free_pixmap(dri2_dpy->conn, dri3_surf->drawable); > + cleanup_surf: > + free(dri3_surf); > + > + return NULL; > +} > + > +/** > + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). > + */ > +static _EGLSurface * > +dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, > + _EGLConfig *conf, void *native_window, > + const EGLint *attrib_list) > +{ > + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); > + _EGLSurface *surf; > + > + surf = dri3_create_surface(drv, disp, EGL_WINDOW_BIT, conf, > + native_window, attrib_list); > + if (surf != NULL) > + dri3_set_swap_interval(drv, disp, surf, > dri2_dpy->default_swap_interval); > + > + return surf; > +} > + > +static _EGLSurface * > +dri3_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, > + _EGLConfig *conf, void *native_pixmap, > + const EGLint *attrib_list) > +{ > + return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf, > + native_pixmap, attrib_list); > +} > + > +static _EGLSurface * > +dri3_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp, > + _EGLConfig *conf, const EGLint *attrib_list) > +{ > + return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf, > + XCB_WINDOW_NONE, attrib_list); > +} > + > +/* > + * Process one Present event > + */ > +static void > +dri3_handle_present_event(struct dri2_egl_display *dri2_dpy, > + struct dri3_egl_surface *dri3_surf, > + xcb_present_generic_event_t *ge) > +{ > + switch (ge->evtype) { > + case XCB_PRESENT_CONFIGURE_NOTIFY: { > + xcb_present_configure_notify_event_t *ce = (void *) ge; > + > + dri3_surf->base.Width = ce->width; > + dri3_surf->base.Height = ce->height; > + break; > + } > + case XCB_PRESENT_COMPLETE_NOTIFY: { > + xcb_present_complete_notify_event_t *ce = (void *) ge; > + > + /* Compute the processed SBC number from the received 32-bit serial > number merged > + * with the upper 32-bits of the sent 64-bit serial number while > checking for > + * wrap > + */ > + if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) { > + dri3_surf->recv_sbc = (dri3_surf->send_sbc & 0xffffffff00000000LL) > | ce->serial; > + if (dri3_surf->recv_sbc > dri3_surf->send_sbc) > + dri3_surf->recv_sbc -= 0x100000000; > + switch (ce->mode) { > + case XCB_PRESENT_COMPLETE_MODE_FLIP: > + dri3_surf->flipping = true; > + break; > + case XCB_PRESENT_COMPLETE_MODE_COPY: > + dri3_surf->flipping = false; > + break; > + } > + dri3_update_num_back(dri3_surf); > + > + /* > + if (psc->show_fps_interval) > + show_fps(priv, ce->ust); */ > + > + dri3_surf->ust = ce->ust; > + dri3_surf->msc = ce->msc; > + } else { > + dri3_surf->recv_msc_serial = ce->serial; > + dri3_surf->notify_ust = ce->ust; > + dri3_surf->notify_msc = ce->msc; > + } > + break; > + } > + case XCB_PRESENT_EVENT_IDLE_NOTIFY: { > + xcb_present_idle_notify_event_t *ie = (void *) ge; > + int b; > + > + for (b = 0; b < sizeof (dri3_surf->buffers) / sizeof > (dri3_surf->buffers[0]); b++) { > + struct dri3_buffer *buf = dri3_surf->buffers[b]; > + > + if (buf && buf->pixmap == ie->pixmap) { > + buf->busy = 0; > + if (dri3_surf->num_back <= b && b < DRI3_MAX_BACK) { > + dri3_free_render_buffer(dri2_dpy, dri3_surf, buf); > + dri3_surf->buffers[b] = NULL; > + } > + break; > + } > + } > + break; > + } > + } > + free(ge); > +} > + > +static bool > +dri3_wait_for_event(struct dri2_egl_display *dri2_dpy, > + struct dri3_egl_surface *dri3_surf) > +{ > + xcb_generic_event_t *ev; > + xcb_present_generic_event_t *ge; > + > + xcb_flush(dri2_dpy->conn); > + ev = xcb_wait_for_special_event(dri2_dpy->conn, dri3_surf->special_event); > + if (!ev) > + return false; > + ge = (void *) ev; > + dri3_handle_present_event(dri2_dpy, dri3_surf, ge); > + return true; > +} > + > +/** dri3_wait_for_msc > + * > + * Get the X server to send an event when the target msc/divisor/remainder is > + * reached. > + */ > +static EGLBoolean > +dri3_wait_for_msc(struct dri2_egl_display *dri2_dpy, > + struct dri3_egl_surface *dri3_surf, > + int64_t target_msc, int64_t divisor, int64_t remainder, > + int64_t *ust, int64_t *msc, int64_t *sbc) > +{ > + uint32_t msc_serial; > + > + msc_serial = ++dri3_surf->send_msc_serial; > + xcb_present_notify_msc(dri2_dpy->conn, > + dri3_surf->drawable, > + msc_serial, > + target_msc, > + divisor, > + remainder); > + > + xcb_flush(dri2_dpy->conn); > + > + /* Wait for the event */ > + if (dri3_surf->special_event) { > + while ((int32_t) (msc_serial - dri3_surf->recv_msc_serial) > 0) { > + if (!dri3_wait_for_event(dri2_dpy, dri3_surf)) > + return EGL_FALSE; > + } > + } > + > + *ust = dri3_surf->notify_ust; > + *msc = dri3_surf->notify_msc; > + *sbc = dri3_surf->recv_sbc; > + > + return EGL_TRUE; > +} > + > +static EGLBoolean > +dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface, > + EGLuint64KHR *ust, EGLuint64KHR *msc, > + EGLuint64KHR *sbc) > +{ > + struct dri2_egl_display *dri2_dpy = dri2_egl_display(display); > + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface); > + > + return dri3_wait_for_msc(dri2_dpy, dri3_surf, 0, 0, 0, ust, msc, sbc); > +} > + > +/** > + * Asks the driver to flush any queued work necessary for serializing with > the > + * X command stream, and optionally the slightly more strict requirement of > + * glFlush() equivalence (which would require flushing even if nothing had > + * been drawn to a window system framebuffer, for example). > + */ > +static void > +dri3_flush(struct dri2_egl_display *dri2_dpy, > + struct dri3_egl_surface *dri3_surf, > + unsigned flags, > + enum __DRI2throttleReason throttle_reason) > +{ > + _EGLContext *ctx = _eglGetCurrentContext(); > + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); > + > + if (dri2_ctx) > + (*dri2_dpy->flush->flush_with_flags)(dri2_ctx->dri_context, > + dri3_surf->dri_drawable, > + flags, throttle_reason); > +} > + > +static xcb_gcontext_t > +dri3_drawable_gc(struct dri2_egl_display *dri2_dpy, > + struct dri3_egl_surface *dri3_surf) > +{ > + if (!dri3_surf->gc) { > + uint32_t v = 0; > + xcb_create_gc(dri2_dpy->conn, > + (dri3_surf->gc = xcb_generate_id(dri2_dpy->conn)), > + dri3_surf->drawable, > + XCB_GC_GRAPHICS_EXPOSURES, > + &v); > + } > + return dri3_surf->gc; > +} > + > + > +static struct dri3_buffer * > +dri3_back_buffer(struct dri3_egl_surface *dri3_surf) > +{ > + return dri3_surf->buffers[DRI3_BACK_ID(dri3_surf->cur_back)]; > +} > + > +static struct dri3_buffer * > +dri3_fake_front_buffer(struct dri3_egl_surface *dri3_surf) > +{ > + return dri3_surf->buffers[DRI3_FRONT_ID]; > +} > + > +static void > +dri3_copy_area (xcb_connection_t *c /**< */, Please, no space between function name and opening bracket. > + xcb_drawable_t src_drawable /**< */, > + xcb_drawable_t dst_drawable /**< */, > + xcb_gcontext_t gc /**< */, > + int16_t src_x /**< */, > + int16_t src_y /**< */, > + int16_t dst_x /**< */, > + int16_t dst_y /**< */, > + uint16_t width /**< */, > + uint16_t height /**< */) Add some comments or just drop the "/**< */"s ? > +{ > + xcb_void_cookie_t cookie; > + > + cookie = xcb_copy_area_checked(c, > + src_drawable, > + dst_drawable, > + gc, > + src_x, > + src_y, > + dst_x, > + dst_y, > + width, > + height); > + xcb_discard_reply(c, cookie.sequence); > +} > + > +/** > + * Called by the driver when it needs to update the real front buffer with > the > + * contents of its fake front buffer. > + */ > +static void > +dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate) > +{ > +#if 0 > + struct glx_context *gc; > + struct dri3_drawable *pdraw = loaderPrivate; > + struct dri3_screen *psc; > + > + if (!pdraw) > + return; > + > + if (!pdraw->base.psc) > + return; > + > + psc = (struct dri3_screen *) pdraw->base.psc; > + > + (void) __glXInitialize(psc->base.dpy); > + > + gc = __glXGetCurrentContext(); > + > + dri3_flush(psc, pdraw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT); > + > + dri3_wait_gl(gc); > +#endif > + /* FIXME */ > + (void) driDrawable; > + (void) loaderPrivate; If we don't get to fixing this now, providing some feedback (printf(foo)) would be appreciated. Same goes for other stubbed functions. > +} > + > +static uint32_t > +dri3_cpp_for_format(uint32_t format) { > + switch (format) { > + case __DRI_IMAGE_FORMAT_R8: > + return 1; > + case __DRI_IMAGE_FORMAT_RGB565: > + case __DRI_IMAGE_FORMAT_GR88: > + return 2; > + case __DRI_IMAGE_FORMAT_XRGB8888: > + case __DRI_IMAGE_FORMAT_ARGB8888: > + case __DRI_IMAGE_FORMAT_ABGR8888: > + case __DRI_IMAGE_FORMAT_XBGR8888: > + case __DRI_IMAGE_FORMAT_XRGB2101010: > + case __DRI_IMAGE_FORMAT_ARGB2101010: > + case __DRI_IMAGE_FORMAT_SARGB8: > + return 4; > + case __DRI_IMAGE_FORMAT_NONE: > + default: > + return 0; > + } > +} > + > +/** dri3_alloc_render_buffer > + * > + * Use the driver createImage function to construct a __DRIimage, then > + * get a file descriptor for that and create an X pixmap from that > + * > + * Allocate an xshmfence for synchronization > + */ > +static struct dri3_buffer * > +dri3_alloc_render_buffer(struct dri2_egl_display *dri2_dpy, xcb_drawable_t > draw, > + unsigned int format, int width, int height, int > depth) > +{ > + struct dri3_buffer *buffer; > + __DRIimage *pixmap_buffer; > + xcb_pixmap_t pixmap; > + xcb_sync_fence_t sync_fence; > + struct xshmfence *shm_fence; > + int buffer_fd, fence_fd; > + int stride; > + > + /* Create an xshmfence object and > + * prepare to send that to the X server > + */ > + > + fence_fd = xshmfence_alloc_shm(); > + if (fence_fd < 0) { > + _eglLog(_EGL_WARNING, "DRI3 Fence object allocation failure %s\n", > strerror(errno)); > + return NULL; > + } > + shm_fence = xshmfence_map_shm(fence_fd); > + if (shm_fence == NULL) { > + _eglLog(_EGL_WARNING, "DRI3 Fence object map failure %s\n", > strerror(errno)); > + goto no_shm_fence; > + } > + > + /* Allocate the image from the driver > + */ > + buffer = calloc(1, sizeof (struct dri3_buffer)); > + if (!buffer) > + goto no_buffer; > + > + buffer->cpp = dri3_cpp_for_format(format); > + if (!buffer->cpp) { > + _eglLog(_EGL_WARNING, "DRI3 buffer format %d invalid\n", format); > + goto no_image; > + } > + > + if (!dri2_dpy->is_different_gpu) { > + buffer->image = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen, > + width, height, > + format, > + __DRI_IMAGE_USE_SHARE > | > + > __DRI_IMAGE_USE_SCANOUT, > + buffer); > + pixmap_buffer = buffer->image; > + > + if (!buffer->image) { > + _eglLog(_EGL_WARNING, "DRI3 gpu image creation failure\n"); > + goto no_image; > + } > + } else { > + buffer->image = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen, > + width, height, > + format, > + 0, > + buffer); > + > + if (!buffer->image) { > + _eglLog(_EGL_WARNING, "DRI3 other gpu image creation failure\n"); > + goto no_image; > + } > + > + buffer->linear_buffer = (*dri2_dpy->image->createImage) > (dri2_dpy->dri_screen, > + width, height, > + format, > + > __DRI_IMAGE_USE_SHARE | > + > __DRI_IMAGE_USE_LINEAR, > + buffer); > + pixmap_buffer = buffer->linear_buffer; > + > + if (!buffer->linear_buffer) { > + _eglLog(_EGL_WARNING, "DRI3 gpu linear image creation failure\n"); > + goto no_linear_buffer; > + } > + } > + > + /* X wants the stride, so ask the image for it > + */ > + if (!(*dri2_dpy->image->queryImage)(pixmap_buffer, > __DRI_IMAGE_ATTRIB_STRIDE, &stride)) { > + _eglLog(_EGL_WARNING, "DRI3 get image stride failed\n"); > + goto no_buffer_attrib; > + } > + > + buffer->pitch = stride; > + > + if (!(*dri2_dpy->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, > &buffer_fd)) { > + _eglLog(_EGL_WARNING, "DRI3 get image FD failed\n"); > + goto no_buffer_attrib; > + } > + > + xcb_dri3_pixmap_from_buffer(dri2_dpy->conn, > + (pixmap = xcb_generate_id(dri2_dpy->conn)), > + draw, > + buffer->size, > + width, height, buffer->pitch, > + depth, buffer->cpp * 8, > + buffer_fd); > + > + xcb_dri3_fence_from_fd(dri2_dpy->conn, > + pixmap, > + (sync_fence = xcb_generate_id(dri2_dpy->conn)), > + false, > + fence_fd); > + > + buffer->pixmap = pixmap; > + buffer->own_pixmap = true; > + buffer->sync_fence = sync_fence; > + buffer->shm_fence = shm_fence; > + buffer->width = width; > + buffer->height = height; > + > + /* Mark the buffer as idle > + */ > + dri3_fence_set(buffer); > + > + return buffer; > + > +no_buffer_attrib: > + (*dri2_dpy->image->destroyImage)(pixmap_buffer); > +no_linear_buffer: > + if (dri2_dpy->is_different_gpu) > + (*dri2_dpy->image->destroyImage)(buffer->image); > +no_image: > + free(buffer); > +no_buffer: > + xshmfence_unmap_shm(shm_fence); > +no_shm_fence: > + close(fence_fd); > + _eglLog(_EGL_WARNING, "DRI3 alloc_render_buffer failed\n"); > + return NULL; > +} > + > +/** dri3_flush_present_events > + * > + * Process any present events that have been received from the X server > + */ > +static void > +dri3_flush_present_events(struct dri2_egl_display *dri2_dpy, > + struct dri3_egl_surface *dri3_surf) > +{ > + /* Check to see if any configuration changes have occurred > + * since we were last invoked > + */ > + if (dri3_surf->special_event) { > + xcb_generic_event_t *ev; > + > + while ((ev = xcb_poll_for_special_event(dri2_dpy->conn, > + dri3_surf->special_event)) != > NULL) { > + xcb_present_generic_event_t *ge = (void *) ev; > + dri3_handle_present_event(dri2_dpy, dri3_surf, ge); > + } > + } > +} > + > +/** dri3_update_drawable > + * > + * Called the first time we use the drawable and then > + * after we receive present configure notify events to > + * track the geometry of the drawable > + */ > +static int > +dri3_update_drawable(__DRIdrawable *driDrawable, > + struct dri3_egl_surface *dri3_surf, > + struct dri2_egl_display *dri2_dpy) > +{ > + /* First time through, go get the current drawable geometry > + */ > + if (dri3_surf->first_init) { > + xcb_void_cookie_t cookie; > + xcb_generic_error_t *error; > + xcb_present_query_capabilities_cookie_t present_capabilities_cookie; > + xcb_present_query_capabilities_reply_t *present_capabilities_reply; > + > + dri3_surf->first_init = false; > + > + /* Try to select for input on the window. > + * > + * If the drawable is a window, this will get our events > + * delivered. > + * > + * Otherwise, we'll get a BadWindow error back from this request which > + * will let us know that the drawable is a pixmap instead. > + */ > + > + > + cookie = xcb_present_select_input_checked(dri2_dpy->conn, > + (dri3_surf->eid = > xcb_generate_id(dri2_dpy->conn)), > + dri3_surf->drawable, > + > XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY| > + > XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY| > + > XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); > + > + present_capabilities_cookie = > xcb_present_query_capabilities(dri2_dpy->conn, > + > dri3_surf->drawable); > + > + /* Create an XCB event queue to hold present events outside of the > usual > + * application event queue > + */ > + dri3_surf->special_event = xcb_register_for_special_xge(dri2_dpy->conn, > + > &xcb_present_id, > + dri3_surf->eid, > + > dri3_surf->stamp); > + > + dri3_surf->is_pixmap = false; > + > + /* Check to see if our select input call failed. If it failed with a > + * BadWindow error, then assume the drawable is a pixmap. Destroy the > + * special event queue created above and mark the drawable as a pixmap > + */ > + > + error = xcb_request_check(dri2_dpy->conn, cookie); > + > + present_capabilities_reply = > xcb_present_query_capabilities_reply(dri2_dpy->conn, > + > present_capabilities_cookie, > + > NULL); > + > + if (present_capabilities_reply) { > + dri3_surf->present_capabilities = > present_capabilities_reply->capabilities; > + free(present_capabilities_reply); > + } else > + dri3_surf->present_capabilities = 0; > + > + if (error) { > + if (error->error_code != BadWindow) { > + free(error); > + return false; > + } > + dri3_surf->is_pixmap = true; > + xcb_unregister_for_special_event(dri2_dpy->conn, > dri3_surf->special_event); > + dri3_surf->special_event = NULL; > + } > + } > + dri3_flush_present_events(dri2_dpy, dri3_surf); > + return true; > +} > + > +/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while > + * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid > + * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and > + * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds > + */ > +static int > +image_format_to_fourcc(int format) > +{ > + > + /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */ > + switch (format) { > + case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888; > + case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565; > + case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888; > + case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888; > + case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888; > + case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888; > + } > + return 0; > +} > + > +/** dri3_get_pixmap_buffer > + * > + * Get the DRM object for a pixmap from the X server and > + * wrap that with a __DRIimage structure using createImageFromFds > + */ > +static struct dri3_buffer * > +dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, > + unsigned int format, > + enum dri3_buffer_type buffer_type, > + struct dri3_egl_surface *dri3_surf, > + struct dri2_egl_display *dri2_dpy) > +{ > + int buf_id = > dri3_pixmap_buf_id(buffer_type); > + struct dri3_buffer *buffer = dri3_surf->buffers[buf_id]; > + xcb_drawable_t pixmap; > + xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie; > + xcb_dri3_buffer_from_pixmap_reply_t *bp_reply; > + int *fds; > + xcb_sync_fence_t sync_fence; > + struct xshmfence *shm_fence; > + int fence_fd; > + __DRIimage *image_planar; > + int stride, offset; > + > + if (buffer) > + return buffer; > + > + pixmap = dri3_surf->drawable; > + > + buffer = calloc(1, sizeof (struct dri3_buffer)); > + if (!buffer) > + goto no_buffer; > + > + fence_fd = xshmfence_alloc_shm(); > + if (fence_fd < 0) > + goto no_fence; > + shm_fence = xshmfence_map_shm(fence_fd); > + if (shm_fence == NULL) { > + close (fence_fd); > + goto no_fence; > + } > + > + xcb_dri3_fence_from_fd(dri2_dpy->conn, > + pixmap, > + (sync_fence = xcb_generate_id(dri2_dpy->conn)), > + false, > + fence_fd); > + > + /* Get an FD for the pixmap object > + */ > + bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, pixmap); > + bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn, > + bp_cookie, NULL); > + if (!bp_reply) > + goto no_image; > + fds = xcb_dri3_buffer_from_pixmap_reply_fds(dri2_dpy->conn, bp_reply); > + > + stride = bp_reply->stride; > + offset = 0; > + > + /* createImageFromFds creates a wrapper __DRIimage structure which > + * can deal with multiple planes for things like Yuv images. So, once > + * we've gotten the planar wrapper, pull the single plane out of it and > + * discard the wrapper. > + */ > + image_planar = (*dri2_dpy->image->createImageFromFds) > (dri2_dpy->dri_screen, > + bp_reply->width, > + bp_reply->height, > + > image_format_to_fourcc(format), > + fds, 1, > + &stride, &offset, > buffer); > + close(fds[0]); > + if (!image_planar) > + goto no_image; > + > + buffer->image = (*dri2_dpy->image->fromPlanar)(image_planar, 0, buffer); > + > + (*dri2_dpy->image->destroyImage)(image_planar); > + > + if (!buffer->image) > + goto no_image; > + > + buffer->pixmap = pixmap; > + buffer->own_pixmap = false; > + buffer->width = bp_reply->width; > + buffer->height = bp_reply->height; > + buffer->buffer_type = buffer_type; > + buffer->shm_fence = shm_fence; > + buffer->sync_fence = sync_fence; > + > + dri3_surf->buffers[buf_id] = buffer; > + return buffer; > + > +no_image: > + xcb_sync_destroy_fence(dri2_dpy->conn, sync_fence); > + xshmfence_unmap_shm(shm_fence); > +no_fence: > + free(buffer); > +no_buffer: > + return NULL; > +} > + > +/** dri3_find_back > + * > + * Find an idle back buffer. If there isn't one, then > + * wait for a present idle notify event from the X server > + */ > +static int > +dri3_find_back(struct dri2_egl_display *dri2_dpy, > + struct dri3_egl_surface *dri3_surf) > +{ > + int b; > + xcb_generic_event_t *ev; > + xcb_present_generic_event_t *ge; > + > + for (;;) { > + for (b = 0; b < dri3_surf->num_back; b++) { > + int id = DRI3_BACK_ID((b + dri3_surf->cur_back) % > dri3_surf->num_back); > + struct dri3_buffer *buffer = dri3_surf->buffers[id]; > + > + if (!buffer || !buffer->busy) { > + dri3_surf->cur_back = id; > + return id; > + } > + } > + xcb_flush(dri2_dpy->conn); > + ev = xcb_wait_for_special_event(dri2_dpy->conn, > dri3_surf->special_event); > + if (!ev) > + return -1; > + ge = (void *) ev; > + dri3_handle_present_event(dri2_dpy, dri3_surf, ge); > + } > +} > + > +/** dri3_get_buffer > + * > + * Find a front or back buffer, allocating new ones as necessary > + */ > +static struct dri3_buffer * > +dri3_get_buffer(__DRIdrawable *driDrawable, > + unsigned int format, > + enum dri3_buffer_type buffer_type, > + struct dri3_egl_surface *dri3_surf, > + struct dri2_egl_display *dri2_dpy) > +{ > + struct dri3_buffer *buffer; > + _EGLContext *ctx = _eglGetCurrentContext(); > + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); > + int buf_id; > + > + if (buffer_type == dri3_buffer_back) { > + buf_id = dri3_find_back(dri2_dpy, dri3_surf); > + > + if (buf_id < 0) > + return NULL; > + } else { > + buf_id = DRI3_FRONT_ID; > + } > + > + buffer = dri3_surf->buffers[buf_id]; > + > + /* Allocate a new buffer if there isn't an old one, or if that > + * old one is the wrong size > + */ > + if (!buffer || buffer->width != dri3_surf->base.Width || > + buffer->height != dri3_surf->base.Height) { > + struct dri3_buffer *new_buffer; > + > + /* Allocate the new buffers > + */ > + new_buffer = dri3_alloc_render_buffer(dri2_dpy, > + dri3_surf->drawable, > + format, > + dri3_surf->base.Width, > + dri3_surf->base.Height, > + dri3_surf->depth); > + if (!new_buffer) > + return NULL; > + > + /* When resizing, copy the contents of the old buffer, waiting for that > + * copy to complete using our fences before proceeding > + */ > + switch (buffer_type) { > + case dri3_buffer_back: > + if (buffer) { > + if (!buffer->linear_buffer) { > + dri3_fence_reset(dri2_dpy->conn, new_buffer); > + dri3_fence_await(dri2_dpy->conn, buffer); > + dri3_copy_area(dri2_dpy->conn, > + buffer->pixmap, > + new_buffer->pixmap, > + dri3_drawable_gc(dri2_dpy, dri3_surf), > + 0, 0, 0, 0, > + dri3_surf->base.Width, > + dri3_surf->base.Height); > + dri3_fence_trigger(dri2_dpy->conn, new_buffer); > + } else if (dri2_ctx->base.Resource.Display == > dri3_surf->base.Resource.Display) { > + dri2_dpy->image->blitImage(dri2_ctx->dri_context, > + new_buffer->image, > + buffer->image, > + 0, 0, dri3_surf->base.Width, > + dri3_surf->base.Height, > + 0, 0, dri3_surf->base.Width, > + dri3_surf->base.Height, 0); > + } > + dri3_free_render_buffer(dri2_dpy, dri3_surf, buffer); > + } > + break; > + case dri3_buffer_front: > + dri3_fence_reset(dri2_dpy->conn, new_buffer); > + dri3_copy_area(dri2_dpy->conn, > + dri3_surf->drawable, > + new_buffer->pixmap, > + dri3_drawable_gc(dri2_dpy, dri3_surf), > + 0, 0, 0, 0, > + dri3_surf->base.Width, > + dri3_surf->base.Height); > + dri3_fence_trigger(dri2_dpy->conn, new_buffer); > + > + if (new_buffer->linear_buffer && > + dri2_ctx->base.Resource.Display == > dri3_surf->base.Resource.Display) { > + dri3_fence_await(dri2_dpy->conn, new_buffer); > + dri2_dpy->image->blitImage(dri2_ctx->dri_context, > + new_buffer->image, > + new_buffer->linear_buffer, > + 0, 0, dri3_surf->base.Width, > + dri3_surf->base.Height, > + 0, 0, dri3_surf->base.Width, > + dri3_surf->base.Height, 0); > + } > + break; > + } > + buffer = new_buffer; > + buffer->buffer_type = buffer_type; > + dri3_surf->buffers[buf_id] = buffer; > + } > + dri3_fence_await(dri2_dpy->conn, buffer); > + > + /* Return the requested buffer */ > + return buffer; > +} > + > +/** dri3_free_buffers > + * > + * Free the front bufffer or all of the back buffers. Used > + * when the application changes which buffers it needs > + */ > +static void > +dri3_free_buffers(__DRIdrawable *driDrawable, > + enum dri3_buffer_type buffer_type, > + struct dri3_egl_surface *dri3_surf, > + struct dri2_egl_display *dri2_dpy) > +{ > + struct dri3_buffer *buffer; > + int first_id; > + int n_id; > + int buf_id; > + > + switch (buffer_type) { > + case dri3_buffer_back: > + first_id = DRI3_BACK_ID(0); > + n_id = DRI3_MAX_BACK; > + break; > + case dri3_buffer_front: > + first_id = DRI3_FRONT_ID; > + n_id = 1; > + } > + > + for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) { > + buffer = dri3_surf->buffers[buf_id]; > + if (buffer) { > + dri3_free_render_buffer(dri2_dpy, dri3_surf, buffer); > + dri3_surf->buffers[buf_id] = NULL; > + } > + } > +} > + > +/** dri3_get_buffers > + * > + * The published buffer allocation API. > + * Returns all of the necessary buffers, allocating > + * as needed. > + */ > +static int > +dri3_get_buffers(__DRIdrawable *driDrawable, > + unsigned int format, > + uint32_t *stamp, > + void *loaderPrivate, > + uint32_t buffer_mask, > + struct __DRIimageList *buffers) > +{ > + struct dri3_egl_surface *dri3_surf = loaderPrivate; > + struct dri2_egl_display *dri2_dpy = > + dri2_egl_display(dri3_surf->base.Resource.Display); > + struct dri3_buffer *front, *back; > + > + buffers->image_mask = 0; > + buffers->front = NULL; > + buffers->back = NULL; > + > + front = NULL; > + back = NULL; > + > + if (!dri3_update_drawable(driDrawable, dri3_surf, dri2_dpy)) > + return false; > + > + /* pixmaps always have front buffers */ > + if (dri3_surf->is_pixmap) > + buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; > + > + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { > + /* All pixmaps are owned by the server gpu. > + * When we use a different gpu, we can't use the pixmap > + * as buffer since it is potentially tiled a way > + * our device can't understand. In this case, use > + * a fake front buffer. Hopefully the pixmap > + * content will get synced with the fake front > + * buffer. > + */ > + if (dri3_surf->is_pixmap && !dri2_dpy->is_different_gpu) > + front = dri3_get_pixmap_buffer(driDrawable, > + format, > + dri3_buffer_front, > + dri3_surf, > + dri2_dpy); > + else > + front = dri3_get_buffer(driDrawable, > + format, > + dri3_buffer_front, > + dri3_surf, > + dri2_dpy); > + > + if (!front) > + return false; > + } else { > + dri3_free_buffers(driDrawable, dri3_buffer_front, dri3_surf, dri2_dpy); > + dri3_surf->have_fake_front = 0; > + } > + > + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { > + back = dri3_get_buffer(driDrawable, > + format, > + dri3_buffer_back, > + dri3_surf, > + dri2_dpy); > + if (!back) > + return false; > + dri3_surf->have_back = 1; > + } else { > + dri3_free_buffers(driDrawable, dri3_buffer_back, dri3_surf, dri2_dpy); > + dri3_surf->have_back = 0; > + } > + > + if (front) { > + buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; > + buffers->front = front->image; > + dri3_surf->have_fake_front = dri2_dpy->is_different_gpu || > !dri3_surf->is_pixmap; > + } > + > + if (back) { > + buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; > + buffers->back = back->image; > + } > + > + dri3_surf->stamp = stamp; > + > + return true; > +} > + > +const __DRIimageLoaderExtension dri3_image_loader_extension = { > + .base = { __DRI_IMAGE_LOADER, 1 }, > + > + .getBuffers = dri3_get_buffers, > + .flushFrontBuffer = dri3_flush_front_buffer, > +}; > + > +static int > +dri3_get_ust(int64_t *ust) > +{ > + struct timeval tv; > + > + if (ust == NULL) > + return -EFAULT; > + > + if (gettimeofday(&tv, NULL) == 0) { > + ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec; > + return 0; > + } else > + return -errno; > +} > + > +static GLboolean > +dri3_get_msc_rate(__DRIdrawable *draw, int32_t *numerator, > + int32_t *denominator, void *loaderPrivate) > +{ > +#ifdef XF86VIDMODE > + dri3_egl_surface *dri3_surf = loaderPrivate; > + struct dri2_egl_display *dri2_dpy = > + dri2_egl_display(dri3_surf->base.Resource.Display); > + XF86VidModeModeLine mode_line; > + int dot_clock; > + int i; > + > + if (XF86VidModeQueryVersion(dri2_dpy->dpy, &i, &i) && > + XF86VidModeGetModeLine(dri2_dpy->dpy, dri2_dpy->screen, > + &dot_clock, &mode_line)) { > + unsigned n = dot_clock * 1000; > + unsigned d = mode_line.vtotal * mode_line.htotal; > + > +# define V_INTERLACE 0x010 > +# define V_DBLSCAN 0x020 > + > + if (mode_line.flags & V_INTERLACE) > + n *= 2; > + else if (mode_line.flags & V_DBLSCAN) > + d *= 2; > + > + /* The OML_sync_control spec requires that if the refresh rate is a > + * whole number, that the returned numerator be equal to the refresh > + * rate and the denominator be 1. > + */ > + > + if (n % d == 0) { > + n /= d; > + d = 1; > + } > + else { > + static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 }; > + > + /* This is a poor man's way to reduce a fraction. It's far from > + * perfect, but it will work well enough for this situation. > + */ > + > + for (i = 0; f[i] != 0; i++) { > + while (n % f[i] == 0 && d % f[i] == 0) { > + d /= f[i]; > + n /= f[i]; > + } > + } > + } > + > + *numerator = n; > + *denominator = d; > + > + return True; > + > +#endif > + return False; > +} > + > +const __DRIsystemTimeExtension dri3_system_time_extension = { > + .base = { __DRI_SYSTEM_TIME, 1 }, > + > + .getUST = dri3_get_ust, > + .getMSCRate = dri3_get_msc_rate, > +}; > + > +/** dri3_swap_buffers_msc > + * > + * Make the current back buffer visible using the present extension > + */ > +static int64_t > +dri3_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw, > + int64_t target_msc, int64_t divisor, > + int64_t remainder) > +{ > + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw); > + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); > + struct dri3_buffer *back; > + _EGLContext *ctx = _eglGetCurrentContext(); > + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); > + int64_t ret = 0; > + uint32_t options = XCB_PRESENT_OPTION_NONE; > + > + dri2_flush_drawable_for_swapbuffers(disp, draw); > + > + back = dri3_surf->buffers[DRI3_BACK_ID(dri3_surf->cur_back)]; > + if (dri2_dpy->is_different_gpu && back) { > + /* Update the linear buffer before presenting the pixmap */ > + dri2_dpy->image->blitImage(dri2_ctx->dri_context, > + back->linear_buffer, > + back->image, > + 0, 0, back->width, > + back->height, > + 0, 0, back->width, > + back->height, __BLIT_FLAG_FLUSH); > + /* Update the fake front */ > + if (dri3_surf->have_fake_front) > + dri2_dpy->image->blitImage(dri2_ctx->dri_context, > + dri3_surf->buffers[DRI3_FRONT_ID]->image, > + back->image, > + 0, 0, dri3_surf->base.Width, > + dri3_surf->base.Height, > + 0, 0, dri3_surf->base.Width, > + dri3_surf->base.Height, > + __BLIT_FLAG_FLUSH); > + } > + > + dri3_flush_present_events(dri2_dpy, dri3_surf); > + > + if (back && !dri3_surf->is_pixmap) { > + dri3_fence_reset(dri2_dpy->conn, back); > + > + /* Compute when we want the frame shown by taking the last known > successful > + * MSC and adding in a swap interval for each outstanding swap request. > + * target_msc=divisor=remainder=0 means "Use glXSwapBuffers() semantic" > + */ > + ++dri3_surf->send_sbc; > + if (target_msc == 0 && divisor == 0 && remainder == 0) > + target_msc = dri3_surf->msc + dri3_surf->base.SwapInterval * > (dri3_surf->send_sbc - dri3_surf->recv_sbc); > + else if (divisor == 0 && remainder > 0) { > + /* > + * "If <divisor> = 0, the swap will occur when MSC becomes > + * greater than or equal to <target_msc>." > + * > + * Note that there's no mention of the remainder. The Present > extension > + * throws BadValue for remainder != 0 with divisor == 0, so just > drop > + * the passed in value. > + */ > + remainder = 0; > + } > + > + /* From the EGL 1.4 spec (page 53): > + * > + * "If <interval> is set to a value of 0, buffer swaps are not > + * synchronized to a video frame." > + * > + * Implementation note: It is possible to enable triple buffering > behaviour > + * by not using XCB_PRESENT_OPTION_ASYNC, but this should not be the > default. > + */ > + if (dri3_surf->base.SwapInterval == 0) > + options |= XCB_PRESENT_OPTION_ASYNC; > + > + back->busy = 1; > + back->last_swap = dri3_surf->send_sbc; > + xcb_present_pixmap(dri2_dpy->conn, > + dri3_surf->drawable, > + back->pixmap, > + (uint32_t) dri3_surf->send_sbc, > + 0, /* valid */ > + 0, /* update */ > + 0, /* x_off */ > + 0, /* y_off */ > + None, /* > target_crtc */ > + None, > + back->sync_fence, > + options, > + target_msc, > + divisor, > + remainder, 0, NULL); > + ret = (int64_t) dri3_surf->send_sbc; > + > + /* If there's a fake front, then copy the source back buffer > + * to the fake front to keep it up to date. This needs > + * to reset the fence and make future users block until > + * the X server is done copying the bits > + */ > + if (dri3_surf->have_fake_front && !dri2_dpy->is_different_gpu) { > + dri3_fence_reset(dri2_dpy->conn, dri3_surf->buffers[DRI3_FRONT_ID]); > + dri3_copy_area(dri2_dpy->conn, > + back->pixmap, > + dri3_surf->buffers[DRI3_FRONT_ID]->pixmap, > + dri3_drawable_gc(dri2_dpy, dri3_surf), > + 0, 0, 0, 0, > + dri3_surf->base.Width, > + dri3_surf->base.Height); > + dri3_fence_trigger(dri2_dpy->conn, > dri3_surf->buffers[DRI3_FRONT_ID]); > + } > + xcb_flush(dri2_dpy->conn); > + if (dri3_surf->stamp) > + ++(*dri3_surf->stamp); > + } > + > + (*dri2_dpy->flush->invalidate)(dri3_surf->dri_drawable); > + > + return ret; > +} > + > +static EGLBoolean > +dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) > +{ > + return dri3_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1; > +} > + > +static int > +dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) > +{ > + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); > + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf); > + int back_id = DRI3_BACK_ID(dri3_find_back(dri2_dpy, dri3_surf)); > + > + if (back_id < 0 || !dri3_surf->buffers[back_id]) > + return 0; > + > + if (dri3_surf->buffers[back_id]->last_swap != 0) > + return dri3_surf->send_sbc - dri3_surf->buffers[back_id]->last_swap + > 1; > + else > + return 0; > +} > + > +/* FIXME: Is this right? Seems problematic for WL_bind_wayland_display */ What seems to be the problem ? Afaik xcb_dri3_open_reply_fds should return an FD which is ok (be that a render_node device, or a master one with explicit auth). > +static int > +dri3_authenticate(_EGLDisplay *disp, uint32_t id) > +{ > + return 0; > +} > + > +struct dri2_egl_display_vtbl dri3_x11_display_vtbl = { static ? > + .authenticate = dri3_authenticate, > + .create_window_surface = dri3_create_window_surface, > + .create_pixmap_surface = dri3_create_pixmap_surface, > + .create_pbuffer_surface = dri3_create_pbuffer_surface, > + .destroy_surface = dri3_destroy_surface, > + .create_image = dri2_create_image_khr, > + .swap_interval = dri3_set_swap_interval, > + .swap_buffers = dri3_swap_buffers, > + .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage, > + .swap_buffers_region = dri2_fallback_swap_buffers_region, > + .post_sub_buffer = dri2_fallback_post_sub_buffer, > + .copy_buffers = dri2_fallback_copy_buffers, > + .query_buffer_age = dri3_query_buffer_age, > + .create_wayland_buffer_from_image = > dri2_fallback_create_wayland_buffer_from_image, > + .get_sync_values = dri3_get_sync_values, > +}; > + > +/** dri3_open > + * > + * Wrapper around xcb_dri3_open > + */ > +static int > +dri3_open(xcb_connection_t *conn, > + xcb_window_t root, > + uint32_t provider) > +{ > + xcb_dri3_open_cookie_t cookie; > + xcb_dri3_open_reply_t *reply; > + int fd; > + > + cookie = xcb_dri3_open(conn, > + root, > + provider); > + > + reply = xcb_dri3_open_reply(conn, cookie, NULL); > + if (!reply) > + return -1; > + > + if (reply->nfd != 1) { > + free(reply); > + return -1; > + } > + > + fd = xcb_dri3_open_reply_fds(conn, reply)[0]; > + fcntl(fd, F_SETFD, FD_CLOEXEC); I do recall looking at this (in src/glx) and wondering... aren't we missing fcntl(F_GETFD) ? > + > + return fd; > +} > + > +EGLBoolean > +dri3_x11_connect(struct dri2_egl_display *dri2_dpy) > +{ > + xcb_dri3_query_version_reply_t *dri3_query; > + xcb_dri3_query_version_cookie_t dri3_query_cookie; > + xcb_present_query_version_reply_t *present_query; > + xcb_present_query_version_cookie_t present_query_cookie; > + xcb_generic_error_t *error; > + xcb_screen_iterator_t s; > + xcb_screen_t *screen; > + const xcb_query_extension_reply_t *extension; > + > + xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id); > + xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id); > + > + extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id); > + if (!(extension && extension->present)) > + return EGL_FALSE; > + > + extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id); > + if (!(extension && extension->present)) > + return EGL_FALSE; > + > + dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn, > + XCB_DRI3_MAJOR_VERSION, > + XCB_DRI3_MINOR_VERSION); > + > + present_query_cookie = xcb_present_query_version(dri2_dpy->conn, > + > XCB_PRESENT_MAJOR_VERSION, > + > XCB_PRESENT_MINOR_VERSION); > + > + /* FIXME: a little bit memory leak here */ > + dri3_query = > + xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, > &error); > + if (dri3_query == NULL || error != NULL) { > + _eglLog(_EGL_WARNING, "DRI2: failed to query dri3 version"); > + free(error); > + return EGL_FALSE; > + } > + dri2_dpy->dri3_major = dri3_query->major_version; > + dri2_dpy->dri3_minor = dri3_query->minor_version; > + free(dri3_query); > + > + present_query = > + xcb_present_query_version_reply(dri2_dpy->conn, > + present_query_cookie, &error); > + if (present_query == NULL || error != NULL) { > + _eglLog(_EGL_WARNING, "DRI2: failed to query Present version"); > + free(error); > + return EGL_FALSE; > + } > + dri2_dpy->present_major = present_query->major_version; > + dri2_dpy->present_minor = present_query->minor_version; > + free(present_query); > + > + s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); > + screen = get_xcb_screen(s, dri2_dpy->screen); > + if (!screen) { > + _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_x11_connect"); > + return EGL_FALSE; > + } > + > + dri2_dpy->fd = dri3_open(dri2_dpy->conn, screen->root, 0); > + if (dri2_dpy->fd < 0) { > + int conn_error = xcb_connection_has_error(dri2_dpy->conn); > + _eglLog(_EGL_WARNING, "DRI2: Screen seem not DRI3 capable"); > + > + if (conn_error) > + _eglLog(_EGL_WARNING, "DRI2: Failed to initialize DRI3"); > + > + return EGL_FALSE; > + } > + > + dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, > &dri2_dpy->is_different_gpu); > + > + dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0); > + if (!dri2_dpy->driver_name) { > + _eglLog(_EGL_WARNING, "DRI2: No driver found"); > + close(dri2_dpy->fd); > + return EGL_FALSE; > + } > + > + dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd); Seems like wayland_drm_init is the only user of device_name in the whole of EGL. Wondering if it'll be worth keeping it wayland specific and ripping it out of platform_{drm,x11}. Cheers, Emil _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev