[RFC xserver 05/16] DRI3/Glamor: Implement PixmapFromBuffers request

Daniel Stone daniels at collabora.com
Thu Jun 8 18:43:31 UTC 2017


From: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 dri3/dri3.h                   |  18 ++--
 dri3/dri3_priv.h              |   5 +-
 dri3/dri3_request.c           |  75 ++++++++++++---
 dri3/dri3_screen.c            |  12 ++-
 glamor/glamor.c               |  56 +++++++++++
 glamor/glamor.h               |  28 ++----
 glamor/glamor_egl.c           | 161 +++++++++++++++++++++++++++++---
 hw/xwayland/xwayland-glamor.c | 211 ++++++++++++++++++++++++++++++++++++++----
 hw/xwayland/xwayland.h        |   1 +
 9 files changed, 491 insertions(+), 76 deletions(-)

diff --git a/dri3/dri3.h b/dri3/dri3.h
index 40b8474c0..4d6699f5e 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -39,13 +39,15 @@ typedef int (*dri3_open_client_proc)(ClientPtr client,
                                      RRProviderPtr provider,
                                      int *fd);
 
-typedef PixmapPtr (*dri3_pixmap_from_fd_proc) (ScreenPtr screen,
-                                               int fd,
-                                               CARD16 width,
-                                               CARD16 height,
-                                               CARD16 stride,
-                                               CARD8 depth,
-                                               CARD8 bpp);
+typedef PixmapPtr (*dri3_pixmap_from_fds_proc) (ScreenPtr screen,
+                                                CARD8 num_fds,
+                                                int *fds,
+                                                CARD16 width,
+                                                CARD16 height,
+                                                CARD32 *strides,
+                                                CARD32 *offsets,
+                                                CARD32 format,
+                                                uint64_t modifiers);
 
 typedef int (*dri3_fd_from_pixmap_proc) (ScreenPtr screen,
                                          PixmapPtr pixmap,
@@ -66,7 +68,7 @@ typedef struct dri3_screen_info {
     uint32_t                    version;
 
     dri3_open_proc              open;
-    dri3_pixmap_from_fd_proc    pixmap_from_fd;
+    dri3_pixmap_from_fds_proc   pixmap_from_fds;
     dri3_fd_from_pixmap_proc    fd_from_pixmap;
     dri3_get_formats_proc       get_formats;
     dri3_get_modifiers_proc     get_modifiers;
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index c767f373e..5359a8a92 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -80,8 +80,9 @@ int
 dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd);
 
 int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
-                    CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp);
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, CARD8 num_fds, int *fds,
+                     CARD16 width, CARD16 height, CARD32 *strides, CARD32 *offsets,
+                     CARD32 format, uint64_t modifier);
 
 int
 dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index 35f1c2533..182388232 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <xace.h>
 #include "../Xext/syncsdk.h"
+#include <drm_fourcc.h>
 #include <protocol-versions.h>
 
 static int
@@ -117,6 +118,41 @@ proc_dri3_open(ClientPtr client)
     return Success;
 }
 
+static uint32_t
+drm_format_for_depth(uint32_t bpp, uint32_t depth)
+{
+    uint32_t fmt;
+
+    switch (bpp) {
+        case 8:
+            fmt = DRM_FORMAT_C8;
+            break;
+        case 16:
+            if (depth == 15)
+                fmt = DRM_FORMAT_XRGB1555;
+            else
+                fmt = DRM_FORMAT_RGB565;
+            break;
+        case 24:
+            fmt = DRM_FORMAT_RGB888;
+            break;
+        case 32:
+            if (depth == 24)
+                fmt = DRM_FORMAT_XRGB8888;
+            else if (depth == 30)
+                fmt = DRM_FORMAT_XRGB2101010;
+            else
+                fmt = DRM_FORMAT_ARGB8888;
+            break;
+        default:
+            // XXX error
+            fmt = DRM_FORMAT_XRGB8888;
+            break;
+    }
+
+    return fmt;
+}
+
 static int
 proc_dri3_pixmap_from_buffer(ClientPtr client)
 {
@@ -124,6 +160,7 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
     int fd;
     DrawablePtr drawable;
     PixmapPtr pixmap;
+    CARD32 stride, offset, format;
     int rc;
 
     SetReqFds(client, 1);
@@ -159,11 +196,13 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
     if (fd < 0)
         return BadValue;
 
-    rc = dri3_pixmap_from_fd(&pixmap,
-                             drawable->pScreen, fd,
-                             stuff->width, stuff->height,
-                             stuff->stride, stuff->depth,
-                             stuff->bpp);
+    offset = 0;
+    stride = stuff->stride;
+    format = drm_format_for_depth(stuff->bpp, stuff->depth);
+    rc = dri3_pixmap_from_fds(&pixmap,
+                              drawable->pScreen, 1, &fd,
+                              stuff->width, stuff->height,
+                              &stride, &offset, format, 0);
     close (fd);
     if (rc != Success)
         return rc;
@@ -402,8 +441,10 @@ proc_dri3_pixmap_from_buffers(ClientPtr client)
 {
     REQUEST(xDRI3PixmapFromBuffersReq);
     int fds[4];
+    CARD32 strides[4], offsets[4];
     DrawablePtr drawable;
     PixmapPtr pixmap;
+    uint64_t modifier;
     int rc;
     int i;
 
@@ -435,12 +476,24 @@ proc_dri3_pixmap_from_buffers(ClientPtr client)
             return BadValue;
     }
 
-    /* XXX: DTRT */
-    rc = dri3_pixmap_from_fd(&pixmap,
-                             drawable->pScreen, fds[0],
-                             stuff->width, stuff->height,
-                             stuff->stride0,
-                             0, 0);
+    modifier = (uint64_t) stuff->modifier_hi << 32;
+    modifier |= ((uint64_t) stuff->modifier_lo & 0xffffffff);
+    strides[0] = stuff->stride0;
+    strides[1] = stuff->stride1;
+    strides[2] = stuff->stride2;
+    strides[3] = stuff->stride3;
+    offsets[0] = stuff->offset0;
+    offsets[1] = stuff->offset1;
+    offsets[2] = stuff->offset2;
+    offsets[3] = stuff->offset3;
+
+    rc = dri3_pixmap_from_fds(&pixmap,
+                              drawable->pScreen,
+                              stuff->num_buffers, fds,
+                              stuff->width, stuff->height,
+                              strides, offsets,
+                              stuff->format, modifier);
+
     if (rc != Success)
         goto error;
 
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 4d4f77bcf..65c262ba0 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -60,17 +60,21 @@ dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd)
 }
 
 int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
-                    CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp)
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen,
+                     CARD8 num_fds, int *fds,
+                     CARD16 width, CARD16 height,
+                     CARD32 *strides, CARD32 *offsets,
+                     CARD32 format, uint64_t modifier)
 {
     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
     dri3_screen_info_ptr        info = ds->info;
     PixmapPtr                   pixmap;
 
-    if (!info || !info->pixmap_from_fd)
+    if (!info || !info->pixmap_from_fds)
         return BadImplementation;
 
-    pixmap = (*info->pixmap_from_fd) (screen, fd, width, height, stride, depth, bpp);
+    pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height,
+                                       strides, offsets, format, modifier);
     if (!pixmap)
         return BadAlloc;
 
diff --git a/glamor/glamor.c b/glamor/glamor.c
index 91236e29c..66b081272 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -35,11 +35,67 @@
 
 #include "glamor_priv.h"
 #include "mipict.h"
+#include <drm_fourcc.h>
 
 DevPrivateKeyRec glamor_screen_private_key;
 DevPrivateKeyRec glamor_pixmap_private_key;
 DevPrivateKeyRec glamor_gc_private_key;
 
+_X_EXPORT const struct drm_format_info *
+drm_format_get_info(uint32_t format)
+{
+    static const struct drm_format_info formats[] = {
+        { .format = DRM_FORMAT_C8,          .depth = 8,  .bpp = 8  },
+        { .format = DRM_FORMAT_RGB332,      .depth = 8,  .bpp = 8  },
+        { .format = DRM_FORMAT_BGR233,      .depth = 8,  .bpp = 8  },
+        { .format = DRM_FORMAT_XRGB4444,    .depth = 12, .bpp = 16 },
+        { .format = DRM_FORMAT_XBGR4444,    .depth = 12, .bpp = 16 },
+        { .format = DRM_FORMAT_RGBX4444,    .depth = 12, .bpp = 16 },
+        { .format = DRM_FORMAT_BGRX4444,    .depth = 12, .bpp = 16 },
+        { .format = DRM_FORMAT_ARGB4444,    .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_ABGR4444,    .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_RGBA4444,    .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_BGRA4444,    .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_XRGB1555,    .depth = 15, .bpp = 16 },
+        { .format = DRM_FORMAT_XBGR1555,    .depth = 15, .bpp = 16 },
+        { .format = DRM_FORMAT_RGBX5551,    .depth = 15, .bpp = 16 },
+        { .format = DRM_FORMAT_BGRX5551,    .depth = 15, .bpp = 16 },
+        { .format = DRM_FORMAT_ARGB1555,    .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_ABGR1555,    .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_RGBA5551,    .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_BGRA5551,    .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_RGB565,      .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_BGR565,      .depth = 16, .bpp = 16 },
+        { .format = DRM_FORMAT_RGB888,      .depth = 24, .bpp = 24 },
+        { .format = DRM_FORMAT_BGR888,      .depth = 24, .bpp = 24 },
+        { .format = DRM_FORMAT_XRGB8888,    .depth = 24, .bpp = 32 },
+        { .format = DRM_FORMAT_XBGR8888,    .depth = 24, .bpp = 32 },
+        { .format = DRM_FORMAT_RGBX8888,    .depth = 24, .bpp = 32 },
+        { .format = DRM_FORMAT_BGRX8888,    .depth = 24, .bpp = 32 },
+        { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .bpp = 32 },
+        { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .bpp = 32 },
+        { .format = DRM_FORMAT_RGBX1010102, .depth = 30, .bpp = 32 },
+        { .format = DRM_FORMAT_BGRX1010102, .depth = 30, .bpp = 32 },
+        { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .bpp = 32 },
+        { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .bpp = 32 },
+        { .format = DRM_FORMAT_RGBA1010102, .depth = 30, .bpp = 32 },
+        { .format = DRM_FORMAT_BGRA1010102, .depth = 30, .bpp = 32 },
+        { .format = DRM_FORMAT_ARGB8888,    .depth = 32, .bpp = 32 },
+        { .format = DRM_FORMAT_ABGR8888,    .depth = 32, .bpp = 32 },
+        { .format = DRM_FORMAT_RGBA8888,    .depth = 32, .bpp = 32 },
+        { .format = DRM_FORMAT_BGRA8888,    .depth = 32, .bpp = 32 },
+    };
+
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+        if (formats[i].format == format)
+            return &formats[i];
+    }
+
+    return NULL;
+}
+
 /**
  * glamor_get_drawable_pixmap() returns a backing pixmap for a given drawable.
  *
diff --git a/glamor/glamor.h b/glamor/glamor.h
index 4ad28df17..fdf265075 100644
--- a/glamor/glamor.h
+++ b/glamor/glamor.h
@@ -60,6 +60,14 @@ typedef enum glamor_pixmap_type {
     GLAMOR_TEXTURE_ONLY,
 } glamor_pixmap_type_t;
 
+struct drm_format_info {
+    uint32_t format;
+    uint32_t depth;
+    uint32_t bpp;
+};
+
+extern _X_EXPORT const struct drm_format_info * drm_format_get_info(uint32_t format);
+
 #define GLAMOR_EGL_EXTERNAL_BUFFER 3
 #define GLAMOR_USE_EGL_SCREEN		(1 << 0)
 #define GLAMOR_NO_DRI3			(1 << 1)
@@ -225,26 +233,6 @@ extern _X_EXPORT int glamor_name_from_pixmap(PixmapPtr pixmap,
 extern _X_EXPORT struct gbm_bo *glamor_gbm_bo_from_pixmap(ScreenPtr screen,
                                                           PixmapPtr pixmap);
 
-/* @glamor_pixmap_from_fd: Creates a pixmap to wrap a dma-buf fd.
- *
- * @screen: Current screen pointer.
- * @fd: The dma-buf fd to import.
- * @width: The width of the buffer.
- * @height: The height of the buffer.
- * @stride: The stride of the buffer.
- * @depth: The depth of the buffer.
- * @bpp: The number of bpp of the buffer.
- *
- * Returns a valid pixmap if the import succeeded, else NULL.
- * */
-extern _X_EXPORT PixmapPtr glamor_pixmap_from_fd(ScreenPtr screen,
-                                                 int fd,
-                                                 CARD16 width,
-                                                 CARD16 height,
-                                                 CARD16 stride,
-                                                 CARD8 depth,
-                                                 CARD8 bpp);
-
 /* @glamor_back_pixmap_from_fd: Backs an existing pixmap with a dma-buf fd.
  *
  * @pixmap: Pixmap to change backing for
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index 91b34a4bb..762908203 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -56,6 +56,7 @@ struct glamor_egl_screen_private {
     CloseScreenProcPtr CloseScreen;
     int fd;
     struct gbm_device *gbm;
+    int dmabuf_capable;
     int modifiers_capable;
 
     CloseScreenProcPtr saved_close_screen;
@@ -235,6 +236,121 @@ glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap,
     return ret;
 }
 
+static Bool
+glamor_egl_create_textured_pixmap_from_dmabuf(PixmapPtr pixmap,
+                                              CARD8 num_fds, int *fds,
+                                              CARD16 width, CARD16 height,
+                                              CARD32 *strides, CARD32 *offsets,
+                                              CARD32 format, uint64_t modifier)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+    return FALSE;
+#else
+    ScreenPtr screen = pixmap->drawable.pScreen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    struct glamor_screen_private *glamor_priv =
+        glamor_get_screen_private(screen);
+    struct glamor_egl_screen_private *glamor_egl;
+    EGLImageKHR image;
+    GLuint texture;
+    EGLint attribs[30];
+    int atti = 0;
+
+    glamor_egl = glamor_egl_get_screen_private(scrn);
+    assert(glamor_egl->dmabuf_capable);
+
+    glamor_make_current(glamor_priv);
+
+    attribs[atti++] = EGL_WIDTH;
+    attribs[atti++] = width;
+    attribs[atti++] = EGL_HEIGHT;
+    attribs[atti++] = height;
+    attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+    attribs[atti++] = format;
+
+    if (num_fds > 0) {
+        attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+        attribs[atti++] = fds[0];
+        attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+        attribs[atti++] = offsets[0];
+        attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+        attribs[atti++] = strides[0];
+        if (modifier) {
+            attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
+            attribs[atti++] = modifier & 0xffffffff;
+            attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
+            attribs[atti++] = modifier >> 32;
+        }
+    }
+
+    if (num_fds > 1) {
+        attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
+        attribs[atti++] = fds[1];
+        attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
+        attribs[atti++] = offsets[1];
+        attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
+        attribs[atti++] = strides[1];
+        if (modifier) {
+            attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
+            attribs[atti++] = modifier & 0xffffffff;
+            attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
+            attribs[atti++] = modifier >> 32;
+        }
+    }
+
+    if (num_fds > 2) {
+        attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
+        attribs[atti++] = fds[2];
+        attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
+        attribs[atti++] = offsets[2];
+        attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
+        attribs[atti++] = strides[2];
+        if (modifier) {
+            attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
+            attribs[atti++] = modifier & 0xffffffff;
+            attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
+            attribs[atti++] = modifier >> 32;
+        }
+    }
+
+    if (num_fds > 3) {
+        if (!glamor_egl->modifiers_capable) {
+            glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+            return FALSE;
+        }
+#ifdef EGL_EXT_image_dma_buf_import_modifiers
+        attribs[atti++] = EGL_DMA_BUF_PLANE3_FD_EXT;
+        attribs[atti++] = fds[3];
+        attribs[atti++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
+        attribs[atti++] = offsets[3];
+        attribs[atti++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
+        attribs[atti++] = strides[3];
+        if (modifier) {
+            attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
+            attribs[atti++] = modifier & 0xffffffff;
+            attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
+            attribs[atti++] = modifier >> 32;
+        }
+#endif
+    }
+
+    attribs[atti++] = EGL_NONE;
+
+    image = eglCreateImageKHR(glamor_egl->display, EGL_NO_CONTEXT,
+                              EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
+    if (image == EGL_NO_IMAGE_KHR) {
+        glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+        return FALSE;
+    }
+    glamor_create_texture_from_image(screen, image, &texture);
+    glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+    glamor_set_pixmap_texture(pixmap, texture);
+    glamor_egl_set_pixmap_image(pixmap, image);
+
+    return TRUE;
+#endif
+}
+
 static void
 glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name)
 {
@@ -396,20 +512,39 @@ glamor_back_pixmap_from_fd(PixmapPtr pixmap,
     return ret;
 }
 
-_X_EXPORT PixmapPtr
-glamor_pixmap_from_fd(ScreenPtr screen,
-                      int fd,
-                      CARD16 width,
-                      CARD16 height,
-                      CARD16 stride, CARD8 depth, CARD8 bpp)
+static PixmapPtr
+glamor_pixmap_from_fds(ScreenPtr screen,
+                       CARD8 num_fds, int *fds,
+                       CARD16 width, CARD16 height,
+                       CARD32 *strides, CARD32 *offsets,
+                       CARD32 format, uint64_t modifier)
 {
     PixmapPtr pixmap;
-    Bool ret;
+    struct glamor_egl_screen_private *glamor_egl;
+    const struct drm_format_info *info;
+    Bool ret = FALSE;
+    int i;
+
+    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+    info = drm_format_get_info(format);
+
+    pixmap = screen->CreatePixmap(screen, 0, 0, info->depth, 0);
+
+    if (glamor_egl->dmabuf_capable) {
+        screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL); // XXX what is the stride used for?
+        ret = glamor_egl_create_textured_pixmap_from_dmabuf(pixmap, num_fds, fds,
+                                                            width, height,
+                                                            strides, offsets,
+                                                            format, modifier);
+    } else if (num_fds == 1) {
+        ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height,
+                                         strides[0], info->depth, info->bpp);
+    }
 
-    pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
-    ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height,
-                                     stride, depth, bpp);
     if (ret == FALSE) {
+        for (i = 0; i < num_fds; i++)
+            close(fds[i]);
         screen->DestroyPixmap(pixmap);
         return NULL;
     }
@@ -501,6 +636,7 @@ glamor_egl_destroy_pixmap(PixmapPtr pixmap)
     struct glamor_egl_screen_private *glamor_egl =
         glamor_egl_get_screen_private(scrn);
     Bool ret;
+    int i;
 
     if (pixmap->refcnt == 1) {
         struct glamor_pixmap_private *pixmap_priv =
@@ -612,7 +748,7 @@ glamor_dri3_open_client(ClientPtr client,
 static dri3_screen_info_rec glamor_dri3_info = {
     .version = 1,
     .open_client = glamor_dri3_open_client,
-    .pixmap_from_fd = glamor_pixmap_from_fd,
+    .pixmap_from_fds = glamor_pixmap_from_fds,
     .fd_from_pixmap = glamor_fd_from_pixmap,
     .get_formats = glamor_get_formats,
     .get_modifiers = glamor_get_modifiers,
@@ -815,6 +951,9 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
                glGetString(GL_RENDERER));
 
     if (epoxy_has_egl_extension(glamor_egl->display,
+                                "EXT_image_dma_buf_import"))
+        glamor_egl->dmabuf_capable = TRUE;
+    if (epoxy_has_egl_extension(glamor_egl->display,
                                 "EXT_image_dma_buf_import_modifiers"))
         glamor_egl->modifiers_capable = TRUE;
 
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 0273f5f16..ddf93bce6 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -45,6 +45,13 @@ struct xwl_pixmap {
     struct gbm_bo *bo;
     void *image;
     unsigned int texture;
+
+    int num_fds;
+    int fds[4];
+    uint32_t strides[4];
+    uint32_t offsets[4];
+    uint32_t format;
+    uint64_t modifier;
 };
 
 static void
@@ -152,6 +159,147 @@ xwl_glamor_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, int depth)
     return pixmap;
 }
 
+static PixmapPtr
+xwl_glamor_create_pixmap_for_dmabuf(ScreenPtr screen, CARD8 num_fds, int *fds,
+                                    CARD16 width, CARD16 height,
+                                    CARD32 *strides, CARD32 *offsets,
+                                    CARD32 format, uint64_t modifier)
+{
+#ifndef EGL_EXT_image_dma_buf_import
+    return NULL;
+#else
+    PixmapPtr pixmap;
+    struct xwl_pixmap *xwl_pixmap;
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    const struct drm_format_info *info;
+    EGLint attribs[30];
+    int atti = 0;
+    int i;
+
+    xwl_pixmap = malloc(sizeof *xwl_pixmap);
+    if (xwl_pixmap == NULL)
+        return NULL;
+
+    info = drm_format_get_info(format);
+    pixmap = glamor_create_pixmap(screen, width, height, info->depth,
+                                  GLAMOR_CREATE_PIXMAP_NO_TEXTURE);
+    if (pixmap == NULL) {
+        free(xwl_pixmap);
+        return NULL;
+    }
+
+    attribs[atti++] = EGL_WIDTH;
+    attribs[atti++] = width;
+    attribs[atti++] = EGL_HEIGHT;
+    attribs[atti++] = height;
+    attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+    attribs[atti++] = format;
+
+    if (num_fds > 0) {
+        attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+        attribs[atti++] = fds[0];
+        attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+        attribs[atti++] = offsets[0];
+        attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+        attribs[atti++] = strides[0];
+        if (modifier) {
+            attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
+            attribs[atti++] = modifier & 0xffffffff;
+            attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
+            attribs[atti++] = modifier >> 32;
+        }
+    }
+
+    if (num_fds > 1) {
+        attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
+        attribs[atti++] = fds[1];
+        attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
+        attribs[atti++] = offsets[1];
+        attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
+        attribs[atti++] = strides[1];
+        if (modifier) {
+            attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
+            attribs[atti++] = modifier & 0xffffffff;
+            attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
+            attribs[atti++] = modifier >> 32;
+        }
+    }
+
+    if (num_fds > 2) {
+        attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
+        attribs[atti++] = fds[2];
+        attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
+        attribs[atti++] = offsets[2];
+        attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
+        attribs[atti++] = strides[2];
+        if (modifier) {
+            attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
+            attribs[atti++] = modifier & 0xffffffff;
+            attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
+            attribs[atti++] = modifier >> 32;
+        }
+    }
+
+    if (num_fds > 3) {
+        if (!xwl_screen->modifiers_capable) {
+            glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+            return NULL;
+        }
+#ifdef EGL_EXT_image_dma_buf_import_modifiers
+        attribs[atti++] = EGL_DMA_BUF_PLANE3_FD_EXT;
+        attribs[atti++] = fds[3];
+        attribs[atti++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
+        attribs[atti++] = offsets[3];
+        attribs[atti++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
+        attribs[atti++] = strides[3];
+        if (modifier) {
+            attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
+            attribs[atti++] = modifier & 0xffffffff;
+            attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
+            attribs[atti++] = modifier >> 32;
+        }
+#endif
+    }
+
+    attribs[atti++] = EGL_NONE;
+
+    if (lastGLContext != xwl_screen->glamor_ctx) {
+        lastGLContext = xwl_screen->glamor_ctx;
+        xwl_glamor_egl_make_current(xwl_screen->glamor_ctx);
+    }
+
+    xwl_pixmap->bo = NULL;
+    xwl_pixmap->buffer = NULL;
+    xwl_pixmap->num_fds = num_fds;
+    for (i = 0; i < num_fds; i++) {
+       xwl_pixmap->fds[i] = fds[i];
+       xwl_pixmap->strides[i] = strides[i];
+       xwl_pixmap->offsets[i] = offsets[i];
+    }
+    xwl_pixmap->format = format;
+    xwl_pixmap->modifier = modifier;
+    xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
+                                          xwl_screen->egl_context,
+                                          EGL_LINUX_DMA_BUF_EXT,
+                                          NULL, attribs);
+
+    glGenTextures(1, &xwl_pixmap->texture);
+    glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    xwl_pixmap_set_private(pixmap, xwl_pixmap);
+
+    glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture);
+    glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+
+    return pixmap;
+#endif
+}
+
 struct wl_buffer *
 xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
 {
@@ -162,6 +310,10 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
     if (xwl_pixmap->buffer)
         return xwl_pixmap->buffer;
 
+    /* XXX If xwl_pimxap is not backed by a bo (dmabuf),
+     * should we create a wl_buffer using the zwp_linux_dmabuf
+     * interface? Is it safe to use in Xorg server? */
+
     prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
     if (prime_fd == -1)
         return NULL;
@@ -213,7 +365,8 @@ xwl_glamor_destroy_pixmap(PixmapPtr pixmap)
             wl_buffer_destroy(xwl_pixmap->buffer);
 
         eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
-        gbm_bo_destroy(xwl_pixmap->bo);
+        if (xwl_pixmap->bo)
+           gbm_bo_destroy(xwl_pixmap->bo);
         free(xwl_pixmap);
     }
 
@@ -332,6 +485,9 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen)
     }
 
     if (epoxy_has_egl_extension(xwl_screen->egl_display,
+                                "EXT_image_dma_buf_import"))
+       xwl_screen->dmabuf_capable = TRUE;
+    if (epoxy_has_egl_extension(xwl_screen->egl_display,
                                 "EXT_image_dma_buf_import_modifiers"))
        xwl_screen->modifiers_capable = TRUE;
 
@@ -527,33 +683,48 @@ xwl_dri3_open_client(ClientPtr client,
 }
 
 static PixmapPtr
-xwl_dri3_pixmap_from_fd(ScreenPtr screen, int fd,
-                        CARD16 width, CARD16 height, CARD16 stride,
-                        CARD8 depth, CARD8 bpp)
+xwl_dri3_pixmap_from_fds(ScreenPtr screen,
+                         CARD8 num_fds, int *fds,
+                         CARD16 width, CARD16 height,
+                         CARD32 *strides, CARD32 *offsets,
+                         CARD32 format, uint64_t modifier)
 {
     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
     struct gbm_import_fd_data data;
     struct gbm_bo *bo;
+    const struct drm_format_info *info;
     PixmapPtr pixmap;
 
-    if (width == 0 || height == 0 ||
-        depth < 15 || bpp != BitsPerPixel(depth) || stride < width * bpp / 8)
-        return NULL;
+    info = drm_format_get_info(format);
 
-    data.fd = fd;
-    data.width = width;
-    data.height = height;
-    data.stride = stride;
-    data.format = gbm_format_for_depth(depth);
-    bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
-                       GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
-    if (bo == NULL)
+    if (width == 0 || height == 0 || num_fds == 0 ||
+        info->depth < 15 || info->bpp != BitsPerPixel(info->depth) ||
+        strides[0] < width * info->bpp / 8) // XXX Does this condition still make sense?
         return NULL;
 
-    pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
-    if (pixmap == NULL) {
-        gbm_bo_destroy(bo);
-        return NULL;
+    if (xwl_screen->dmabuf_capable) {
+      pixmap = xwl_glamor_create_pixmap_for_dmabuf(screen, num_fds, fds,
+                                                   width, height,
+                                                   strides, offsets,
+                                                   format, modifier);
+    } else if (num_fds == 1) {
+       data.fd = fds[0];
+       data.width = width;
+       data.height = height;
+       data.stride = strides[0];
+       data.format = gbm_format_for_depth(info->depth);
+       bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
+             GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+       if (bo == NULL)
+          return NULL;
+
+       pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, info->depth);
+       if (pixmap == NULL) {
+          gbm_bo_destroy(bo);
+          return NULL;
+       }
+    } else {
+       return NULL;
     }
 
     return pixmap;
@@ -649,7 +820,7 @@ xwl_dri3_get_modifiers(ScreenPtr screen, CARD32 format,
 static dri3_screen_info_rec xwl_dri3_info = {
     .version = 1,
     .open = NULL,
-    .pixmap_from_fd = xwl_dri3_pixmap_from_fd,
+    .pixmap_from_fds = xwl_dri3_pixmap_from_fds,
     .fd_from_pixmap = xwl_dri3_fd_from_pixmap,
     .open_client = xwl_dri3_open_client,
     .get_formats = xwl_dri3_get_formats,
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 30f7de026..df2a3087d 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -99,6 +99,7 @@ struct xwl_screen {
     void *egl_display, *egl_context;
     struct gbm_device *gbm;
     struct glamor_context *glamor_ctx;
+    int dmabuf_capable;
     int modifiers_capable;
 
     Atom allow_commits_prop;
-- 
2.13.0



More information about the xorg-devel mailing list