From a02815253ab69811a1d75cb8b7f9cc8c446a8f85 Mon Sep 17 00:00:00 2001
From: Julian Orth <ju.orth@gmail.com>
Date: Mon, 19 Feb 2024 18:35:45 +0100
Subject: [PATCH] x: use modifier-aware buffer import

---
 src/backends/x.rs  | 45 +++++++++++++++++++++++----------------------
 wire-xcon/dri3.txt | 22 ++++++++++++++++++++++
 2 files changed, 45 insertions(+), 22 deletions(-)

diff --git a/src/backends/x.rs b/src/backends/x.rs
index e44d4d6d..dfea819d 100644
--- a/src/backends/x.rs
+++ b/src/backends/x.rs
@@ -19,12 +19,11 @@ use {
         },
         video::{
             drm::{ConnectorType, Drm, DrmError, DrmVersion},
-            gbm::{GbmDevice, GbmError, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING},
-            INVALID_MODIFIER, LINEAR_MODIFIER,
+            gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING},
         },
         wire_xcon::{
             ChangeProperty, ChangeWindowAttributes, ConfigureNotify, CreateCursor, CreatePixmap,
-            CreateWindow, CreateWindowValues, DestroyNotify, Dri3Open, Dri3PixmapFromBuffer,
+            CreateWindow, CreateWindowValues, DestroyNotify, Dri3Open, Dri3PixmapFromBuffers,
             Dri3QueryVersion, Extension, FreePixmap, MapWindow, PresentCompleteNotify,
             PresentIdleNotify, PresentPixmap, PresentQueryVersion, PresentSelectInput,
             XiButtonPress, XiButtonRelease, XiDeviceInfo, XiEnter, XiEventMask,
@@ -383,28 +382,16 @@ impl XBackend {
             Some(f) => f,
             None => return Err(XBackendError::XRGB8888),
         };
-        let mut usage = GBM_BO_USE_RENDERING;
-        let modifier = if format.write_modifiers.contains(&LINEAR_MODIFIER) {
-            &[LINEAR_MODIFIER]
-        } else if format.write_modifiers.contains(&INVALID_MODIFIER) {
-            usage |= GBM_BO_USE_LINEAR;
-            &[INVALID_MODIFIER]
-        } else {
-            panic!("Neither linear nor invalid modifier is supported");
-        };
         for image in &mut images {
             let bo = self.gbm.create_bo(
                 &self.state.dma_buf_ids,
                 width,
                 height,
                 XRGB8888,
-                modifier,
-                usage,
+                &format.write_modifiers,
+                GBM_BO_USE_RENDERING,
             )?;
             let dma = bo.dmabuf();
-            assert!(dma.planes.len() == 1);
-            let plane = dma.planes.first().unwrap();
-            let size = plane.stride * dma.height as u32;
             let img = match self.ctx.clone().dmabuf_img(dma) {
                 Ok(f) => f,
                 Err(e) => return Err(XBackendError::CreateImage(e)),
@@ -417,17 +404,31 @@ impl XBackend {
                 Ok(f) => f,
                 Err(e) => return Err(XBackendError::CreateTexture(e)),
             };
+            macro_rules! pp {
+                ($num:expr, $field:ident) => {
+                    dma.planes.get($num).map(|p| p.$field).unwrap_or(0) as _
+                };
+            }
+            let buffers: Vec<_> = dma.planes.iter().map(|p| p.fd.clone()).collect();
             let pixmap = {
-                let pfb = Dri3PixmapFromBuffer {
+                let pfb = Dri3PixmapFromBuffers {
                     pixmap: self.c.generate_id()?,
-                    drawable: window,
-                    size,
+                    window,
+                    num_buffers: dma.planes.len() as _,
                     width: dma.width as _,
                     height: dma.height as _,
-                    stride: plane.stride as _,
+                    stride0: pp!(0, stride),
+                    offset0: pp!(0, offset),
+                    stride1: pp!(1, stride),
+                    offset1: pp!(1, offset),
+                    stride2: pp!(2, stride),
+                    offset2: pp!(2, offset),
+                    stride3: pp!(3, stride),
+                    offset3: pp!(3, offset),
                     depth: 24,
                     bpp: 32,
-                    pixmap_fd: plane.fd.clone(),
+                    modifier: dma.modifier,
+                    buffers: buffers.into(),
                 };
                 if let Err(e) = self.c.call(&pfb).await {
                     return Err(XBackendError::ImportBuffer(e));
diff --git a/wire-xcon/dri3.txt b/wire-xcon/dri3.txt
index 5ebb1abc..c5d71771 100644
--- a/wire-xcon/dri3.txt
+++ b/wire-xcon/dri3.txt
@@ -29,3 +29,25 @@ request Dri3PixmapFromBuffer = 2 (
     bpp: u8,
     pixmap_fd: fd,
 );
+
+request Dri3PixmapFromBuffers = 7 (
+    pixmap: u32,
+    window: u32,
+    num_buffers: u8,
+    @pad 3,
+    width: u16,
+    height: u16,
+    stride0: u32,
+    offset0: u32,
+    stride1: u32,
+    offset1: u32,
+    stride2: u32,
+    offset2: u32,
+    stride3: u32,
+    offset3: u32,
+    depth: u8,
+    bpp: u8,
+    @pad 2,
+    modifier: u64,
+    buffers: list(fd, field(num_buffers)),
+);