[RFC xserver v6 03/14] dri3: Add multi-planar/modifier buffer requests

Louis-Francis Ratté-Boulianne lfrb at collabora.com
Fri Feb 16 04:15:36 UTC 2018


Initial implementation for DRI3 v1.1. Only the DRI3 implementation
is there, backends need to implement the proper hooks.

Version is still set to 1.0 so clients shouldn't use the new
requests yet.

v2: Use depth/bpp instead of DRM formats in requests

v3: Remove DMA fence requests from v1.1
    Add screen/drawable modifier sets

v4: Free array returned by 'get_drawable_modifiers()'

v5: Fix FD leak

v6: Fix FD leak on error
    Add some checks

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
---
 configure.ac                  |   2 +-
 dri3/dri3.c                   |  19 +++
 dri3/dri3.h                   |  44 ++++++-
 dri3/dri3_priv.h              |  27 +++-
 dri3/dri3_request.c           | 293 ++++++++++++++++++++++++++++++++++++++++--
 dri3/dri3_screen.c            | 196 ++++++++++++++++++++++++++--
 hw/xwayland/xwayland-glamor.c |   4 +-
 meson.build                   |   2 +-
 8 files changed, 558 insertions(+), 29 deletions(-)

diff --git a/configure.ac b/configure.ac
index 98b8ea2ed..20f53d2a9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -729,7 +729,7 @@ SCRNSAVERPROTO="scrnsaverproto >= 1.1"
 RESOURCEPROTO="resourceproto >= 1.2.0"
 DRIPROTO="xf86driproto >= 2.1.0"
 DRI2PROTO="dri2proto >= 2.8"
-DRI3PROTO="dri3proto >= 1.0"
+DRI3PROTO="dri3proto >= 1.1"
 XINERAMAPROTO="xineramaproto"
 BIGFONTPROTO="xf86bigfontproto >= 1.2.0"
 DGAPROTO="xf86dgaproto >= 2.0.99.1"
diff --git a/dri3/dri3.c b/dri3/dri3.c
index d042b8b7d..8ac0f3ae2 100644
--- a/dri3/dri3.c
+++ b/dri3/dri3.c
@@ -26,6 +26,8 @@
 
 #include "dri3_priv.h"
 
+#include <drm_fourcc.h>
+
 static int dri3_request;
 DevPrivateKeyRec dri3_screen_private_key;
 
@@ -99,3 +101,20 @@ dri3_extension_init(void)
 bail:
     FatalError("Cannot initialize DRI3 extension");
 }
+
+uint32_t
+drm_format_for_depth(uint32_t depth, uint32_t bpp)
+{
+    switch (bpp) {
+        case 16:
+            return DRM_FORMAT_RGB565;
+        case 24:
+            return DRM_FORMAT_XRGB8888;
+        case 30:
+            return DRM_FORMAT_XRGB2101010;
+        case 32:
+            return DRM_FORMAT_ARGB8888;
+        default:
+            return 0;
+    }
+}
diff --git a/dri3/dri3.h b/dri3/dri3.h
index 7562352ff..89ad13ad9 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -28,7 +28,7 @@
 #include <X11/extensions/dri3proto.h>
 #include <randrstr.h>
 
-#define DRI3_SCREEN_INFO_VERSION        1
+#define DRI3_SCREEN_INFO_VERSION        2
 
 typedef int (*dri3_open_proc)(ScreenPtr screen,
                               RRProviderPtr provider,
@@ -47,11 +47,43 @@ typedef PixmapPtr (*dri3_pixmap_from_fd_proc) (ScreenPtr screen,
                                                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,
+                                                CARD8 depth,
+                                                CARD8 bpp,
+                                                CARD64 modifier);
+
 typedef int (*dri3_fd_from_pixmap_proc) (ScreenPtr screen,
                                          PixmapPtr pixmap,
                                          CARD16 *stride,
                                          CARD32 *size);
 
+typedef int (*dri3_fds_from_pixmap_proc) (ScreenPtr screen,
+                                          PixmapPtr pixmap,
+                                          int *fds,
+                                          CARD32 *strides,
+                                          CARD32 *offsets,
+                                          CARD64 *modifier);
+
+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,
+                                        CARD64 **modifiers);
+
+typedef int (*dri3_get_drawable_modifiers_proc) (DrawablePtr draw,
+                                                 CARD32 format,
+                                                 CARD32 *num_modifiers,
+                                                 CARD64 **modifiers);
+
 typedef struct dri3_screen_info {
     uint32_t                    version;
 
@@ -62,6 +94,13 @@ typedef struct dri3_screen_info {
     /* Version 1 */
     dri3_open_client_proc       open_client;
 
+    /* Version 2 */
+    dri3_pixmap_from_fds_proc   pixmap_from_fds;
+    dri3_fds_from_pixmap_proc   fds_from_pixmap;
+    dri3_get_formats_proc       get_formats;
+    dri3_get_modifiers_proc     get_modifiers;
+    dri3_get_drawable_modifiers_proc get_drawable_modifiers;
+
 } dri3_screen_info_rec, *dri3_screen_info_ptr;
 
 extern _X_EXPORT Bool
@@ -70,6 +109,9 @@ dri3_screen_init(ScreenPtr screen, dri3_screen_info_ptr info);
 extern _X_EXPORT int
 dri3_send_open_reply(ClientPtr client, int fd);
 
+extern _X_EXPORT uint32_t
+drm_format_for_depth(uint32_t depth, uint32_t bpp);
+
 #endif
 
 #endif /* _DRI3_H_ */
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index e61ef226c..8447680ba 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -34,11 +34,21 @@
 
 extern DevPrivateKeyRec dri3_screen_private_key;
 
+typedef struct dri3_dmabuf_format {
+    uint32_t                    format;
+    uint32_t                    num_modifiers;
+    uint64_t                   *modifiers;
+} 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;
 
@@ -69,10 +79,21 @@ 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,
+                     CARD8 depth, CARD8 bpp, CARD64 modifier);
+
+int
+dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+                     CARD32 *strides, CARD32 *offsets,
+                     CARD64 *modifier);
 
 int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
+dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
+                             CARD8 depth, CARD8 bpp,
+                             CARD32 *num_drawable_modifiers,
+                             CARD64 **drawable_modifiers,
+                             CARD32 *num_screen_modifiers,
+                             CARD64 **screen_modifiers);
 
 #endif /* _DRI3PRIV_H_ */
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index b28d883a5..c306934d5 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -30,6 +30,7 @@
 #include <xace.h>
 #include "../Xext/syncsdk.h"
 #include <protocol-versions.h>
+#include <drm_fourcc.h>
 
 static int
 proc_dri3_query_version(ClientPtr client)
@@ -124,6 +125,7 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
     int fd;
     DrawablePtr drawable;
     PixmapPtr pixmap;
+    CARD32 stride, offset;
     int rc;
 
     SetReqFds(client, 1);
@@ -159,11 +161,14 @@ 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;
+    rc = dri3_pixmap_from_fds(&pixmap,
+                              drawable->pScreen, 1, &fd,
+                              stuff->width, stuff->height,
+                              &stride, &offset,
+                              stuff->depth, stuff->bpp,
+                              DRM_FORMAT_MOD_INVALID);
     close (fd);
     if (rc != Success)
         return rc;
@@ -195,7 +200,10 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
         .length = 0,
     };
     int rc;
-    int fd;
+    int num_fds;
+    int fds[4];
+    uint32_t strides[4], offsets[4];
+    uint64_t modifier;
     PixmapPtr pixmap;
 
     REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
@@ -211,9 +219,12 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
     rep.depth = pixmap->drawable.depth;
     rep.bpp = pixmap->drawable.bitsPerPixel;
 
-    rc = dri3_fd_from_pixmap(&fd, pixmap, &rep.stride, &rep.size);
-    if (rc != Success)
-        return rc;
+    num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
+    if (num_fds != 1)
+        return BadPixmap;
+
+    rep.stride = (CARD16) strides[0];
+    rep.size = rep.stride * rep.height;
 
     if (client->swapped) {
         swaps(&rep.sequenceNumber);
@@ -223,8 +234,8 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
         swaps(&rep.height);
         swaps(&rep.stride);
     }
-    if (WriteFdToClient(client, fd, TRUE) < 0) {
-        close(fd);
+    if (WriteFdToClient(client, fds[0], TRUE) < 0) {
+        close(fds[0]);
         return BadAlloc;
     }
 
@@ -299,6 +310,215 @@ proc_dri3_fd_from_fence(ClientPtr client)
     return Success;
 }
 
+static int
+proc_dri3_get_supported_modifiers(ClientPtr client)
+{
+    REQUEST(xDRI3GetSupportedModifiersReq);
+    xDRI3GetSupportedModifiersReply rep = {
+        .type = X_Reply,
+        .sequenceNumber = client->sequence,
+    };
+    DrawablePtr drawable;
+    ScreenPtr pScreen;
+    CARD64 *drawable_modifiers = NULL;
+    CARD64 *screen_modifiers = NULL;
+    CARD32 ndrawablemodifiers = 0;
+    CARD32 nscreenmodifiers = 0;
+    int status;
+    int i;
+
+    REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
+
+    status = dixLookupDrawable(&drawable, stuff->window, client, 0,
+                               DixReadAccess);
+    if (status != Success)
+        return status;
+    pScreen = drawable->pScreen;
+
+    dri3_get_supported_modifiers(pScreen, drawable, stuff->depth, stuff->bpp,
+                                 &ndrawablemodifiers, &drawable_modifiers,
+                                 &nscreenmodifiers, &screen_modifiers);
+
+    rep.numDrawableModifiers = ndrawablemodifiers;
+    rep.numScreenModifiers = nscreenmodifiers;
+    rep.length = bytes_to_int32(rep.numDrawableModifiers * sizeof(CARD64)) +
+                 bytes_to_int32(rep.numScreenModifiers * sizeof(CARD64));
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swapl(&rep.numDrawableModifiers);
+        swapl(&rep.numScreenModifiers);
+        for (i = 0; i < ndrawablemodifiers; i++)
+            swapll(&drawable_modifiers[i]);
+        for (i = 0; i < nscreenmodifiers; i++)
+            swapll(&screen_modifiers[i]);
+    }
+
+    WriteToClient(client, sizeof(rep), &rep);
+    WriteToClient(client, ndrawablemodifiers * sizeof(CARD64), drawable_modifiers);
+    WriteToClient(client, nscreenmodifiers * sizeof(CARD64), screen_modifiers);
+
+    free(drawable_modifiers);
+    free(screen_modifiers);
+
+    return Success;
+}
+
+static int
+proc_dri3_pixmap_from_buffers(ClientPtr client)
+{
+    REQUEST(xDRI3PixmapFromBuffersReq);
+    int fds[4];
+    CARD32 strides[4], offsets[4];
+    DrawablePtr drawable;
+    PixmapPtr pixmap;
+    int rc;
+    int i;
+
+    SetReqFds(client, stuff->num_buffers);
+    REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
+    LEGAL_NEW_RESOURCE(stuff->pixmap, client);
+    rc = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
+    if (rc != Success) {
+        client->errorValue = stuff->drawable;
+        return rc;
+    }
+
+    if (!stuff->width || !stuff->height || !stuff->bpp || !stuff->depth) {
+        client->errorValue = 0;
+        return BadValue;
+    }
+
+    if (stuff->width > 32767 || stuff->height > 32767)
+        return BadAlloc;
+
+    if (stuff->depth != 1) {
+        DepthPtr depth = drawable->pScreen->allowedDepths;
+        int j;
+        for (j = 0; j < drawable->pScreen->numDepths; j++, depth++)
+            if (depth->depth == stuff->depth)
+                break;
+        if (j == drawable->pScreen->numDepths) {
+            client->errorValue = stuff->depth;
+            return BadValue;
+        }
+    }
+
+    if (!stuff->num_buffers || stuff->num_buffers > 4) {
+        client->errorValue = stuff->num_buffers;
+        return BadValue;
+    }
+
+    for (i = 0; i < stuff->num_buffers; i++) {
+        fds[i] = ReadFdFromClient(client);
+        if (fds[i] < 0) {
+            while (--i >= 0)
+                close(fds[i]);
+            return BadValue;
+        }
+    }
+
+    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->depth, stuff->bpp,
+                              stuff->modifier);
+
+    for (i = 0; i < stuff->num_buffers; i++)
+        close (fds[i]);
+
+    if (rc != Success)
+        return rc;
+
+    pixmap->drawable.id = stuff->pixmap;
+
+    /* security creation/labeling check */
+    rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
+                  pixmap, RT_NONE, NULL, DixCreateAccess);
+
+    if (rc != Success) {
+        (*drawable->pScreen->DestroyPixmap) (pixmap);
+        return rc;
+    }
+    if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap))
+        return BadAlloc;
+
+    return Success;
+}
+
+static int
+proc_dri3_buffers_from_pixmap(ClientPtr client)
+{
+    REQUEST(xDRI3BuffersFromPixmapReq);
+    xDRI3BuffersFromPixmapReply rep = {
+        .type = X_Reply,
+        .sequenceNumber = client->sequence,
+    };
+    int rc;
+    int fds[4];
+    int num_fds;
+    uint32_t strides[4], offsets[4];
+    uint64_t modifier;
+    int i;
+    PixmapPtr pixmap;
+
+    REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
+    rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP,
+                                 client, DixWriteAccess);
+    if (rc != Success) {
+        client->errorValue = stuff->pixmap;
+        return rc;
+    }
+
+    num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
+    if (num_fds == 0)
+        return BadPixmap;
+
+    rep.nfd = num_fds;
+    rep.length = bytes_to_int32(num_fds * 2 * sizeof(CARD32));
+    rep.width = pixmap->drawable.width;
+    rep.height = pixmap->drawable.height;
+    rep.modifier = modifier;
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swaps(&rep.width);
+        swaps(&rep.height);
+        swapll(&rep.modifier);
+        for (i = 0; i < num_fds; i++) {
+            swapl(&strides[i]);
+            swapl(&offsets[i]);
+        }
+    }
+
+    for (i = 0; i < num_fds; i++) {
+        if (WriteFdToClient(client, fds[i], TRUE) < 0) {
+            while (i--)
+                close(fds[i]);
+            return BadAlloc;
+        }
+    }
+
+    WriteToClient(client, sizeof(rep), &rep);
+    WriteToClient(client, num_fds * sizeof(CARD32), strides);
+    WriteToClient(client, num_fds * sizeof(CARD32), offsets);
+
+    return Success;
+}
+
 int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     proc_dri3_query_version,            /* 0 */
     proc_dri3_open,                     /* 1 */
@@ -306,6 +526,9 @@ int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     proc_dri3_buffer_from_pixmap,       /* 3 */
     proc_dri3_fence_from_fd,            /* 4 */
     proc_dri3_fd_from_fence,            /* 5 */
+    proc_dri3_get_supported_modifiers,  /* 6 */
+    proc_dri3_pixmap_from_buffers,      /* 7 */
+    proc_dri3_buffers_from_pixmap,      /* 8 */
 };
 
 int
@@ -394,6 +617,51 @@ sproc_dri3_fd_from_fence(ClientPtr client)
     return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
 }
 
+static int _X_COLD
+sproc_dri3_get_supported_modifiers(ClientPtr client)
+{
+    REQUEST(xDRI3GetSupportedModifiersReq);
+    REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->window);
+    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_pixmap_from_buffers(ClientPtr client)
+{
+    REQUEST(xDRI3PixmapFromBuffersReq);
+    REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->pixmap);
+    swapl(&stuff->drawable);
+    swaps(&stuff->width);
+    swaps(&stuff->height);
+    swapl(&stuff->stride0);
+    swapl(&stuff->offset0);
+    swapl(&stuff->stride1);
+    swapl(&stuff->offset1);
+    swapl(&stuff->stride2);
+    swapl(&stuff->offset2);
+    swapl(&stuff->stride3);
+    swapl(&stuff->offset3);
+    swapll(&stuff->modifier);
+    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_buffers_from_pixmap(ClientPtr client)
+{
+    REQUEST(xDRI3BuffersFromPixmapReq);
+    REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->pixmap);
+    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
 int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     sproc_dri3_query_version,           /* 0 */
     sproc_dri3_open,                    /* 1 */
@@ -401,6 +669,9 @@ int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     sproc_dri3_buffer_from_pixmap,      /* 3 */
     sproc_dri3_fence_from_fd,           /* 4 */
     sproc_dri3_fd_from_fence,           /* 5 */
+    sproc_dri3_get_supported_modifiers, /* 6 */
+    sproc_dri3_pixmap_from_buffers,     /* 7 */
+    sproc_dri3_buffers_from_pixmap,     /* 8 */
 };
 
 int _X_COLD
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 6c0c60cbf..df40f8281 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -29,6 +29,7 @@
 #include <misync.h>
 #include <misyncshm.h>
 #include <randrstr.h>
+#include <drm_fourcc.h>
 
 static inline Bool has_open(dri3_screen_info_ptr info) {
     if (info == NULL)
@@ -60,17 +61,30 @@ 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,
+                     CARD8 depth, CARD8 bpp, CARD64 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)
         return BadImplementation;
 
-    pixmap = (*info->pixmap_from_fd) (screen, fd, width, height, stride, depth, bpp);
+    if (info->version >= 2 && info->pixmap_from_fds != NULL) {
+        pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height,
+                                           strides, offsets, depth, bpp, modifier);
+    } else if (info->pixmap_from_fd != NULL && num_fds == 1 &&
+               modifier == DRM_FORMAT_MOD_INVALID) {
+        pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height,
+                                          strides[0], depth, bpp);
+    } else {
+        return BadImplementation;
+    }
+
     if (!pixmap)
         return BadAlloc;
 
@@ -79,20 +93,182 @@ dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
 }
 
 int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
+dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+                     CARD32 *strides, CARD32 *offsets,
+                     CARD64 *modifier)
 {
     ScreenPtr                   screen = pixmap->drawable.pScreen;
     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
     dri3_screen_info_ptr        info = ds->info;
-    int                         fd;
 
-    if (!info || !info->fd_from_pixmap)
+    if (!info)
+        return 0;
+
+    if (info->version >= 2 && info->fds_from_pixmap != NULL) {
+        return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets,
+                                        modifier);
+    } else if (info->fd_from_pixmap != NULL) {
+        CARD16 stride;
+        CARD32 size;
+
+        fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size);
+        if (fds[0] < 0)
+            return 0;
+
+        strides[0] = stride;
+        offsets[0] = 0;
+        *modifier = DRM_FORMAT_MOD_INVALID;
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+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;
+    CARD64                     *modifiers = NULL;
+    int                         i;
+
+    if (ds->formats_cached)
+        return Success;
+
+    if (!info)
         return BadImplementation;
 
-    fd = (*info->fd_from_pixmap)(screen, pixmap, stride, size);
-    if (fd < 0)
+    if (!info->get_formats || !info->get_modifiers) {
+        ds->formats = NULL;
+        ds->num_formats = 0;
+        ds->formats_cached = TRUE;
+        return Success;
+    }
+
+    (*info->get_formats) (screen, &ds->num_formats, &formats);
+    ds->formats = calloc(ds->num_formats, sizeof(dri3_dmabuf_format_rec));
+    if (!ds->formats)
         return BadAlloc;
-    *pfd = fd;
+
+    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 = malloc(iter->num_modifiers * sizeof(CARD64));
+        if (iter->modifiers == NULL)
+            goto error;
+
+        memcpy(iter->modifiers, modifiers,
+               iter->num_modifiers * sizeof(CARD64));
+        goto done;
+
+error:
+        iter->num_modifiers = 0;
+        free(iter->modifiers);
+done:
+        free(modifiers);
+    }
+    free(formats);
+    ds->formats_cached = TRUE;
+
     return Success;
 }
 
+int
+dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
+                             CARD8 depth, CARD8 bpp,
+                             CARD32 *num_intersect_modifiers,
+                             CARD64 **intersect_modifiers,
+                             CARD32 *num_screen_modifiers,
+                             CARD64 **screen_modifiers)
+{
+    dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
+    dri3_screen_info_ptr        info = ds->info;
+    int                         i, j;
+    int                         ret;
+    CARD32                      num_drawable_mods;
+    CARD64                     *drawable_mods;
+    CARD64                     *intersect_mods = NULL;
+    CARD64                     *screen_mods = NULL;
+    CARD32                      format;
+    dri3_dmabuf_format_ptr      screen_format = NULL;
+
+    ret = cache_formats_and_modifiers(screen);
+    if (ret != Success)
+        return ret;
+
+    format = drm_format_for_depth(depth, bpp);
+    if (format == 0)
+        return BadValue;
+
+    /* Find screen-global modifiers from cache
+     */
+    for (i = 0; i < ds->num_formats; i++) {
+        if (ds->formats[i].format == format) {
+            screen_format = &ds->formats[i];
+            break;
+        }
+    }
+    if (screen_format == NULL)
+        return BadMatch;
+
+    if (screen_format->num_modifiers == 0) {
+        *num_screen_modifiers = 0;
+        *num_intersect_modifiers = 0;
+        return Success;
+    }
+
+    if (info->get_drawable_modifiers)
+        (*info->get_drawable_modifiers) (drawable, format,
+                                         &num_drawable_mods,
+                                         &drawable_mods);
+
+    /* We're allocating slightly more memory than necessary but it reduces
+     * the complexity of finding the intersection set.
+     */
+    screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
+    if (!screen_mods)
+        return BadAlloc;
+    if (num_drawable_mods > 0) {
+        intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
+        if (!intersect_mods) {
+            free(screen_mods);
+            return BadAlloc;
+        }
+    }
+
+    *num_screen_modifiers = 0;
+    *num_intersect_modifiers = 0;
+    for (i = 0; i < screen_format->num_modifiers; i++) {
+        CARD64 modifier = screen_format->modifiers[i];
+        Bool intersect = FALSE;
+
+        for (j = 0; j < num_drawable_mods; j++) {
+            if (drawable_mods[j] == modifier) {
+                intersect = TRUE;
+                break;
+            }
+        }
+
+        if (intersect) {
+            intersect_mods[*num_intersect_modifiers] = modifier;
+            *num_intersect_modifiers += 1;
+        } else {
+            screen_mods[*num_screen_modifiers] = modifier;
+            *num_screen_modifiers += 1;
+        }
+    }
+
+    assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers);
+
+    *intersect_modifiers = intersect_mods;
+    *screen_modifiers = screen_mods;
+    free(drawable_mods);
+
+    return Success;
+}
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 8ffb40d6f..0933e9411 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -59,7 +59,7 @@ xwl_glamor_egl_make_current(struct glamor_context *glamor_ctx)
 }
 
 static uint32_t
-drm_format_for_depth(int depth)
+wl_drm_format_for_depth(int depth)
 {
     switch (depth) {
     case 15:
@@ -170,7 +170,7 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
         wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
                                    pixmap->drawable.width,
                                    pixmap->drawable.height,
-                                   drm_format_for_depth(pixmap->drawable.depth),
+                                   wl_drm_format_for_depth(pixmap->drawable.depth),
                                    0, gbm_bo_get_stride(xwl_pixmap->bo),
                                    0, 0,
                                    0, 0);
diff --git a/meson.build b/meson.build
index 3c1d54cdf..01eddaac3 100644
--- a/meson.build
+++ b/meson.build
@@ -78,7 +78,7 @@ scrnsaverproto_dep = dependency('scrnsaverproto', version: '>= 1.1')
 resourceproto_dep = dependency('resourceproto', version: '>= 1.2.0')
 xf86driproto_dep = dependency('xf86driproto', version: '>= 2.1.0', required: get_option('dri1') == 'true')
 dri2proto_dep = dependency('dri2proto', version: '>= 2.8', required: get_option('dri2') == 'true')
-dri3proto_dep = dependency('dri3proto', version: '>= 1.0', required: get_option('dri3') == 'true')
+dri3proto_dep = dependency('dri3proto', version: '>= 1.1', required: get_option('dri3') == 'true')
 xineramaproto_dep = dependency('xineramaproto')
 xf86bigfontproto_dep = dependency('xf86bigfontproto', version: '>= 1.2.0')
 xf86dgaproto_dep = dependency('xf86dgaproto', version: '>= 2.0.99.1', required: false)
-- 
2.14.3



More information about the xorg-devel mailing list