[RFC v2 02/13] dri3: Add multi-planar/modifier buffer requests

Louis-Francis Ratté-Boulianne lfrb at collabora.com
Fri Jul 14 04:47:49 UTC 2017


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.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
---
 dri3/dri3.h         |  35 +++-
 dri3/dri3_priv.h    |  27 +++-
 dri3/dri3_request.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 dri3/dri3_screen.c  | 173 ++++++++++++++++++--
 4 files changed, 658 insertions(+), 25 deletions(-)

diff --git a/dri3/dri3.h b/dri3/dri3.h
index 7562352ff..67589c70c 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,38 @@ 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,
+                                                CARD32 format,
+                                                uint64_t modifiers);
+
 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,
+                                          uint32_t *strides,
+                                          uint32_t *offsets,
+                                          uint32_t *format,
+                                          uint64_t *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,
+                                        uint64_t **modifiers);
+
 typedef struct dri3_screen_info {
     uint32_t                    version;
 
@@ -62,6 +89,12 @@ 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_screen_info_rec, *dri3_screen_info_ptr;
 
 extern _X_EXPORT Bool
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index e61ef226c..730fcfb43 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;
 
@@ -69,10 +80,20 @@ 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_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+                     uint32_t *strides, uint32_t *offsets,
+                     uint32_t *format, uint64_t *modifier);
+
+int
+dri3_get_supported_formats(ScreenPtr screen, CARD32 *num_formats, CARD32 **formats);
 
 int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
+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 b28d883a5..50522ebb7 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -124,6 +124,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 +160,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;
@@ -195,7 +198,11 @@ 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];
+    uint32_t format;
+    uint64_t modifier;
     PixmapPtr pixmap;
 
     REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
@@ -211,9 +218,15 @@ 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,
+                                   &format, &modifier);
+    if (num_fds == 0)
+        return BadPixmap;
+
+    // XXX Should we fail if num_fds > 1
+
+    rep.stride = (CARD16) strides[0];
+    rep.size = rep.stride * rep.height;
 
     if (client->swapped) {
         swaps(&rep.sequenceNumber);
@@ -223,8 +236,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 +312,324 @@ proc_dri3_fd_from_fence(ClientPtr client)
     return Success;
 }
 
+static int
+proc_dri3_get_supported_formats(ClientPtr client)
+{
+    REQUEST(xDRI3GetSupportedFormatsReq);
+    xDRI3GetSupportedFormatsReply rep = {
+        .type = X_Reply,
+        .sequenceNumber = client->sequence,
+    };
+    DrawablePtr drawable;
+    ScreenPtr pScreen;
+    CARD32 *formats = NULL;
+    CARD32 nformats = 0;
+    CARD32 i;
+    int status;
+
+    REQUEST_SIZE_MATCH(xDRI3GetSupportedFormatsReq);
+
+    status = dixLookupDrawable(&drawable, stuff->window, client, 0,
+                               DixReadAccess);
+    if (status != Success)
+        return status;
+    pScreen = drawable->pScreen;
+
+    dri3_get_supported_formats(pScreen, &nformats, &formats);
+
+    rep.numFormats = nformats;
+    rep.length = bytes_to_int32(rep.numFormats * sizeof(CARD32));
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swapl(&rep.numFormats);
+        for (i = 0; i < nformats; i++)
+            swapl(&formats[i]);
+    }
+
+    WriteToClient(client, sizeof(rep), &rep);
+    WriteToClient(client, nformats * sizeof(CARD32), formats);
+
+    free(formats);
+
+    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;
+    CARD32 *modifiers_hi = NULL;
+    CARD32 *modifiers_lo = NULL;
+    CARD32 nmodifiers = 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, stuff->format, &nmodifiers,
+                                 &modifiers_hi, &modifiers_lo);
+
+    rep.numModifiers = nmodifiers;
+    rep.length = bytes_to_int32(2 * rep.numModifiers * sizeof(CARD32));
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swapl(&rep.numModifiers);
+        for (i = 0; i < nmodifiers; i++) {
+            swapl(&modifiers_hi[i]);
+            swapl(&modifiers_lo[i]);
+        }
+    }
+
+    WriteToClient(client, sizeof(rep), &rep);
+
+    for (i = 0; i < nmodifiers; i++) {
+	/* XXX: Could this be better ... ? */
+        WriteToClient(client, sizeof(CARD32), &modifiers_hi[i]);
+        WriteToClient(client, sizeof(CARD32), &modifiers_lo[i]);
+    }
+
+    free(modifiers_hi);
+    free(modifiers_lo);
+
+    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;
+    uint64_t modifier;
+    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->format) {
+        client->errorValue = 0;
+        return BadValue;
+    }
+
+    if (stuff->width > 32767 || stuff->height > 32767)
+        return BadAlloc;
+
+    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)
+            return BadValue;
+    }
+
+    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;
+
+    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);
+        goto error;
+    }
+    if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap)) {
+        rc = BadAlloc;
+        goto error;
+    }
+
+    return Success;
+
+error:
+    for (i = 0; i < stuff->num_buffers; i++)
+        close (fds[i]);
+    return rc;
+}
+
+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];
+    uint32_t format;
+    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,
+                                   &format, &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.format = format;
+    rep.modifier_hi = modifier >> 32;
+    rep.modifier_lo = modifier & 0xffffffff;
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swaps(&rep.width);
+        swaps(&rep.height);
+        swapl(&rep.format);
+        swapl(&rep.modifier_hi);
+        swapl(&rep.modifier_lo);
+        for (i = 0; i < num_fds; i++) {
+            swapl(&strides[i]);
+            swapl(&offsets[i]);
+        }
+    }
+
+    for (i = 0; i < num_fds; i++) {
+        fds[i] = dup(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;
+}
+
+static int
+proc_dri3_fence_from_dma_fence_fd(ClientPtr client)
+{
+    REQUEST(xDRI3FenceFromFDReq);
+    DrawablePtr drawable;
+    int fd;
+    int status;
+
+    SetReqFds(client, 1);
+    REQUEST_SIZE_MATCH(xDRI3FenceFromDMAFenceFDReq);
+    LEGAL_NEW_RESOURCE(stuff->fence, client);
+
+    status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
+    if (status != Success)
+        return status;
+
+    fd = ReadFdFromClient(client);
+    if (fd < 0)
+        return BadValue;
+
+    /* XXX: DTRT :) */
+    status = SyncCreateFenceFromFD(client, drawable, stuff->fence,
+                                   fd, stuff->initially_triggered);
+
+    return status;
+}
+
+static int
+proc_dri3_dma_fence_fd_from_fence(ClientPtr client)
+{
+    REQUEST(xDRI3DMAFenceFDFromFenceReq);
+    xDRI3DMAFenceFDFromFenceReply rep = {
+        .type = X_Reply,
+        .nfd = 1,
+        .sequenceNumber = client->sequence,
+        .length = 0,
+    };
+    DrawablePtr drawable;
+    int fd;
+    int status;
+    SyncFence *fence;
+
+    REQUEST_SIZE_MATCH(xDRI3DMAFenceFDFromFenceReq);
+
+    status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
+    if (status != Success)
+        return status;
+    status = SyncVerifyFence(&fence, stuff->fence, client, DixWriteAccess);
+    if (status != Success)
+        return status;
+
+    /* XXX: DTRT :) */
+    fd = SyncFDFromFence(client, drawable, fence);
+    if (fd < 0)
+        return BadMatch;
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+    }
+    if (WriteFdToClient(client, fd, FALSE) < 0)
+        return BadAlloc;
+
+    WriteToClient(client, sizeof(rep), &rep);
+
+    return Success;
+}
+
 int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     proc_dri3_query_version,            /* 0 */
     proc_dri3_open,                     /* 1 */
@@ -306,6 +637,12 @@ 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_formats,    /* 6 */
+    proc_dri3_get_supported_modifiers,  /* 7 */
+    proc_dri3_pixmap_from_buffers,      /* 8 */
+    proc_dri3_buffers_from_pixmap,      /* 9 */
+    proc_dri3_fence_from_dma_fence_fd,  /* 10 */
+    proc_dri3_dma_fence_fd_from_fence,  /* 11 */
 };
 
 int
@@ -394,6 +731,89 @@ sproc_dri3_fd_from_fence(ClientPtr client)
     return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
 }
 
+static int _X_COLD
+sproc_dri3_get_supported_formats(ClientPtr client)
+{
+    REQUEST(xDRI3GetSupportedFormatsReq);
+    REQUEST_SIZE_MATCH(xDRI3GetSupportedFormatsReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->window);
+    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);
+    swapl(&stuff->format);
+    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);
+    swapl(&stuff->format);
+    swapl(&stuff->modifier_hi);
+    swapl(&stuff->modifier_lo);
+    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);
+}
+
+static int _X_COLD
+sproc_dri3_dma_fence_fd_from_fence(ClientPtr client)
+{
+    REQUEST(xDRI3DMAFenceFDFromFenceReq);
+    REQUEST_SIZE_MATCH(xDRI3DMAFenceFDFromFenceReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->drawable);
+    swapl(&stuff->fence);
+    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_fence_from_dma_fence_fd(ClientPtr client)
+{
+    REQUEST(xDRI3FenceFromDMAFenceFDReq);
+    REQUEST_SIZE_MATCH(xDRI3FenceFromDMAFenceFDReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->drawable);
+    swapl(&stuff->fence);
+    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
 int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     sproc_dri3_query_version,           /* 0 */
     sproc_dri3_open,                    /* 1 */
@@ -401,6 +821,12 @@ 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_formats,   /* 6 */
+    sproc_dri3_get_supported_modifiers, /* 7 */
+    sproc_dri3_pixmap_from_buffers,     /* 8 */
+    sproc_dri3_buffers_from_pixmap,     /* 9 */
+    sproc_dri3_fence_from_dma_fence_fd, /* 10 */
+    sproc_dri3_dma_fence_fd_from_fence, /* 11 */
 };
 
 int _X_COLD
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 6c0c60cbf..59748cad1 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -60,17 +60,32 @@ 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)
         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, format, modifier);
+    } else if (info->pixmap_from_fd != NULL && num_fds == 1 && modifier == 0) {
+        const struct drm_format_info *f;
+
+        f = drm_format_get_info(format);
+        pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height,
+                                          strides[0], f->depth, f->bpp);
+    } else {
+        return BadImplementation;
+    }
+
     if (!pixmap)
         return BadAlloc;
 
@@ -79,20 +94,158 @@ 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,
+                     uint32_t *strides, uint32_t *offsets,
+                     uint32_t *format, uint64_t *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,
+                                        format, modifier);
+    } else if (info->fd_from_pixmap != NULL) {
+        CARD16 stride;
+        CARD32 size;
+        int fd;
+
+        fd = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size);
+        if (fd < 0)
+            return 0;
+
+        fds[0] = fd;
+        strides[0] = stride;
+        offsets[0] = 0;
+        *format = drm_format_for_depth(pixmap->drawable.bitsPerPixel,
+                                       pixmap->drawable.depth);
+        *modifier = 0;
+        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;
+    uint64_t                   *modifiers = NULL;
+    int                         i, j;
+
+    if (ds->formats_cached)
+        return Success;
+
+    if (!info || !info->get_formats || !info->get_modifiers)
         return BadImplementation;
 
-    fd = (*info->fd_from_pixmap)(screen, pixmap, stride, size);
-    if (fd < 0)
+    (*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_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;
+    CARD32                     *array;
+
+    ret = cache_formats_and_modifiers(screen);
+    if (ret != Success)
+        return ret;
+
+    array = malloc(ds->num_formats * sizeof(CARD32));
+    if (!array)
+        return BadAlloc;
+
+    *num_formats = ds->num_formats;
+    *formats = array;
+    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;
+    CARD32                     *hi, *lo;
+
+    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) {
+            hi = malloc(ds->formats[i].num_modifiers * sizeof(CARD32));
+            if (!hi)
+                return BadAlloc;
+            lo = malloc(ds->formats[i].num_modifiers * sizeof(CARD32));
+            if (!lo) {
+                free(hi);
+                return BadAlloc;
+            }
+
+            *num_modifiers = ds->formats[i].num_modifiers;
+            memcpy(hi, ds->formats[i].modifiers_hi,
+                   ds->formats[i].num_modifiers * sizeof(CARD32));
+            memcpy(lo, ds->formats[i].modifiers_lo,
+                   ds->formats[i].num_modifiers * sizeof(CARD32));
+            *modifiers_hi = hi;
+            *modifiers_lo = lo;
+
+            return Success;
+        }
+    }
+
+    return BadMatch;
+}
-- 
2.13.0



More information about the xorg-devel mailing list