egl/x11: Support DRI3 v1.1
[mesa.git] / src / egl / drivers / dri2 / platform_x11_dri3.c
index 9c018168b1cd4f57159425c1a1005b453917f6d1..c1efa93015921e673dd7c7a49f418b991be022ad 100644 (file)
 #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);
@@ -51,8 +68,8 @@ egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
 {
    struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
 
-   dri3_surf->base.Width = width;
-   dri3_surf->base.Height = height;
+   dri3_surf->surf.base.Width = width;
+   dri3_surf->surf.base.Height = height;
 }
 
 static bool
@@ -61,7 +78,7 @@ egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
    struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
    _EGLContext *ctx = _eglGetCurrentContext();
 
-   return ctx->Resource.Display == dri3_surf->base.Resource.Display;
+   return ctx->Resource.Display == dri3_surf->surf.base.Resource.Display;
 }
 
 static __DRIcontext *
@@ -76,7 +93,7 @@ egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
 }
 
 static __DRIscreen *
-egl_dri3_get_dri_screen(struct loader_dri3_drawable *draw)
+egl_dri3_get_dri_screen(void)
 {
    _EGLContext *ctx = _eglGetCurrentContext();
    struct dri2_egl_context *dri2_ctx;
@@ -90,9 +107,9 @@ static void
 egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
 {
    struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
-   _EGLDisplay *disp = dri3_surf->base.Resource.Display;
+   _EGLDisplay *disp = dri3_surf->surf.base.Resource.Display;
 
-   dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->base);
+   dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);
 }
 
 static const struct loader_dri3_vtable egl_dri3_vtable = {
@@ -113,6 +130,7 @@ dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
 
    loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
 
+   dri2_fini_surface(surf);
    free(surf);
 
    return EGL_TRUE;
@@ -124,7 +142,7 @@ dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
 {
    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
 
-   dri3_surf->base.SwapInterval = interval;
+   dri3_surf->surf.base.SwapInterval = interval;
    loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);
 
    return EGL_TRUE;
@@ -149,25 +167,27 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
       return NULL;
    }
 
-   if (!_eglInitSurface(&dri3_surf->base, disp, type, conf, attrib_list))
+   if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf, attrib_list, false))
       goto cleanup_surf;
 
    if (type == EGL_PBUFFER_BIT) {
       drawable = xcb_generate_id(dri2_dpy->conn);
       xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
                         drawable, dri2_dpy->screen->root,
-                        dri3_surf->base.Width, dri3_surf->base.Height);
+                        dri3_surf->surf.base.Width, dri3_surf->surf.base.Height);
    } else {
       STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
       drawable = (uintptr_t) native_surface;
    }
 
    dri_config = dri2_get_dri_config(dri2_conf, type,
-                                    dri3_surf->base.GLColorspace);
+                                    dri3_surf->surf.base.GLColorspace);
 
    if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
                                  dri2_dpy->dri_screen,
-                                 dri2_dpy->is_different_gpu, dri_config,
+                                 dri2_dpy->is_different_gpu,
+                                 dri2_dpy->multibuffers_available,
+                                 dri_config,
                                  &dri2_dpy->loader_dri3_ext,
                                  &egl_dri3_vtable,
                                  &dri3_surf->loader_drawable)) {
@@ -175,7 +195,7 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
       goto cleanup_pixmap;
    }
 
-   return &dri3_surf->base;
+   return &dri3_surf->surf.base;
 
  cleanup_pixmap:
    if (type == EGL_PBUFFER_BIT)
@@ -273,17 +293,8 @@ dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
       return NULL;
    }
 
-   switch (bp_reply->depth) {
-   case 16:
-      format = __DRI_IMAGE_FORMAT_RGB565;
-      break;
-   case 24:
-      format = __DRI_IMAGE_FORMAT_XRGB8888;
-      break;
-   case 32:
-      format = __DRI_IMAGE_FORMAT_ARGB8888;
-      break;
-   default:
+   format = dri3_format_for_depth(bp_reply->depth);
+   if (format == __DRI_IMAGE_FORMAT_NONE) {
       _eglError(EGL_BAD_PARAMETER,
                 "dri3_create_image_khr: unsupported pixmap depth");
       free(bp_reply);
@@ -293,6 +304,7 @@ dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
    dri2_img = malloc(sizeof *dri2_img);
    if (!dri2_img) {
       _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
+      free(bp_reply);
       return EGL_NO_IMAGE_KHR;
    }
 
@@ -310,15 +322,74 @@ dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
    return &dri2_img->base;
 }
 
+static _EGLImage *
+dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
+                                          EGLClientBuffer buffer,
+                                          const EGLint *attr_list)
+{
+   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;
+   xcb_dri3_buffers_from_pixmap_reply_t  *bp_reply;
+   xcb_drawable_t drawable;
+   unsigned int format;
+
+   drawable = (xcb_drawable_t) (uintptr_t) buffer;
+   bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
+   bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
+                                                 bp_cookie, NULL);
+
+   if (!bp_reply) {
+      _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   format = dri3_format_for_depth(bp_reply->depth);
+   if (format == __DRI_IMAGE_FORMAT_NONE) {
+      _eglError(EGL_BAD_PARAMETER,
+                "dri3_create_image_khr: unsupported pixmap depth");
+      free(bp_reply);
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   dri2_img = malloc(sizeof *dri2_img);
+   if (!dri2_img) {
+      _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
+      free(bp_reply);
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   _eglInitImage(&dri2_img->base, disp);
+
+   dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
+                                                               bp_reply,
+                                                               format,
+                                                               dri2_dpy->dri_screen,
+                                                               dri2_dpy->image,
+                                                               dri2_img);
+   free(bp_reply);
+
+   if (!dri2_img->dri_image) {
+      _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
+      free(dri2_img);
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   return &dri2_img->base;
+}
+
 static _EGLImage *
 dri3_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
                       _EGLContext *ctx, EGLenum target,
                       EGLClientBuffer buffer, const EGLint *attr_list)
 {
-   (void) drv;
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
 
    switch (target) {
    case EGL_NATIVE_PIXMAP_KHR:
+      if (dri2_dpy->multibuffers_available)
+         return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
+                                                          attr_list);
       return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
    default:
       return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
@@ -413,6 +484,14 @@ dri3_get_dri_drawable(_EGLSurface *surf)
    return dri3_surf->loader_drawable.dri_drawable;
 }
 
+static void
+dri3_close_screen_notify(_EGLDisplay *dpy)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
+
+   loader_dri3_close_screen(dri2_dpy->dri_screen);
+}
+
 struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
    .authenticate = dri3_authenticate,
    .create_window_surface = dri3_create_window_surface,
@@ -432,6 +511,7 @@ struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
    .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,
 };
 
 EGLBoolean
@@ -471,6 +551,9 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
       free(error);
       return EGL_FALSE;
    }
+
+   dri2_dpy->dri3_major_version = dri3_query->major_version;
+   dri2_dpy->dri3_minor_version = dri3_query->minor_version;
    free(dri3_query);
 
    present_query =