[RFC xserver 04/16] DRI3: Implement GetSupportedFormats and GetSupportedModifiers

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


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

Use EGL extension EXT_image_dma_buf_modifiers to query supported
DMA-BUF formats and modifiers to return to DRI3 clients. The
information is cached to avoid having to fetch it again for
each new client.

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 dri3/dri3.h                   |  12 +++++
 dri3/dri3_priv.h              |  18 +++++++
 dri3/dri3_request.c           |  13 +++--
 dri3/dri3_screen.c            | 121 ++++++++++++++++++++++++++++++++++++++++++
 glamor/glamor_egl.c           |  84 +++++++++++++++++++++++++++++
 hw/xwayland/xwayland-glamor.c |  79 +++++++++++++++++++++++++++
 hw/xwayland/xwayland.h        |   1 +
 7 files changed, 325 insertions(+), 3 deletions(-)

diff --git a/dri3/dri3.h b/dri3/dri3.h
index 7562352ff..40b8474c0 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -52,12 +52,24 @@ typedef int (*dri3_fd_from_pixmap_proc) (ScreenPtr screen,
                                          CARD16 *stride,
                                          CARD32 *size);
 
+typedef int (*dri3_get_formats_proc) (ScreenPtr screen,
+                                      CARD32 *num_formats,
+                                      CARD32 **formats);
+
+typedef int (*dri3_get_modifiers_proc) (ScreenPtr screen,
+                                        CARD32 format,
+                                        CARD32 *num_modifiers,
+                                        uint64_t **modifiers);
+
+
 typedef struct dri3_screen_info {
     uint32_t                    version;
 
     dri3_open_proc              open;
     dri3_pixmap_from_fd_proc    pixmap_from_fd;
     dri3_fd_from_pixmap_proc    fd_from_pixmap;
+    dri3_get_formats_proc       get_formats;
+    dri3_get_modifiers_proc     get_modifiers;
 
     /* Version 1 */
     dri3_open_client_proc       open_client;
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index e61ef226c..c767f373e 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -34,11 +34,22 @@
 
 extern DevPrivateKeyRec dri3_screen_private_key;
 
+typedef struct dri3_dmabuf_format {
+    CARD32                      format;
+    CARD32                      num_modifiers;
+    CARD32                     *modifiers_hi;
+    CARD32                     *modifiers_lo;
+} dri3_dmabuf_format_rec, *dri3_dmabuf_format_ptr;
+
 typedef struct dri3_screen_priv {
     CloseScreenProcPtr          CloseScreen;
     ConfigNotifyProcPtr         ConfigNotify;
     DestroyWindowProcPtr        DestroyWindow;
 
+    Bool                        formats_cached;
+    CARD32                      num_formats;
+    dri3_dmabuf_format_ptr      formats;
+
     dri3_screen_info_ptr        info;
 } dri3_screen_priv_rec, *dri3_screen_priv_ptr;
 
@@ -75,4 +86,11 @@ dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
 int
 dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
 
+int
+dri3_get_supported_formats(ScreenPtr screen, CARD32 *num_formats, CARD32 **formats);
+
+int
+dri3_get_supported_modifiers(ScreenPtr screen, CARD32 format, CARD32 *num_modifiers,
+                             CARD32 **modifiers_hi, CARD32 **modifiers_lo);
+
 #endif /* _DRI3PRIV_H_ */
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index 336175d92..35f1c2533 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -310,9 +310,9 @@ proc_dri3_get_supported_formats(ClientPtr client)
     DrawablePtr drawable;
     ScreenPtr pScreen;
     CARD32 *formats = NULL;
-    int nformats = 0;
+    CARD32 nformats = 0;
+    CARD32 i;
     int status;
-    int i;
 
     REQUEST_SIZE_MATCH(xDRI3GetSupportedFormatsReq);
 
@@ -322,6 +322,8 @@ proc_dri3_get_supported_formats(ClientPtr client)
         return status;
     pScreen = drawable->pScreen;
 
+    dri3_get_supported_formats(pScreen, &nformats, &formats);
+
     rep.numFormats = nformats;
     rep.length = bytes_to_int32(rep.numFormats * sizeof(CARD32));
 
@@ -336,6 +338,8 @@ proc_dri3_get_supported_formats(ClientPtr client)
     WriteToClient(client, sizeof(rep), &rep);
     WriteToClient(client, nformats * sizeof(CARD32), formats);
 
+    free(formats);
+
     return Success;
 }
 
@@ -351,7 +355,7 @@ proc_dri3_get_supported_modifiers(ClientPtr client)
     ScreenPtr pScreen;
     CARD32 *modifiers_hi = NULL;
     CARD32 *modifiers_lo = NULL;
-    int nmodifiers = 0;
+    CARD32 nmodifiers = 0;
     int status;
     int i;
 
@@ -363,6 +367,9 @@ proc_dri3_get_supported_modifiers(ClientPtr client)
         return status;
     pScreen = drawable->pScreen;
 
+    dri3_get_supported_modifiers(pScreen, stuff->format, &nmodifiers,
+                                 &modifiers_hi, &modifiers_lo);
+
     rep.numModifiers = nmodifiers;
     rep.length = bytes_to_int32(2 * rep.numModifiers * sizeof(CARD32));
 
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 6c0c60cbf..4d4f77bcf 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -96,3 +96,124 @@ dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
     return Success;
 }
 
+static int
+cache_formats_and_modifiers(ScreenPtr screen)
+{
+    dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
+    dri3_screen_info_ptr        info = ds->info;
+    CARD32                     *formats = NULL;
+    uint64_t                   *modifiers = NULL;
+    int                         i, j;
+
+    if (ds->formats_cached)
+        return Success;
+
+    if (!info || !info->get_formats || !info->get_modifiers)
+        return BadImplementation;
+
+    (*info->get_formats) (screen, &ds->num_formats, &formats);
+    ds->formats = calloc(ds->num_formats, sizeof(dri3_dmabuf_format_rec));
+    if (!ds->formats)
+        return BadAlloc;
+
+    for (i = 0; i < ds->num_formats; i++) {
+        dri3_dmabuf_format_ptr iter = &ds->formats[i];
+
+        iter->format = formats[i];
+        (*info->get_modifiers) (screen, formats[i],
+                                &iter->num_modifiers,
+                                &modifiers);
+
+        iter->modifiers_hi = malloc(iter->num_modifiers * sizeof(CARD32));
+        if (iter->modifiers_hi == NULL)
+            goto error;
+        iter->modifiers_lo = malloc(iter->num_modifiers * sizeof(CARD32));
+        if (iter->modifiers_lo == NULL)
+            goto error;
+
+        for (j = 0; j < iter->num_modifiers; j++) {
+            iter->modifiers_hi[j] = modifiers[j] >> 32;
+            iter->modifiers_lo[j] = modifiers[j] & 0xffffffff;
+        }
+        goto done;
+
+error:
+        iter->num_modifiers = 0;
+        free(iter->modifiers_hi);
+        free(iter->modifiers_lo);
+done:
+        free(modifiers);
+    }
+    free(formats);
+    ds->formats_cached = TRUE;
+
+    return Success;
+}
+
+int
+dri3_get_supported_formats(ScreenPtr screen, CARD32 *num_formats,
+                           CARD32 **formats)
+{
+    dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
+    int                         i;
+    int                         ret;
+
+    ret = cache_formats_and_modifiers(screen);
+    if (ret != Success)
+        return ret;
+
+    *formats = malloc(ds->num_formats * sizeof(CARD32));
+    if (!*formats) {
+        *num_formats = 0;
+        return BadAlloc;
+    }
+
+    *num_formats = ds->num_formats;
+    for (i = 0; i < ds->num_formats; i++)
+        *formats[i] = ds->formats[i].format;
+
+    return Success;
+}
+
+int
+dri3_get_supported_modifiers(ScreenPtr screen,
+                             CARD32 format, CARD32 *num_modifiers,
+                             CARD32 **modifiers_hi, CARD32 **modifiers_lo)
+{
+    dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
+    int                         i;
+    int                         ret;
+
+    ret = cache_formats_and_modifiers(screen);
+    if (ret != Success)
+        return ret;
+
+    // XXX We don't really need a copy, but without it we're kind of asymetric
+    //     with the get_formats API...
+    for (i = 0; i < ds->num_formats; i++) {
+        if (ds->formats[i].format == format) {
+            *modifiers_hi = malloc(ds->formats[i].num_modifiers * sizeof(CARD32));
+            if (!*modifiers_hi) {
+                *num_modifiers = 0;
+                return BadAlloc;
+            }
+            *modifiers_lo = malloc(ds->formats[i].num_modifiers * sizeof(CARD32));
+            if (!*modifiers_lo) {
+                *num_modifiers = 0;
+                free(*modifiers_hi);
+                *modifiers_hi = NULL;
+                return BadAlloc;
+            }
+
+            *num_modifiers = ds->formats[i].num_modifiers;
+            memcpy(*modifiers_hi, ds->formats[i].modifiers_hi,
+                   ds->formats[i].num_modifiers * sizeof(CARD32));
+            memcpy(*modifiers_lo, ds->formats[i].modifiers_lo,
+                   ds->formats[i].num_modifiers * sizeof(CARD32));
+
+            return Success;
+        }
+    }
+
+    return BadMatch;
+}
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index b0d3e9efe..91b34a4bb 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 modifiers_capable;
 
     CloseScreenProcPtr saved_close_screen;
     DestroyPixmapProcPtr saved_destroy_pixmap;
@@ -416,6 +417,83 @@ glamor_pixmap_from_fd(ScreenPtr screen,
 }
 
 static Bool
+glamor_get_formats(ScreenPtr screen,
+                   CARD32 *num_formats, CARD32 **formats)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+    return FALSE;
+#else
+    struct glamor_egl_screen_private *glamor_egl;
+    EGLint num;
+
+    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+    if (!glamor_egl->modifiers_capable)
+        return FALSE;
+
+    if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num)) {
+        *num_formats = 0;
+        return FALSE;
+    }
+
+    *formats = calloc(num, sizeof(CARD32));
+    if (*formats == NULL) {
+        *num_formats = 0;
+        return FALSE;
+    }
+
+    if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num,
+                                  (EGLint *) *formats, &num)) {
+        *num_formats = 0;
+        free(*formats);
+        return FALSE;
+    }
+
+    *num_formats = num;
+    return TRUE;
+#endif
+}
+
+static Bool
+glamor_get_modifiers(ScreenPtr screen, CARD32 format,
+                     CARD32 *num_modifiers, uint64_t **modifiers)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+    return FALSE;
+#else
+    struct glamor_egl_screen_private *glamor_egl;
+    EGLint num;
+
+    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+    if (!glamor_egl->modifiers_capable)
+        return FALSE;
+
+    if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL,
+                                    NULL, &num)) {
+        *num_modifiers = 0;
+        return FALSE;
+    }
+
+    *modifiers = calloc(num, sizeof(uint64_t));
+    if (*modifiers == NULL) {
+        *num_modifiers = 0;
+        return FALSE;
+    }
+
+    if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num,
+                                    (EGLuint64KHR *) *modifiers, NULL, &num)) {
+        *num_modifiers = 0;
+        free(*modifiers);
+        return FALSE;
+    }
+
+    *num_modifiers = num;
+    return TRUE;
+#endif
+}
+
+static Bool
 glamor_egl_destroy_pixmap(PixmapPtr pixmap)
 {
     ScreenPtr screen = pixmap->drawable.pScreen;
@@ -536,6 +614,8 @@ static dri3_screen_info_rec glamor_dri3_info = {
     .open_client = glamor_dri3_open_client,
     .pixmap_from_fd = glamor_pixmap_from_fd,
     .fd_from_pixmap = glamor_fd_from_pixmap,
+    .get_formats = glamor_get_formats,
+    .get_modifiers = glamor_get_modifiers,
 };
 #endif /* DRI3 */
 
@@ -734,6 +814,10 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
     xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n",
                glGetString(GL_RENDERER));
 
+    if (epoxy_has_egl_extension(glamor_egl->display,
+                                "EXT_image_dma_buf_import_modifiers"))
+        glamor_egl->modifiers_capable = TRUE;
+
     glamor_egl->saved_free_screen = scrn->FreeScreen;
     scrn->FreeScreen = glamor_egl_free_screen;
     return TRUE;
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 87622839e..0273f5f16 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -331,6 +331,10 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen)
         return;
     }
 
+    if (epoxy_has_egl_extension(xwl_screen->egl_display,
+                                "EXT_image_dma_buf_import_modifiers"))
+       xwl_screen->modifiers_capable = TRUE;
+
     return;
 }
 
@@ -569,12 +573,87 @@ xwl_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
     return gbm_bo_get_fd(xwl_pixmap->bo);
 }
 
+static int
+xwl_dri3_get_formats(ScreenPtr screen,
+                     CARD32 *num_formats, CARD32 **formats)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+    return FALSE;
+#else
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    EGLint num;
+
+    if (!xwl_screen->modifiers_capable)
+        return FALSE;
+
+    if (!eglQueryDmaBufFormatsEXT(xwl_screen->egl_display, 0, NULL, &num)) {
+        *num_formats = 0;
+        return FALSE;
+    }
+
+    *formats = calloc(num, sizeof(CARD32));
+    if (*formats == NULL) {
+        *num_formats = 0;
+        return FALSE;
+    }
+
+    if (!eglQueryDmaBufFormatsEXT(xwl_screen->egl_display, num, (EGLint *) *formats, &num)) {
+        *num_formats = 0;
+        free(*formats);
+        return FALSE;
+    }
+
+    *num_formats = num;
+    return TRUE;
+#endif
+}
+
+static int
+xwl_dri3_get_modifiers(ScreenPtr screen, CARD32 format,
+                       CARD32 *num_modifiers, uint64_t **modifiers)
+{
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+    return FALSE;
+#else
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    EGLint num;
+
+    if (!xwl_screen->modifiers_capable)
+        return FALSE;
+
+    if (!eglQueryDmaBufModifiersEXT(xwl_screen->egl_display, format, 0, NULL,
+                                    NULL, &num)) {
+        *num_modifiers = 0;
+        return FALSE;
+    }
+
+    *modifiers = calloc(num, sizeof(uint64_t));
+    if (*modifiers == NULL) {
+        *num_modifiers = 0;
+        return FALSE;
+    }
+
+    if (!eglQueryDmaBufModifiersEXT(xwl_screen->egl_display, format, num,
+                                  *modifiers, NULL, &num)) {
+        *num_modifiers = 0;
+        free(*modifiers);
+        return FALSE;
+    }
+
+    *num_modifiers = num;
+    return TRUE;
+#endif
+}
+
+
 static dri3_screen_info_rec xwl_dri3_info = {
     .version = 1,
     .open = NULL,
     .pixmap_from_fd = xwl_dri3_pixmap_from_fd,
     .fd_from_pixmap = xwl_dri3_fd_from_pixmap,
     .open_client = xwl_dri3_open_client,
+    .get_formats = xwl_dri3_get_formats,
+    .get_modifiers = xwl_dri3_get_modifiers,
 };
 
 Bool
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index a05e0862c..30f7de026 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 modifiers_capable;
 
     Atom allow_commits_prop;
 };
-- 
2.13.0



More information about the xorg-devel mailing list