When importing client buffers into Pixmaps, we can use the fds_to_pixmap
hook for both single-FD and multi-FD client requests without any harm.

For the other direction of exporting Pixmap buffers to client FDs,
create a new helper which calls the old pixmap_to_fd hook if available.
This allows the implementation to ensure that the Pixmap storage is
accessible to clients not aware of multiple planes or modifiers, e.g. by
reallocating and copying.

This makes it possible to run a compositing manager on an old GLX/EGL
stack on top of an X server which allocates internal buffer storage
using exotic modifiers from modifier-aware GBM/EGL/KMS.

Signed-off-by: Daniel Stone <dani...@collabora.com>
Reported-by: Adam Jackson <a...@redhat.com>
---
 dri3/dri3_priv.h    |  3 +++
 dri3/dri3_request.c | 16 +++++-----------
 dri3/dri3_screen.c  | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index 8447680ba..d86f06be0 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -83,6 +83,9 @@ dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, 
CARD8 num_fds, int *f
                      CARD16 width, CARD16 height, CARD32 *strides, CARD32 
*offsets,
                      CARD8 depth, CARD8 bpp, CARD64 modifier);
 
+int
+dri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
+
 int
 dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
                      CARD32 *strides, CARD32 *offsets,
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index fc258711b..2d3deb282 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -212,10 +212,7 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
         .length = 0,
     };
     int rc;
-    int num_fds;
-    int fds[4];
-    uint32_t strides[4], offsets[4];
-    uint64_t modifier;
+    int fd;
     PixmapPtr pixmap;
 
     REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
@@ -231,13 +228,10 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
     rep.depth = pixmap->drawable.depth;
     rep.bpp = pixmap->drawable.bitsPerPixel;
 
-    num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
-    if (num_fds != 1)
+    fd = dri3_fd_from_pixmap(pixmap, &rep.stride, &rep.size);
+    if (fd == -1)
         return BadPixmap;
 
-    rep.stride = (CARD16) strides[0];
-    rep.size = rep.stride * rep.height;
-
     if (client->swapped) {
         swaps(&rep.sequenceNumber);
         swapl(&rep.length);
@@ -246,8 +240,8 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
         swaps(&rep.height);
         swaps(&rep.stride);
     }
-    if (WriteFdToClient(client, fds[0], TRUE) < 0) {
-        close(fds[0]);
+    if (WriteFdToClient(client, fd, TRUE) < 0) {
+        close(fd);
         return BadAlloc;
     }
 
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index df40f8281..41595f412 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -30,6 +30,7 @@
 #include <misyncshm.h>
 #include <randrstr.h>
 #include <drm_fourcc.h>
+#include <unistd.h>
 
 static inline Bool has_open(dri3_screen_info_ptr info) {
     if (info == NULL)
@@ -124,6 +125,45 @@ dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
     }
 }
 
+int
+dri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
+{
+    ScreenPtr                   screen = pixmap->drawable.pScreen;
+    dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
+    dri3_screen_info_ptr        info = ds->info;
+    CARD32                      strides[4];
+    CARD32                      offsets[4];
+    CARD64                      modifier;
+    int                         fds[4];
+    int                         num_fds;
+
+    if (!info)
+        return -1;
+
+    /* Preferentially use the old interface, allowing the implementation to
+     * ensure the buffer is in a single-plane format which doesn't need
+     * modifiers. */
+    if (info->fd_from_pixmap != NULL)
+        return (*info->fd_from_pixmap)(screen, pixmap, stride, size);
+
+    if (info->version < 2 || info->fds_from_pixmap == NULL)
+        return -1;
+
+    /* If using the new interface, make sure that it's a single plane starting
+     * at 0 within the BO. We don't check the modifier, as the client may
+     * have an auxiliary mechanism for determining the modifier itself. */
+    num_fds = info->fds_from_pixmap(screen, pixmap, fds, strides, offsets,
+                                    &modifier);
+    if (num_fds != 1 || offsets[0] != 0) {
+        int i;
+        for (i = 0; i < num_fds; i++)
+            close(fds[i]);
+        return -1;
+    }
+
+    return fds[0];
+}
+
 static int
 cache_formats_and_modifiers(ScreenPtr screen)
 {
-- 
2.17.0

_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to