[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#892204: kwin-common: add support for zwp_linux_dmabuf



Package: kwin-common
Version: 4:5.12.1-1
Severity: important

Dear Maintainer,

zwp_linux_dmabuf protocol support is needed to properly work with the drm
backend to display Plasma Mobile on the Librem 5 development board.

This support is being tracked by KDE in https://phabricator.kde.org/D10750

Also see relating email thread for complete details:
https://www.mail-archive.com/plasma-devel@kde.org/msg81108.html

The proposed patches attached to D10750 (and this bug report) do indeed
fix the display issue.

Please consider carrying the kwin patch ahead of the Plasma 5.13 release
(scheduled for June 2018).

-- System Information:
Debian Release: buster/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: armhf (armv7l)

Kernel: Linux 4.15.0-g837bff1 (SMP w/4 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=locale: Cannot
set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
ANSI_X3.4-1968), LANGUAGE=en_US.UTF-8 (charmap=locale: Cannot set
LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
ANSI_X3.4-1968)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages kwin-common depends on:
ii  kio                                      5.42.0-3
ii  kpackagetool5                            5.42.0-2
ii  kwin-data                                4:5.12.1-1
ii  libc6                                    2.26-6
ii  libepoxy0                                1.4.3-1
ii  libgcc1                                  1:8-20180218-1
ii  libice6                                  2:1.0.9-2
ii  libinput10                               1.10.0-1
ii  libkdecorations2-5v5                     4:5.12.1-1
ii  libkdecorations2private5v5               4:5.12.1-1
ii  libkf5activities5                        5.42.0-2
ii  libkf5auth5                              5.42.0-2
ii  libkf5completion5                        5.42.0-4
ii  libkf5configcore5                        5.42.0-2
ii  libkf5configgui5                         5.42.0-2
ii  libkf5configwidgets5                     5.42.0-2
ii  libkf5coreaddons5                        5.42.0-2
ii  libkf5declarative5                       5.42.0-2
ii  libkf5globalaccel5                       5.42.0-2
ii  libkf5globalaccelprivate5                5.42.0-2
ii  libkf5i18n5                              5.42.0-3
ii  libkf5kcmutils5                          5.42.0-2
ii  libkf5kiowidgets5                        5.42.0-3
ii  libkf5newstuff5                          5.42.0-2
ii  libkf5notifications5                     5.42.0-2
ii  libkf5package5                           5.42.0-2
ii  libkf5plasma5                            5.42.0-3
ii  libkf5service-bin                        5.42.0-2
ii  libkf5service5                           5.42.0-2
ii  libkf5textwidgets5                       5.42.0-2
ii  libkf5waylandclient5                     4:5.42.0-2
ii  libkf5waylandserver5                     4:5.42.0-2
ii  libkf5widgetsaddons5                     5.42.1-2
ii  libkf5windowsystem5                      5.42.0-2
ii  libkf5xmlgui5                            5.42.0-2
ii  libkscreenlocker5                        5.12.2-1
ii  libkwin4-effect-builtins1                4:5.12.1-1
ii  libkwineffects11                         4:5.12.1-1
ii  libkwinglutils11                         4:5.12.1-1
ii  libkwinxrenderutils11                    4:5.12.1-1
ii  libqt5core5a                             5.9.2+dfsg-12
ii  libqt5dbus5                              5.9.2+dfsg-12
ii  libqt5gui5                               5.9.2+dfsg-12
ii  libqt5qml5                               5.9.2-3
ii  libqt5quick5                             5.9.2-3
ii  libqt5script5                            5.9.2+dfsg-2
ii  libqt5sensors5                           5.9.2-2
ii  libqt5widgets5                           5.9.2+dfsg-12
ii  libqt5x11extras5                         5.9.2-1
ii  libsm6                                   2:1.2.2-1+b3
ii  libstdc++6                               8-20180218-1
ii  libudev1                                 237-3
ii  libwayland-cursor0                       1.14.0-1+b1
ii  libx11-6                                 2:1.6.4-3
ii  libxcb-composite0                        1.12-1
ii  libxcb-cursor0                           0.1.1-4
ii  libxcb-damage0                           1.12-1
ii  libxcb-glx0                              1.12-1
ii  libxcb-icccm4                            0.4.1-1+b1
ii  libxcb-keysyms1                          0.4.0-1+b2
ii  libxcb-randr0                            1.12-1
ii  libxcb-render0                           1.12-1
ii  libxcb-shape0                            1.12-1
ii  libxcb-shm0                              1.12-1
ii  libxcb-sync1                             1.12-1
ii  libxcb-xfixes0                           1.12-1
ii  libxcb1                                  1.12-1
ii  libxkbcommon0                            0.8.0-1
ii  qml-module-org-kde-kquickcontrolsaddons  5.42.0-2
ii  qml-module-qtmultimedia                  5.9.2-1

Versions of packages kwin-common recommends:
pn  libqt5multimedia5-plugins  <none>
pn  plasma-desktop             <none>

Versions of packages kwin-common suggests:
pn  kwin-addons  <none>
diff --git a/platformsupport/scenes/opengl/abstract_egl_backend.h b/platformsupport/scenes/opengl/abstract_egl_backend.h
--- a/platformsupport/scenes/opengl/abstract_egl_backend.h
+++ b/platformsupport/scenes/opengl/abstract_egl_backend.h
@@ -23,6 +23,7 @@
 #include "texture.h"
 
 #include <QObject>
+#include <QLinkedList>
 #include <epoxy/egl.h>
 #include <fixx11h.h>
 
@@ -39,6 +40,8 @@
 namespace KWin
 {
 
+class EglDmabufBuffer;
+
 class KWIN_EXPORT AbstractEglBackend : public QObject, public OpenGLBackend
 {
     Q_OBJECT
@@ -60,6 +63,15 @@
         return m_config;
     }
 
+    void aboutToDestroy(EglDmabufBuffer *buffer);
+
+    QVector<uint32_t> supportedDrmFormats() override;
+    QVector<uint64_t> supportedDrmModifiers(uint32_t format) override;
+    KWayland::Server::LinuxDmabuf::Buffer *importDmabufBuffer(const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                                              uint32_t format,
+                                                              const QSize &size,
+                                                              KWayland::Server::LinuxDmabuf::Flags flags) override;
+
 protected:
     AbstractEglBackend();
     void setEglDisplay(const EGLDisplay &display);
@@ -85,6 +97,8 @@
     EGLContext m_context = EGL_NO_CONTEXT;
     EGLConfig m_config = nullptr;
     QList<QByteArray> m_clientExtensions;
+    QLinkedList<EglDmabufBuffer *> m_dmabufBuffers;
+    bool m_haveDmabufImport = false;
 };
 
 class KWIN_EXPORT AbstractEglTexture : public SceneOpenGLTexturePrivate
@@ -110,6 +124,7 @@
 private:
     bool loadShmTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
     bool loadEglTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
+    bool loadDmabufTexture(const QPointer< KWayland::Server::BufferInterface > &buffer);
     EGLImageKHR attach(const QPointer<KWayland::Server::BufferInterface> &buffer);
     bool updateFromFBO(const QSharedPointer<QOpenGLFramebufferObject> &fbo);
     SceneOpenGLTexture *q;
@@ -117,6 +132,30 @@
     EGLImageKHR m_image;
 };
 
+class KWIN_EXPORT EglDmabufBuffer : public KWayland::Server::LinuxDmabuf::Buffer
+{
+public:
+    EglDmabufBuffer(EGLImage image,
+                    const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                    uint32_t format,
+                    const QSize &size,
+                    KWayland::Server::LinuxDmabuf::Flags flags,
+                    AbstractEglBackend *backend);
+    ~EglDmabufBuffer() override;
+
+    EGLImage image() const { return m_image; }
+    KWayland::Server::LinuxDmabuf::Flags flags() const { return m_flags; }
+    const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes() const { return m_planes; }
+
+    void destroyImage();
+
+private:
+    AbstractEglBackend *m_backend;
+    EGLImage m_image;
+    QVector<KWayland::Server::LinuxDmabuf::Plane> m_planes;
+    KWayland::Server::LinuxDmabuf::Flags m_flags;
+};
+
 }
 
 #endif
diff --git a/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/platformsupport/scenes/opengl/abstract_egl_backend.cpp
--- a/platformsupport/scenes/opengl/abstract_egl_backend.cpp
+++ b/platformsupport/scenes/opengl/abstract_egl_backend.cpp
@@ -36,6 +36,8 @@
 #include <QOpenGLContext>
 #include <QOpenGLFramebufferObject>
 
+#include <unistd.h>
+
 #include <memory>
 
 namespace KWin
@@ -48,6 +50,11 @@
 eglUnbindWaylandDisplayWL_func eglUnbindWaylandDisplayWL = nullptr;
 eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL = nullptr;
 
+typedef EGLBoolean (*eglQueryDmaBufFormatsEXT_func) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+typedef EGLBoolean (*eglQueryDmaBufModifiersEXT_func) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+eglQueryDmaBufFormatsEXT_func eglQueryDmaBufFormatsEXT = nullptr;
+eglQueryDmaBufModifiersEXT_func eglQueryDmaBufModifiersEXT = nullptr;
+
 #ifndef EGL_WAYLAND_BUFFER_WL
 #define EGL_WAYLAND_BUFFER_WL                   0x31D5
 #endif
@@ -58,6 +65,45 @@
 #define EGL_WAYLAND_Y_INVERTED_WL               0x31DB
 #endif
 
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_LINUX_DMA_BUF_EXT                     0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT                  0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT                 0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT             0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT              0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT                 0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT             0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT              0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT                 0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT             0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT              0x327A
+#define EGL_YUV_COLOR_SPACE_HINT_EXT              0x327B
+#define EGL_SAMPLE_RANGE_HINT_EXT                 0x327C
+#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
+#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT   0x327E
+#define EGL_ITU_REC601_EXT                        0x327F
+#define EGL_ITU_REC709_EXT                        0x3280
+#define EGL_ITU_REC2020_EXT                       0x3281
+#define EGL_YUV_FULL_RANGE_EXT                    0x3282
+#define EGL_YUV_NARROW_RANGE_EXT                  0x3283
+#define EGL_YUV_CHROMA_SITING_0_EXT               0x3284
+#define EGL_YUV_CHROMA_SITING_0_5_EXT             0x3285
+#endif // EGL_EXT_image_dma_buf_import
+
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+#define EGL_DMA_BUF_PLANE3_FD_EXT                 0x3440
+#define EGL_DMA_BUF_PLANE3_OFFSET_EXT             0x3441
+#define EGL_DMA_BUF_PLANE3_PITCH_EXT              0x3442
+#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT        0x3443
+#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT        0x3444
+#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT        0x3445
+#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT        0x3446
+#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT        0x3447
+#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT        0x3448
+#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT        0x3449
+#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT        0x344A
+#endif // EGL_EXT_image_dma_buf_import_modifiers
+
 AbstractEglBackend::AbstractEglBackend()
     : QObject(nullptr)
     , OpenGLBackend()
@@ -65,7 +111,12 @@
     connect(Compositor::self(), &Compositor::aboutToDestroy, this, &AbstractEglBackend::unbindWaylandDisplay);
 }
 
-AbstractEglBackend::~AbstractEglBackend() = default;
+AbstractEglBackend::~AbstractEglBackend()
+{
+    for (auto *dmabuf : qAsConst(m_dmabufBuffers)) {
+        dmabuf->destroyImage();
+    }
+}
 
 void AbstractEglBackend::unbindWaylandDisplay()
 {
@@ -169,6 +220,13 @@
             }
         }
     }
+
+    if (hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import_modifiers"))) {
+        eglQueryDmaBufFormatsEXT = (eglQueryDmaBufFormatsEXT_func) eglGetProcAddress("eglQueryDmaBufFormatsEXT");
+        eglQueryDmaBufModifiersEXT = (eglQueryDmaBufModifiersEXT_func) eglGetProcAddress("eglQueryDmaBufModifiersEXT");
+    }
+
+    m_haveDmabufImport = hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import"));
 }
 
 void AbstractEglBackend::initClientExtensions()
@@ -285,6 +343,91 @@
     kwinApp()->platform()->setSceneEglSurface(surface);
 }
 
+void AbstractEglBackend::aboutToDestroy(EglDmabufBuffer *buffer)
+{
+    m_dmabufBuffers.removeOne(buffer);
+}
+
+QVector<uint32_t> AbstractEglBackend::supportedDrmFormats()
+{
+    if (!m_haveDmabufImport || eglQueryDmaBufFormatsEXT == nullptr)
+        return QVector<uint32_t>();
+
+    EGLint count = 0;
+    EGLBoolean success = eglQueryDmaBufFormatsEXT(m_display, 0, NULL, &count);
+
+    if (success && count > 0) {
+        QVector<uint32_t> formats(count);
+        if (eglQueryDmaBufFormatsEXT(m_display, count, (EGLint *) formats.data(), &count)) {
+            return formats;
+        }
+    }
+
+    return QVector<uint32_t>();
+}
+
+QVector<uint64_t> AbstractEglBackend::supportedDrmModifiers(uint32_t format)
+{
+    if (!m_haveDmabufImport || eglQueryDmaBufModifiersEXT == nullptr)
+        return QVector<uint64_t>();
+
+    EGLint count = 0;
+    EGLBoolean success = eglQueryDmaBufModifiersEXT(m_display, format, 0, NULL, NULL, &count);
+
+    if (success && count > 0) {
+        QVector<uint64_t> modifiers(count);
+        if (eglQueryDmaBufModifiersEXT(m_display, format, count, modifiers.data(), NULL, &count)) {
+            return modifiers;
+        }
+    }
+
+    return QVector<uint64_t>();
+}
+
+KWayland::Server::LinuxDmabuf::Buffer *AbstractEglBackend::importDmabufBuffer(const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                                                              uint32_t format,
+                                                                              const QSize &size,
+                                                                              KWayland::Server::LinuxDmabuf::Flags flags)
+{
+    if (!m_haveDmabufImport)
+        return nullptr;
+
+    // FIXME: Add support for multi-planar images
+    if (planes.count() != 1)
+        return nullptr;
+
+    const EGLint attribs[] = {
+        EGL_WIDTH,                          size.width(),
+        EGL_HEIGHT,                         size.height(),
+        EGL_LINUX_DRM_FOURCC_EXT,           EGLint(format),
+        EGL_DMA_BUF_PLANE0_FD_EXT,          planes[0].fd,
+        EGL_DMA_BUF_PLANE0_OFFSET_EXT,      EGLint(planes[0].offset),
+        EGL_DMA_BUF_PLANE0_PITCH_EXT,       EGLint(planes[0].stride),
+        EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGLint(planes[0].modifier & 0xffffffff),
+        EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGLint(planes[0].modifier >> 32),
+        EGL_NONE
+    };
+
+    // Note that the EGLImage does NOT take onwership of the file descriptors
+    EGLImage image = eglCreateImageKHR(m_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, (EGLClientBuffer) nullptr, attribs);
+    if (image == EGL_NO_IMAGE_KHR)
+        return nullptr;
+
+    EglDmabufBuffer *buffer = new EglDmabufBuffer(image, planes, format, size, flags, this);
+
+    // We keep a list of the buffers we have imported so we can clean up the EGL images
+    // from the AbstractEglBackend destructor.
+    m_dmabufBuffers.append(buffer);
+
+    return buffer;
+}
+
+
+
+// --------------------------------------------------------------------
+
+
+
 AbstractEglTexture::AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *backend)
     : SceneOpenGLTexturePrivate()
     , q(texture)
@@ -319,11 +462,13 @@
     if (auto s = pixmap->surface()) {
         s->resetTrackedDamage();
     }
-    if (buffer->shmBuffer()) {
+    if (buffer->linuxDmabufBuffer()) {
+        return loadDmabufTexture(buffer);
+    } else if (buffer->shmBuffer()) {
         return loadShmTexture(buffer);
-    } else {
-        return loadEglTexture(buffer);
     }
+
+    return loadEglTexture(buffer);
 }
 
 void AbstractEglTexture::updateTexture(WindowPixmap *pixmap)
@@ -340,12 +485,34 @@
         return;
     }
     auto s = pixmap->surface();
+    if (EglDmabufBuffer *dmabuf = static_cast<EglDmabufBuffer *>(buffer->linuxDmabufBuffer())) {
+        q->bind();
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) dmabuf->image());
+        q->unbind();
+        if (m_image != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
+        }
+        m_image = EGL_NO_IMAGE_KHR; // The wl_buffer has ownership of the image
+        // The origin in a dmabuf-buffer is at the upper-left corner, so the meaning
+        // of Y-inverted is the inverse of OpenGL.
+        const bool yInverted = !(dmabuf->flags() & KWayland::Server::LinuxDmabuf::YInverted);
+        if (m_size != dmabuf->size() || yInverted != q->isYInverted()) {
+            m_size = dmabuf->size();
+            q->setYInverted(yInverted);
+        }
+        if (s) {
+            s->resetTrackedDamage();
+        }
+        return;
+    }
     if (!buffer->shmBuffer()) {
         q->bind();
         EGLImageKHR image = attach(buffer);
         q->unbind();
         if (image != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
+            if (m_image != EGL_NO_IMAGE_KHR) {
+                eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
+            }
             m_image = image;
         }
         if (s) {
@@ -465,6 +632,30 @@
     return true;
 }
 
+bool AbstractEglTexture::loadDmabufTexture(const QPointer< KWayland::Server::BufferInterface > &buffer)
+{
+    EglDmabufBuffer *dmabuf = static_cast<EglDmabufBuffer *>(buffer->linuxDmabufBuffer());
+    if (!dmabuf || dmabuf->image() == EGL_NO_IMAGE_KHR) {
+        qCritical(KWIN_OPENGL) << "Invalid dmabuf-based wl_buffer";
+        q->discard();
+        return false;
+    }
+
+    assert(m_image == EGL_NO_IMAGE_KHR);
+
+    glGenTextures(1, &m_texture);
+    q->setWrapMode(GL_CLAMP_TO_EDGE);
+    q->setFilter(GL_NEAREST);
+    q->bind();
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) dmabuf->image());
+    q->unbind();
+
+    m_size = dmabuf->size();
+    q->setYInverted(!(dmabuf->flags() & KWayland::Server::LinuxDmabuf::YInverted));
+
+    return true;
+}
+
 EGLImageKHR AbstractEglTexture::attach(const QPointer< KWayland::Server::BufferInterface > &buffer)
 {
     EGLint format, yInverted;
@@ -507,5 +698,51 @@
     return true;
 }
 
+
+
+// --------------------------------------------------------------------
+
+
+
+EglDmabufBuffer::EglDmabufBuffer(EGLImage image,
+                                 const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                 uint32_t format,
+                                 const QSize &size,
+                                 KWayland::Server::LinuxDmabuf::Flags flags,
+                                 AbstractEglBackend *backend)
+    : KWayland::Server::LinuxDmabuf::Buffer(format, size),
+      m_backend(backend),
+      m_image(image),
+      m_planes(planes),
+      m_flags(flags)
+{
 }
 
+EglDmabufBuffer::~EglDmabufBuffer()
+{
+    if (m_backend) {
+        m_backend->aboutToDestroy(this);
+
+        assert(m_image != EGL_NO_IMAGE_KHR);
+        eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
+    }
+
+    // Close all open file descriptors
+    for (int i = 0; i < m_planes.count(); i++) {
+        if (m_planes[i].fd != -1)
+            ::close(m_planes[i].fd);
+        m_planes[i].fd = -1;
+    }
+}
+
+void EglDmabufBuffer::destroyImage()
+{
+    assert(m_image != EGL_NO_IMAGE_KHR);
+    eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
+    m_image = EGL_NO_IMAGE_KHR;
+    m_backend = nullptr;
+}
+
+
+} // namespace KWin
+
diff --git a/platformsupport/scenes/opengl/backend.h b/platformsupport/scenes/opengl/backend.h
--- a/platformsupport/scenes/opengl/backend.h
+++ b/platformsupport/scenes/opengl/backend.h
@@ -26,6 +26,8 @@
 
 #include <kwin_export.h>
 
+#include <KWayland/Server/linuxdmabuf_v1_interface.h>
+
 namespace KWin
 {
 class OpenGLBackend;
@@ -197,6 +199,30 @@
      */
     void copyPixels(const QRegion &region);
 
+    /**
+     * Returns the list of the DRM format codes supported by the OpenGL backend.
+     *
+     * The default implementation returns an empty vector.
+     */
+    virtual QVector<uint32_t> supportedDrmFormats();
+
+    /**
+     * Returns the list of the DRM modifiers supported with the given format.
+     *
+     * The default implementation returns an empty vector.
+     */
+    virtual QVector<uint64_t> supportedDrmModifiers(uint32_t format);
+
+    /**
+     * Imports a dmabuf-buffer into the OpenGL backend.
+     *
+     * The default implementation returns nullptr.
+     */
+    virtual KWayland::Server::LinuxDmabuf::Buffer *importDmabufBuffer(const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                                                      uint32_t format,
+                                                                      const QSize &size,
+                                                                      KWayland::Server::LinuxDmabuf::Flags flags = 0);
+
 protected:
     /**
      * @brief Backend specific flushing of frame to screen.
diff --git a/platformsupport/scenes/opengl/backend.cpp b/platformsupport/scenes/opengl/backend.cpp
--- a/platformsupport/scenes/opengl/backend.cpp
+++ b/platformsupport/scenes/opengl/backend.cpp
@@ -116,4 +116,30 @@
     }
 }
 
+QVector<uint32_t> OpenGLBackend::supportedDrmFormats()
+{
+    return QVector<uint32_t>();
+}
+
+QVector<uint64_t> OpenGLBackend::supportedDrmModifiers(uint32_t format)
+{
+    Q_UNUSED(format)
+
+    return QVector<uint64_t>();
+}
+
+KWayland::Server::LinuxDmabuf::Buffer *OpenGLBackend::importDmabufBuffer(const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                                                         uint32_t format,
+                                                                         const QSize &size,
+                                                                         KWayland::Server::LinuxDmabuf::Flags flags)
+{
+    Q_UNUSED(planes)
+    Q_UNUSED(format)
+    Q_UNUSED(size)
+    Q_UNUSED(flags)
+
+    return nullptr;
+}
+
+
 }
diff --git a/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/scene_opengl.h
--- a/plugins/scenes/opengl/scene_opengl.h
+++ b/plugins/scenes/opengl/scene_opengl.h
@@ -82,6 +82,13 @@
 
     QVector<QByteArray> openGLPlatformInterfaceExtensions() const override;
 
+    QVector<uint32_t> supportedDrmFormats() override final;
+    QVector<uint64_t> supportedDrmModifiers(uint32_t format) override final;
+    KWayland::Server::LinuxDmabuf::Buffer *importDmabufBuffer(const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                                              uint32_t format,
+                                                              const QSize &size,
+                                                              KWayland::Server::LinuxDmabuf::Flags flags = 0) override final;
+
     static SceneOpenGL *createScene(QObject *parent);
 
 protected:
diff --git a/plugins/scenes/opengl/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp
--- a/plugins/scenes/opengl/scene_opengl.cpp
+++ b/plugins/scenes/opengl/scene_opengl.cpp
@@ -738,6 +738,24 @@
     return m_backend->renderTime();
 }
 
+QVector<uint32_t> SceneOpenGL::supportedDrmFormats()
+{
+    return m_backend->supportedDrmFormats();
+}
+
+QVector<uint64_t> SceneOpenGL::supportedDrmModifiers(uint32_t format)
+{
+    return m_backend->supportedDrmModifiers(format);
+}
+
+KWayland::Server::LinuxDmabuf::Buffer *SceneOpenGL::importDmabufBuffer(const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                                                       uint32_t format,
+                                                                       const QSize &size,
+                                                                       KWayland::Server::LinuxDmabuf::Flags flags)
+{
+    return m_backend->importDmabufBuffer(planes, format, size, flags);
+}
+
 QMatrix4x4 SceneOpenGL::transformation(int mask, const ScreenPaintData &data) const
 {
     QMatrix4x4 matrix;
diff --git a/scene.h b/scene.h
--- a/scene.h
+++ b/scene.h
@@ -25,6 +25,8 @@
 #include "utils.h"
 #include "kwineffects.h"
 
+#include <KWayland/Server/linuxdmabuf_v1_interface.h>
+
 #include <QElapsedTimer>
 #include <QMatrix4x4>
 
@@ -184,6 +186,30 @@
      **/
     virtual QVector<QByteArray> openGLPlatformInterfaceExtensions() const;
 
+    /**
+     * Returns the DRM formats supported by the underlying graphics stack.
+     *
+     * The default implementation returns an empty vector.
+     */
+    virtual QVector<uint32_t> supportedDrmFormats();
+
+    /**
+     * Returns the DRM modifiers supported with the given format.
+     *
+     * The default implementation returns an empty vector.
+     */
+    virtual QVector<uint64_t> supportedDrmModifiers(uint32_t format);
+
+    /**
+     * Imports a dmabuf-buffer into the graphics system used by the scene.
+     *
+     * The default implementation returns nullptr.
+     */
+    virtual KWayland::Server::LinuxDmabuf::Buffer *importDmabufBuffer(const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                                                      uint32_t format,
+                                                                      const QSize &size,
+                                                                      KWayland::Server::LinuxDmabuf::Flags flags = 0);
+
 Q_SIGNALS:
     void frameRendered();
     void resetCompositing();
diff --git a/scene.cpp b/scene.cpp
--- a/scene.cpp
+++ b/scene.cpp
@@ -677,6 +677,31 @@
     return QVector<QByteArray>{};
 }
 
+QVector<uint32_t> Scene::supportedDrmFormats()
+{
+    return QVector<uint32_t>();
+}
+
+QVector<uint64_t> Scene::supportedDrmModifiers(uint32_t format)
+{
+    Q_UNUSED(format)
+
+    return QVector<uint64_t>();
+}
+
+KWayland::Server::LinuxDmabuf::Buffer *Scene::importDmabufBuffer(const QVector<KWayland::Server::LinuxDmabuf::Plane> &planes,
+                                                                 uint32_t format,
+                                                                 const QSize &size,
+                                                                 KWayland::Server::LinuxDmabuf::Flags flags)
+{
+    Q_UNUSED(planes)
+    Q_UNUSED(format)
+    Q_UNUSED(size)
+    Q_UNUSED(flags)
+
+    return nullptr;
+}
+
 //****************************************
 // Scene::Window
 //****************************************
diff --git a/wayland_server.h b/wayland_server.h
--- a/wayland_server.h
+++ b/wayland_server.h
@@ -60,6 +60,7 @@
 class OutputConfigurationInterface;
 class XdgShellInterface;
 class XdgForeignInterface;
+class LinuxDmabufUnstableV1Interface;
 }
 }
 
@@ -70,6 +71,8 @@
 class AbstractClient;
 class Toplevel;
 
+class LinuxDmabufBridge;
+
 class KWIN_EXPORT WaylandServer : public QObject
 {
     Q_OBJECT
@@ -253,6 +256,8 @@
     QHash<KWayland::Server::ClientConnection*, quint16> m_clientIds;
     InitalizationFlags m_initFlags;
     QVector<KWayland::Server::PlasmaShellSurfaceInterface*> m_plasmaShellSurfaces;
+    KWayland::Server::LinuxDmabufUnstableV1Interface *m_linuxDmabuf;
+    LinuxDmabufBridge *m_linuxDmabufBridge;
     KWIN_SINGLETON(WaylandServer)
 };
 
diff --git a/wayland_server.cpp b/wayland_server.cpp
--- a/wayland_server.cpp
+++ b/wayland_server.cpp
@@ -25,6 +25,7 @@
 #include "screens.h"
 #include "shell_client.h"
 #include "workspace.h"
+#include "scene.h"
 
 // Client
 #include <KWayland/Client/connection_thread.h>
@@ -58,6 +59,7 @@
 #include <KWayland/Server/outputconfiguration_interface.h>
 #include <KWayland/Server/xdgshell_interface.h>
 #include <KWayland/Server/xdgforeign_interface.h>
+#include <KWayland/Server/linuxdmabuf_v1_interface.h>
 
 // Qt
 #include <QThread>
@@ -78,6 +80,39 @@
 
 KWIN_SINGLETON_FACTORY(WaylandServer)
 
+
+class LinuxDmabufBridge : public LinuxDmabufUnstableV1Interface::Bridge
+{
+public:
+    LinuxDmabufBridge() = default;
+    ~LinuxDmabufBridge() = default;
+
+    QVector<uint32_t> supportedFormats() const override final;
+    QVector<uint64_t> supportedModifiers(uint32_t format) const override final;
+    LinuxDmabuf::Buffer *importBuffer(const QVector<LinuxDmabuf::Plane> &planes, uint32_t format, const QSize &size, LinuxDmabuf::Flags flags) override final;
+};
+
+QVector<uint32_t> LinuxDmabufBridge::supportedFormats() const
+{
+    return Compositor::self()->scene()->supportedDrmFormats();
+}
+
+QVector<uint64_t> LinuxDmabufBridge::supportedModifiers(uint32_t format) const
+{
+    return Compositor::self()->scene()->supportedDrmModifiers(format);
+}
+
+LinuxDmabuf::Buffer *LinuxDmabufBridge::importBuffer(const QVector<LinuxDmabuf::Plane> &planes, uint32_t format, const QSize &size, LinuxDmabuf::Flags flags)
+{
+    return Compositor::self()->scene()->importDmabufBuffer(planes, format, size, flags);
+}
+
+
+
+// --------------------------------------------------------------------
+
+
+
 WaylandServer::WaylandServer(QObject *parent)
     : QObject(parent)
 {
@@ -90,6 +125,8 @@
 WaylandServer::~WaylandServer()
 {
     destroyInputMethodConnection();
+    m_linuxDmabuf->setBridge(nullptr);
+    delete m_linuxDmabufBridge;
 }
 
 void WaylandServer::destroyInternalConnection()
@@ -359,6 +396,12 @@
     m_XdgForeign = m_display->createXdgForeignInterface(m_display);
     m_XdgForeign->create();
 
+    m_linuxDmabufBridge = new LinuxDmabufBridge;
+
+    m_linuxDmabuf = m_display->createLinuxDmabufInterface(m_display);
+    m_linuxDmabuf->setBridge(m_linuxDmabufBridge);
+    m_linuxDmabuf->create();
+
     return true;
 }
 

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: