egl/dri2: move surface refcounting out of the platform code
[mesa.git] / src / egl / drivers / dri2 / platform_x11_dri3.c
index 0b95e4d42de4446b003f6868229696048d994b2f..26bb43011507e0c2394caedbdfd7e7cc918dc10b 100644 (file)
@@ -96,11 +96,24 @@ static __DRIcontext *
 egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
 {
    _EGLContext *ctx = _eglGetCurrentContext();
-   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
-
+   struct dri2_egl_context *dri2_ctx;
+   if (!ctx)
+      return NULL;
+   dri2_ctx = dri2_egl_context(ctx);
    return dri2_ctx->dri_context;
 }
 
+static __DRIscreen *
+egl_dri3_get_dri_screen(struct loader_dri3_drawable *draw)
+{
+   _EGLContext *ctx = _eglGetCurrentContext();
+   struct dri2_egl_context *dri2_ctx;
+   if (!ctx)
+      return NULL;
+   dri2_ctx = dri2_egl_context(ctx);
+   return dri2_egl_display(dri2_ctx->base.Resource.Display)->dri_screen;
+}
+
 static void
 egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
 {
@@ -117,6 +130,7 @@ static struct loader_dri3_vtable egl_dri3_vtable = {
    .set_drawable_size = egl_dri3_set_drawable_size,
    .in_current_context = egl_dri3_in_current_context,
    .get_dri_context = egl_dri3_get_dri_context,
+   .get_dri_screen = egl_dri3_get_dri_screen,
    .flush_drawable = egl_dri3_flush_drawable,
    .show_fps = NULL,
 };
@@ -128,9 +142,6 @@ dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
 
    (void) drv;
 
-   if (!_eglPutSurface(surf))
-      return EGL_TRUE;
-
    loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
 
    free(surf);
@@ -224,6 +235,25 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
    return NULL;
 }
 
+static int
+dri3_authenticate(_EGLDisplay *disp, uint32_t id)
+{
+#ifdef HAVE_WAYLAND_PLATFORM
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+
+   if (dri2_dpy->device_name) {
+      _eglLog(_EGL_WARNING,
+              "Wayland client render node authentication is unnecessary");
+      return 0;
+   }
+
+   _eglLog(_EGL_WARNING,
+           "Wayland client primary node authentication isn't supported");
+#endif
+
+   return -1;
+}
+
 /**
  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
  */
@@ -272,6 +302,81 @@ dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
                                    (int64_t *) sbc) ? EGL_TRUE : EGL_FALSE;
 }
 
+static _EGLImage *
+dri3_create_image_khr_pixmap(_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_drawable_t drawable;
+   xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
+   xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;
+   unsigned int format;
+
+   drawable = (xcb_drawable_t) (uintptr_t) buffer;
+   bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
+   bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,
+                                                bp_cookie, NULL);
+   if (!bp_reply) {
+      _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
+      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:
+      _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");
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   if (!_eglInitImage(&dri2_img->base, disp)) {
+      free(dri2_img);
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,
+                                                  bp_reply,
+                                                  format,
+                                                  dri2_dpy->dri_screen,
+                                                  dri2_dpy->image,
+                                                  dri2_img);
+
+   free(bp_reply);
+
+   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;
+
+   switch (target) {
+   case EGL_NATIVE_PIXMAP_KHR:
+      return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
+   default:
+      return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
+   }
+}
+
 /**
  * Called by the driver when it needs to update the real front buffer with the
  * contents of its fake front buffer.
@@ -342,12 +447,12 @@ dri3_get_dri_drawable(_EGLSurface *surf)
 }
 
 struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
-   .authenticate = NULL,
+   .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,
+   .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,
@@ -360,29 +465,6 @@ struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
    .get_dri_drawable = dri3_get_dri_drawable,
 };
 
-static char *
-dri3_get_device_name(int fd)
-{
-   char *ret = NULL;
-
-   ret = drmGetRenderDeviceNameFromFd(fd);
-   if (ret)
-      return ret;
-
-   /* For dri3, render node support is required for WL_bind_wayland_display.
-    * In order not to regress on older systems without kernel or libdrm
-    * support, fall back to dri2. User can override it with environment
-    * variable if they don't need to use that extension.
-    */
-   if (getenv("EGL_FORCE_DRI3") == NULL) {
-      _eglLog(_EGL_WARNING, "Render node support not available, falling back to dri2");
-      _eglLog(_EGL_WARNING, "If you want to force dri3, set EGL_FORCE_DRI3 environment variable");
-   } else
-      ret = loader_get_device_name_for_fd(fd);
-
-   return ret;
-}
-
 EGLBoolean
 dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
 {
@@ -417,7 +499,7 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
    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");
+      _eglLog(_EGL_WARNING, "DRI3: failed to query the version");
       free(dri3_query);
       free(error);
       return EGL_FALSE;
@@ -428,7 +510,7 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
       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");
+      _eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
       free(present_query);
       free(error);
       return EGL_FALSE;
@@ -445,10 +527,10 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
    dri2_dpy->fd = loader_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");
+      _eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
 
       if (conn_error)
-         _eglLog(_EGL_WARNING, "DRI2: Failed to initialize DRI3");
+         _eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
 
       return EGL_FALSE;
    }
@@ -457,16 +539,17 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
 
    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");
+      _eglLog(_EGL_WARNING, "DRI3: No driver found");
       close(dri2_dpy->fd);
       return EGL_FALSE;
    }
 
-   dri2_dpy->device_name = dri3_get_device_name(dri2_dpy->fd);
-   if (!dri2_dpy->device_name) {
-      close(dri2_dpy->fd);
-      return EGL_FALSE;
-   }
+#ifdef HAVE_WAYLAND_PLATFORM
+   /* Only try to get a render device name since dri3 doesn't provide a
+    * mechanism for authenticating client opened device node fds. If this
+    * fails then don't advertise the extension. */
+   dri2_dpy->device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd);
+#endif
 
    return EGL_TRUE;
 }