egl/x11_dri3: enable & require xfixes 2.0
[mesa.git] / src / egl / drivers / dri2 / platform_x11_dri3.c
index de60e952da872b5ffcf310c5ef8f7a84f631d39a..5c69a3b981e4a0f50ad9c82fccaddc9ce5cb3fd8 100644 (file)
 #include <xcb/xcb.h>
 #include <xcb/dri3.h>
 #include <xcb/present.h>
+#include <xcb/xfixes.h>
 
 #include <xf86drm.h>
 #include "util/macros.h"
 
 #include "egl_dri2.h"
-#include "egl_dri2_fallbacks.h"
 #include "platform_x11_dri3.h"
 
 #include "loader.h"
 #include "loader_dri3_helper.h"
 
-static uint32_t
-dri3_format_for_depth(uint32_t depth)
-{
-   switch (depth) {
-   case 16:
-      return __DRI_IMAGE_FORMAT_RGB565;
-   case 24:
-      return __DRI_IMAGE_FORMAT_XRGB8888;
-   case 30:
-      return __DRI_IMAGE_FORMAT_XRGB2101010;
-   case 32:
-      return __DRI_IMAGE_FORMAT_ARGB8888;
-   default:
-      return __DRI_IMAGE_FORMAT_NONE;
-   }
-}
-
 static struct dri3_egl_surface *
 loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw) {
    size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);
@@ -122,14 +105,17 @@ static const struct loader_dri3_vtable egl_dri3_vtable = {
 };
 
 static EGLBoolean
-dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
+dri3_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
 {
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
-
-   (void) drv;
+   xcb_drawable_t drawable = dri3_surf->loader_drawable.drawable;
 
    loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
 
+   if (surf->Type == EGL_PBUFFER_BIT)
+      xcb_free_pixmap (dri2_dpy->conn, drawable);
+
    dri2_fini_surface(surf);
    free(surf);
 
@@ -137,8 +123,7 @@ dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
 }
 
 static EGLBoolean
-dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
-                       EGLint interval)
+dri3_set_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
 {
    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
 
@@ -149,9 +134,8 @@ dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
 }
 
 static _EGLSurface *
-dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
-                    _EGLConfig *conf, void *native_surface,
-                    const EGLint *attrib_list)
+dri3_create_surface(_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);
@@ -159,15 +143,14 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
    const __DRIconfig *dri_config;
    xcb_drawable_t drawable;
 
-   (void) drv;
-
    dri3_surf = calloc(1, sizeof *dri3_surf);
    if (!dri3_surf) {
       _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
       return NULL;
    }
 
-   if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf, attrib_list, false))
+   if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf,
+                          attrib_list, false, native_surface))
       goto cleanup_surf;
 
    if (type == EGL_PBUFFER_BIT) {
@@ -183,6 +166,11 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
    dri_config = dri2_get_dri_config(dri2_conf, type,
                                     dri3_surf->surf.base.GLColorspace);
 
+   if (!dri_config) {
+      _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
+      goto cleanup_pixmap;
+   }
+
    if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
                                  dri2_dpy->dri_screen,
                                  dri2_dpy->is_different_gpu,
@@ -226,38 +214,36 @@ dri3_authenticate(_EGLDisplay *disp, uint32_t id)
 }
 
 /**
- * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
+ * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
  */
 static _EGLSurface *
-dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
-                           _EGLConfig *conf, void *native_window,
-                           const EGLint *attrib_list)
+dri3_create_window_surface(_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,
+   surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf,
                               native_window, attrib_list);
    if (surf != NULL)
-      dri3_set_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
+      dri3_set_swap_interval(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)
+dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
+                           void *native_pixmap, const EGLint *attrib_list)
 {
-   return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
+   return dri3_create_surface(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)
+dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
+                            const EGLint *attrib_list)
 {
-   return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
+   return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf,
                               NULL, attrib_list);
 }
 
@@ -293,7 +279,7 @@ dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
       return NULL;
    }
 
-   format = dri3_format_for_depth(bp_reply->depth);
+   format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
    if (format == __DRI_IMAGE_FORMAT_NONE) {
       _eglError(EGL_BAD_PARAMETER,
                 "dri3_create_image_khr: unsupported pixmap depth");
@@ -322,12 +308,12 @@ dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
    return &dri2_img->base;
 }
 
+#ifdef HAVE_DRI3_MODIFIERS
 static _EGLImage *
 dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
                                           EGLClientBuffer buffer,
                                           const EGLint *attr_list)
 {
-#ifdef HAVE_DRI3_MODIFIERS
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct dri2_egl_image *dri2_img;
    xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
@@ -345,7 +331,7 @@ dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
       return EGL_NO_IMAGE_KHR;
    }
 
-   format = dri3_format_for_depth(bp_reply->depth);
+   format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
    if (format == __DRI_IMAGE_FORMAT_NONE) {
       _eglError(EGL_BAD_PARAMETER,
                 "dri3_create_image_khr: unsupported pixmap depth");
@@ -377,26 +363,27 @@ dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
    }
 
    return &dri2_img->base;
-#else
-   return NULL;
-#endif
 }
+#endif
 
 static _EGLImage *
-dri3_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
-                      _EGLContext *ctx, EGLenum target,
+dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
                       EGLClientBuffer buffer, const EGLint *attr_list)
 {
+#ifdef HAVE_DRI3_MODIFIERS
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+#endif
 
    switch (target) {
    case EGL_NATIVE_PIXMAP_KHR:
+#ifdef HAVE_DRI3_MODIFIERS
       if (dri2_dpy->multibuffers_available)
          return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
                                                           attr_list);
+#endif
       return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
    default:
-      return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
+      return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
    }
 }
 
@@ -407,13 +394,15 @@ dri3_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
 static void
 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
 {
+   struct loader_dri3_drawable *draw = loaderPrivate;
+   (void) driDrawable;
+
    /* There does not seem to be any kind of consensus on whether we should
     * support front-buffer rendering or not:
     * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
     */
-   _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
-   (void) driDrawable;
-   (void) loaderPrivate;
+   if (!draw->is_pixmap)
+      _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
 }
 
 const __DRIimageLoaderExtension dri3_image_loader_extension = {
@@ -424,22 +413,17 @@ const __DRIimageLoaderExtension dri3_image_loader_extension = {
 };
 
 static EGLBoolean
-dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
+dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
 {
    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
 
-   /* No-op for a pixmap or pbuffer surface */
-   if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
-      return EGL_FALSE;
-
    return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,
                                        0, 0, 0, 0,
                                        draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
 }
 
 static EGLBoolean
-dri3_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
-                  void *native_pixmap_target)
+dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)
 {
    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
    xcb_pixmap_t target;
@@ -454,7 +438,7 @@ dri3_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
 }
 
 static int
-dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
+dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
 {
    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
 
@@ -462,9 +446,8 @@ dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
 }
 
 static EGLBoolean
-dri3_query_surface(_EGLDriver *drv, _EGLDisplay *dpy,
-                   _EGLSurface *surf, EGLint attribute,
-                   EGLint *value)
+dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
+                   EGLint attribute, EGLint *value)
 {
    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
 
@@ -477,7 +460,7 @@ dri3_query_surface(_EGLDriver *drv, _EGLDisplay *dpy,
       break;
    }
 
-   return _eglQuerySurface(drv, dpy, surf, attribute, value);
+   return _eglQuerySurface(disp, surf, attribute, value);
 }
 
 static __DRIdrawable *
@@ -489,9 +472,9 @@ dri3_get_dri_drawable(_EGLSurface *surf)
 }
 
 static void
-dri3_close_screen_notify(_EGLDisplay *dpy)
+dri3_close_screen_notify(_EGLDisplay *disp)
 {
-   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
 
    loader_dri3_close_screen(dri2_dpy->dri_screen);
 }
@@ -505,19 +488,26 @@ struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
    .create_image = dri3_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,
-   .set_damage_region = dri2_fallback_set_damage_region,
-   .post_sub_buffer = dri2_fallback_post_sub_buffer,
    .copy_buffers = dri3_copy_buffers,
    .query_buffer_age = dri3_query_buffer_age,
    .query_surface = dri3_query_surface,
-   .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
    .get_sync_values = dri3_get_sync_values,
    .get_dri_drawable = dri3_get_dri_drawable,
    .close_screen_notify = dri3_close_screen_notify,
 };
 
+/* Only request versions of these protocols which we actually support. */
+#define DRI3_SUPPORTED_MAJOR 1
+#define PRESENT_SUPPORTED_MAJOR 1
+
+#ifdef HAVE_DRI3_MODIFIERS
+#define DRI3_SUPPORTED_MINOR 2
+#define PRESENT_SUPPORTED_MINOR 2
+#else
+#define PRESENT_SUPPORTED_MINOR 0
+#define DRI3_SUPPORTED_MINOR 0
+#endif
+
 EGLBoolean
 dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
 {
@@ -525,11 +515,14 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
    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_xfixes_query_version_reply_t *xfixes_query;
+   xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
    xcb_generic_error_t *error;
    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);
+   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
 
    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
    if (!(extension && extension->present))
@@ -539,13 +532,21 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
    if (!(extension && extension->present))
       return EGL_FALSE;
 
+   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_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);
+                                              DRI3_SUPPORTED_MAJOR,
+                                              DRI3_SUPPORTED_MINOR);
 
    present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
-                                                    XCB_PRESENT_MAJOR_VERSION,
-                                                    XCB_PRESENT_MINOR_VERSION);
+                                                    PRESENT_SUPPORTED_MAJOR,
+                                                    PRESENT_SUPPORTED_MINOR);
+
+   xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
+                                                  XCB_XFIXES_MAJOR_VERSION,
+                                                  XCB_XFIXES_MINOR_VERSION);
 
    dri3_query =
       xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
@@ -574,6 +575,18 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
    dri2_dpy->present_minor_version = present_query->minor_version;
    free(present_query);
 
+   xfixes_query =
+      xcb_xfixes_query_version_reply(dri2_dpy->conn,
+                                      xfixes_query_cookie, &error);
+   if (xfixes_query == NULL || error != NULL ||
+       xfixes_query->major_version < 2) {
+      _eglLog(_EGL_WARNING, "DRI3: failed to query xfixes version");
+      free(error);
+      free(xfixes_query);
+      return EGL_FALSE;
+   }
+   free(xfixes_query);
+
    dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
    if (dri2_dpy->fd < 0) {
       int conn_error = xcb_connection_has_error(dri2_dpy->conn);