[Mesa-dev] [PATCH V2 10/11] Wayland/egl: Add Gpu offloading support

Axel Davy axel.davy at ens.fr
Wed May 28 20:22:04 PDT 2014


Signed-off-by: Axel Davy <axel.davy at ens.fr>
---
 src/egl/drivers/dri2/egl_dri2.h         |   5 +-
 src/egl/drivers/dri2/platform_wayland.c | 171 ++++++++++++++++++++++++++------
 2 files changed, 142 insertions(+), 34 deletions(-)

diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 0dd9d69..4b70c48 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -195,6 +195,8 @@ struct dri2_egl_display
    int			     authenticated;
    int			     formats;
    uint32_t                  capabilities;
+   int			     is_different_gpu;
+   int			     blit_front;
 #endif
 };
 
@@ -247,7 +249,8 @@ struct dri2_egl_surface
    struct {
 #ifdef HAVE_WAYLAND_PLATFORM
       struct wl_buffer   *wl_buffer;
-      __DRIimage         *dri_image;
+      __DRIimage         *rendering_image;
+      __DRIimage         *shared_image;
 #endif
 #ifdef HAVE_DRM_PLATFORM
       struct gbm_bo       *bo;
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index 537d26e..8d0a90c 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -238,8 +238,10 @@ dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
       if (dri2_surf->color_buffers[i].wl_buffer)
          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
-      if (dri2_surf->color_buffers[i].dri_image)
-         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
+      if (dri2_surf->color_buffers[i].rendering_image) {
+         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].rendering_image);
+         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].shared_image);
+      }
    }
 
    for (i = 0; i < __DRI_BUFFER_COUNT; i++)
@@ -272,11 +274,14 @@ dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
       if (dri2_surf->color_buffers[i].wl_buffer &&
           !dri2_surf->color_buffers[i].locked)
          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
-      if (dri2_surf->color_buffers[i].dri_image)
-         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
+      if (dri2_surf->color_buffers[i].rendering_image) {
+         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].rendering_image);
+         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].shared_image);
+      }
 
       dri2_surf->color_buffers[i].wl_buffer = NULL;
-      dri2_surf->color_buffers[i].dri_image = NULL;
+      dri2_surf->color_buffers[i].rendering_image = NULL;
+      dri2_surf->color_buffers[i].shared_image = NULL;
       dri2_surf->color_buffers[i].locked = 0;
    }
 
@@ -292,6 +297,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
 {
    struct dri2_egl_display *dri2_dpy =
       dri2_egl_display(dri2_surf->base.Resource.Display);
+   unsigned int use_flags;
    int i;
 
    /* We always want to throttle to some event (either a frame callback or
@@ -311,24 +317,45 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
             continue;
          if (dri2_surf->back == NULL)
             dri2_surf->back = &dri2_surf->color_buffers[i];
-         else if (dri2_surf->back->dri_image == NULL)
+         else if (dri2_surf->back->rendering_image == NULL)
             dri2_surf->back = &dri2_surf->color_buffers[i];
       }
    }
 
    if (dri2_surf->back == NULL)
       return -1;
-   if (dri2_surf->back->dri_image == NULL) {
-      dri2_surf->back->dri_image = 
+
+   if (dri2_surf->back->rendering_image == NULL) {
+      use_flags = __DRI_IMAGE_USE_SHARE;
+
+      if (dri2_dpy->is_different_gpu)
+         use_flags |= __DRI_IMAGE_USE_LINEAR;
+
+      dri2_surf->back->shared_image =
          dri2_dpy->image->createImage(dri2_dpy->dri_screen,
                                       dri2_surf->base.Width,
                                       dri2_surf->base.Height,
                                       __DRI_IMAGE_FORMAT_ARGB8888,
-                                      __DRI_IMAGE_USE_SHARE,
+                                      use_flags,
                                       NULL);
+      if (dri2_surf->back->shared_image == NULL)
+         return -1;
+
+      if (dri2_dpy->blit_front)
+         dri2_surf->back->rendering_image =
+            dri2_dpy->image->createImage(dri2_dpy->dri_screen,
+                                         dri2_surf->base.Width,
+                                         dri2_surf->base.Height,
+                                         __DRI_IMAGE_FORMAT_ARGB8888,
+                                         0,
+                                         NULL);
+      else
+         dri2_surf->back->rendering_image =
+            dri2_dpy->image->dupImage(dri2_surf->back->shared_image, NULL);
+
       dri2_surf->back->age = 0;
    }
-   if (dri2_surf->back->dri_image == NULL)
+   if (dri2_surf->back->rendering_image == NULL)
       return -1;
 
    dri2_surf->back->locked = 1;
@@ -345,7 +372,7 @@ back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
    __DRIimage *image;
    int name, pitch;
 
-   image = dri2_surf->back->dri_image;
+   image = dri2_surf->back->rendering_image;
 
    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
@@ -411,9 +438,11 @@ update_buffers(struct dri2_egl_surface *dri2_surf)
       if (!dri2_surf->color_buffers[i].locked &&
           dri2_surf->color_buffers[i].wl_buffer) {
          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
-         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
+         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].rendering_image);
+         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].shared_image);
          dri2_surf->color_buffers[i].wl_buffer = NULL;
-         dri2_surf->color_buffers[i].dri_image = NULL;
+         dri2_surf->color_buffers[i].rendering_image = NULL;
+         dri2_surf->color_buffers[i].shared_image = NULL;
       }
    }
 
@@ -504,7 +533,7 @@ image_get_buffers(__DRIdrawable *driDrawable,
       return 0;
 
    buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
-   buffers->back = dri2_surf->back->dri_image;
+   buffers->back = dri2_surf->back->rendering_image;
 
    return 1;
 }
@@ -549,9 +578,9 @@ create_wl_buffer(struct dri2_egl_surface *dri2_surf)
       return;
 
    if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
-      dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
+      dri2_dpy->image->queryImage(dri2_surf->current->shared_image,
                                   __DRI_IMAGE_ATTRIB_FD, &fd);
-      dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
+      dri2_dpy->image->queryImage(dri2_surf->current->shared_image,
                                   __DRI_IMAGE_ATTRIB_STRIDE, &stride);
 
       dri2_surf->current->wl_buffer =
@@ -565,9 +594,9 @@ create_wl_buffer(struct dri2_egl_surface *dri2_surf)
                                     0, 0);
       close(fd);
    } else {
-      dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
+      dri2_dpy->image->queryImage(dri2_surf->current->shared_image,
                                   __DRI_IMAGE_ATTRIB_NAME, &name);
-      dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
+      dri2_dpy->image->queryImage(dri2_surf->current->shared_image,
                                   __DRI_IMAGE_ATTRIB_STRIDE, &stride);
 
       dri2_surf->current->wl_buffer =
@@ -650,6 +679,20 @@ dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
       }
    }
 
+   if (dri2_dpy->flush->base.version >= 4 || dri2_dpy->blit_front) {
+      ctx = _eglGetCurrentContext();
+      dri2_ctx = dri2_egl_context(ctx);
+   }
+
+   if (dri2_dpy->blit_front)
+      dri2_dpy->image->blitImage(dri2_ctx->dri_context,
+                                 dri2_surf->current->shared_image,
+                                 dri2_surf->current->rendering_image,
+                                 0, 0, dri2_surf->base.Width,
+                                 dri2_surf->base.Height,
+                                 0, 0, dri2_surf->base.Width,
+                                 dri2_surf->base.Height);
+
    if (dri2_dpy->flush->base.version >= 4) {
       ctx = _eglGetCurrentContext();
       dri2_ctx = dri2_egl_context(ctx);
@@ -714,6 +757,14 @@ dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv,
    int width, height, format, pitch;
    enum wl_drm_format wl_format;
 
+   /* The buffer to import likely has tiling. This tiling mode is likely
+    * incompatible with the server gpu. We can't check for it, so assume
+    * we cannot import.*/
+   if (dri2_dpy->is_different_gpu) {
+      _eglError(EGL_BAD_MATCH, "dri2_create_wayland_buffer_from_image_wl");
+      return NULL;
+   }
+
    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
 
    switch (format) {
@@ -777,6 +828,22 @@ bad_format:
    return NULL;
 }
 
+static char
+is_fd_render_node(int fd)
+{
+   struct stat render;
+
+   if (fstat(fd, &render))
+      return 0;
+
+   if (!S_ISCHR(render.st_mode))
+      return 0;
+
+   if (render.st_rdev & 0x80)
+      return 1;
+   return 0;
+}
+
 static int
 dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
 {
@@ -804,28 +871,27 @@ drm_handle_device(void *data, struct wl_drm *drm, const char *device)
    struct dri2_egl_display *dri2_dpy = data;
    drm_magic_t magic;
 
-   dri2_dpy->device_name = strdup(device);
-   if (!dri2_dpy->device_name)
-      return;
-
 #ifdef O_CLOEXEC
-   dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
+   dri2_dpy->fd = open(device, O_RDWR | O_CLOEXEC);
    if (dri2_dpy->fd == -1 && errno == EINVAL)
 #endif
    {
-      dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
+      dri2_dpy->fd = open(device, O_RDWR);
       if (dri2_dpy->fd != -1)
          fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
             FD_CLOEXEC);
    }
    if (dri2_dpy->fd == -1) {
       _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
-	      dri2_dpy->device_name, strerror(errno));
+	      device, strerror(errno));
       return;
    }
 
-   drmGetMagic(dri2_dpy->fd, &magic);
-   wl_drm_authenticate(dri2_dpy->wl_drm, magic);
+   if (!is_fd_render_node(dri2_dpy->fd)) {
+      drmGetMagic(dri2_dpy->fd, &magic);
+      wl_drm_authenticate(dri2_dpy->wl_drm, magic);
+   } else
+      dri2_dpy->authenticated = 1;
 }
 
 static void
@@ -967,6 +1033,23 @@ static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
    .get_sync_values = dri2_fallback_get_sync_values,
 };
 
+static EGLBoolean
+is_render_node_capable(struct dri2_egl_display *dri2_dpy)
+{
+   const __DRIextension **extensions;
+   int i;
+
+   if (!(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME))
+      return EGL_FALSE;
+
+   extensions = dri2_dpy->driver_extensions;
+   for (i = 0; extensions[i]; i++) {
+      if (strcmp(extensions[i]->name, __DRI_IMAGE_DRIVER) == 0)
+         return EGL_TRUE;
+   }
+   return EGL_FALSE;
+}
+
 EGLBoolean
 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
 {
@@ -1014,10 +1097,19 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
    if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
       goto cleanup_fd;
 
+   dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
+   dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
+
+   if (dri2_dpy->device_name == NULL) {
+      _eglError(EGL_BAD_ALLOC, "DRI2: failed to get device name");
+      goto cleanup_fd;
+   }
+
    dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
+
    if (dri2_dpy->driver_name == NULL) {
       _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
-      goto cleanup_fd;
+      goto cleanup_device_name;
    }
 
    if (!dri2_load_driver(disp))
@@ -1043,15 +1135,25 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
 
    dri2_wl_setup_swap_interval(dri2_dpy);
 
-   /* The server shouldn't advertise WL_DRM_CAPABILITY_PRIME if the driver
-    * doesn't have createImageFromFds, since we're using the same driver on
-    * both sides.  We don't want crash if that happens anyway, so fall back to
-    * gem names if we don't have prime support. */
+   /* To use Prime, we must have _DRI_IMAGE v7 at least.
+    * createImageFromFds support indicates that Prime export/import
+    * is supported by the driver. Fall back to
+    * gem names if we don't have Prime support. */
 
    if (dri2_dpy->image->base.version < 7 ||
        dri2_dpy->image->createImageFromFds == NULL)
       dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
 
+   if (is_fd_render_node(dri2_dpy->fd) && !is_render_node_capable(dri2_dpy)) {
+      _eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable");
+      goto cleanup_screen;
+   }
+
+   if (dri2_dpy->is_different_gpu && dri2_dpy->image->base.version >= 9) {
+      dri2_dpy->blit_front = 1;
+      _eglLog(_EGL_DEBUG, "wayland-egl: blit mode activated");
+   }
+
    types = EGL_WINDOW_BIT;
    for (i = 0; dri2_dpy->driver_configs[i]; i++) {
       config = dri2_dpy->driver_configs[i];
@@ -1080,14 +1182,17 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
 
    return EGL_TRUE;
 
+ cleanup_screen:
+   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
  cleanup_driver:
    dlclose(dri2_dpy->driver);
  cleanup_driver_name:
    free(dri2_dpy->driver_name);
+ cleanup_device_name:
+   free(dri2_dpy->device_name);
  cleanup_fd:
    close(dri2_dpy->fd);
  cleanup_drm:
-   free(dri2_dpy->device_name);
    wl_drm_destroy(dri2_dpy->wl_drm);
  cleanup_dpy:
    free(dri2_dpy);
-- 
1.9.1



More information about the mesa-dev mailing list