[Mesa-dev] [PATCH RFC] egl/dri2: Add dri3 support to x11 platform
Boyan Ding
boyan.j.ding at gmail.com
Wed Jul 1 23:19:58 PDT 2015
2015-07-01 23:31 GMT+08:00 Boyan Ding <boyan.j.ding at gmail.com>:
> Signed-off-by: Boyan Ding <boyan.j.ding at 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"
> + 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)
> +{
> + 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);
>
I missed a return EGL_FALSE here. Have been fixed locally.
Boyan Ding
+ }
> + 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;
> __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;
> #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;
> };
>
> 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);
> }
>
> 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)
> +{
> + 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);
> + 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);
> }
>
> 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
> @@ -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 /**< */,
> + 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 /**< */)
> +{
> + 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;
> +}
> +
> +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 */
> +static int
> +dri3_authenticate(_EGLDisplay *disp, uint32_t id)
> +{
> + return 0;
> +}
> +
> +struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
> + .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);
> +
> + 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);
> + if (!dri2_dpy->device_name) {
> + _eglLog(_EGL_WARNING, "DRI2: Cannot find device name");
> + close(dri2_dpy->fd);
> + return EGL_FALSE;
> + }
> +
> + return EGL_TRUE;
> +}
> diff --git a/src/egl/drivers/dri2/platform_x11_dri3.h
> b/src/egl/drivers/dri2/platform_x11_dri3.h
> new file mode 100644
> index 0000000..efdfcdb
> --- /dev/null
> +++ b/src/egl/drivers/dri2/platform_x11_dri3.h
> @@ -0,0 +1,140 @@
> +/*
> + * 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.
> + */
> +
> +#ifndef EGL_X11_DRI3_INCLUDED
> +#define EGL_X11_DRI3_INCLUDED
> +
> +#include <stdbool.h>
> +#include <xcb/xcb.h>
> +#include <xcb/present.h>
> +
> +#include "egl_dri2.h"
> +
> +_EGL_DRIVER_TYPECAST(dri3_egl_surface, _EGLSurface, obj)
> +enum dri3_buffer_type {
> + dri3_buffer_back = 0,
> + dri3_buffer_front = 1
> +};
> +
> +struct dri3_buffer {
> + __DRIimage *image;
> + __DRIimage *linear_buffer;
> + uint32_t pixmap;
> +
> + /* Synchronization between the client and X server is done using an
> + * xshmfence that is mapped into an X server SyncFence. This lets the
> + * client check whether the X server is done using a buffer with a
> simple
> + * xshmfence call, rather than going to read X events from the wire.
> + *
> + * However, we can only wait for one xshmfence to be triggered at a
> time,
> + * so we need to know *which* buffer is going to be idle next. We do
> that
> + * by waiting for a PresentIdleNotify event. When that event arrives,
> the
> + * 'busy' flag gets cleared and the client knows that the fence has
> been
> + * triggered, and that the wait call will not block.
> + */
> +
> + uint32_t sync_fence; /* XID of X SyncFence object */
> + struct xshmfence *shm_fence; /* pointer to xshmfence object */
> + bool busy; /* Set on swap, cleared on IdleNotify */
> + bool own_pixmap; /* We allocated the pixmap ID, free on
> destroy */
> +
> + uint32_t size;
> + uint32_t pitch;
> + uint32_t cpp;
> + uint32_t flags;
> + uint32_t width, height;
> + uint64_t last_swap;
> +
> + enum dri3_buffer_type buffer_type;
> +};
> +
> +
> +#define DRI3_MAX_BACK 4
> +#define DRI3_BACK_ID(i) (i)
> +#define DRI3_FRONT_ID (DRI3_MAX_BACK)
> +
> +static inline int
> +dri3_pixmap_buf_id(enum dri3_buffer_type buffer_type)
> +{
> + if (buffer_type == dri3_buffer_back)
> + return DRI3_BACK_ID(0);
> + else
> + return DRI3_FRONT_ID;
> +}
> +
> +#define DRI3_NUM_BUFFERS (1 + DRI3_MAX_BACK)
> +
> +struct dri3_egl_surface {
> + _EGLSurface base;
> + __DRIdrawable *dri_drawable;
> + xcb_drawable_t drawable;
> + int depth;
> + uint8_t have_back;
> + uint8_t have_fake_front;
> + uint8_t is_pixmap;
> + uint8_t flipping;
> +
> + /* Present extension capabilities
> + */
> + uint32_t present_capabilities;
> +
> + /* SBC numbers are tracked by using the serial numbers
> + * in the present request and complete events
> + */
> + uint64_t send_sbc;
> + uint64_t recv_sbc;
> +
> + /* Last received UST/MSC values for pixmap present complete */
> + uint64_t ust, msc;
> +
> + /* Last received UST/MSC values from present notify msc event */
> + uint64_t notify_ust, notify_msc;
> +
> + /* Serial numbers for tracking wait_for_msc events */
> + uint32_t send_msc_serial;
> + uint32_t recv_msc_serial;
> +
> + struct dri3_buffer *buffers[DRI3_NUM_BUFFERS];
> + int cur_back;
> + int num_back;
> +
> + uint32_t *stamp;
> +
> + xcb_present_event_t eid;
> + xcb_gcontext_t gc;
> + xcb_special_event_t *special_event;
> +
> + /* LIBGL_SHOW_FPS support */
> + uint64_t previous_ust;
> + unsigned frames;
> +
> + bool first_init;
> +};
> +
> +extern const __DRIimageLoaderExtension dri3_image_loader_extension;
> +extern const __DRIsystemTimeExtension dri3_system_time_extension;
> +extern struct dri2_egl_display_vtbl dri3_x11_display_vtbl;
> +
> +EGLBoolean
> +dri3_x11_connect(struct dri2_egl_display *dri2_dpy);
> +
> +#endif
> --
> 2.4.4
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20150702/377e3174/attachment-0001.html>
More information about the mesa-dev
mailing list