summaryrefslogtreecommitdiffstats
path: root/src/hardwareintegration/compositor
diff options
context:
space:
mode:
Diffstat (limited to 'src/hardwareintegration/compositor')
-rw-r--r--src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h3
-rw-r--r--src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp2
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri16
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp332
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h162
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp501
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h138
-rw-r--r--src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h5
-rw-r--r--src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h2
9 files changed, 1157 insertions, 4 deletions
diff --git a/src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h b/src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h
index 3028fbed5..83545de2e 100644
--- a/src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h
+++ b/src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h
@@ -41,6 +41,7 @@
#define BRCMBUFFER_H
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <QtCore/QSize>
#include <QtCore/QVector>
@@ -62,7 +63,7 @@ public:
QSize size() { return m_size; }
- static BrcmBuffer *fromResource(struct ::wl_resource *resource) { return static_cast<BrcmBuffer*>(Resource::fromResource(resource)->buffer_object); }
+ static BrcmBuffer *fromResource(struct ::wl_resource *resource) { return QtWayland::fromResource<BrcmBuffer *>(resource); }
protected:
void buffer_destroy_resource(Resource *resource) override;
diff --git a/src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp b/src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp
index 5a42c00dc..af9059603 100644
--- a/src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp
@@ -42,7 +42,7 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLTexture>
#include <hybris/eglplatformcommon/hybris_nativebufferext.h>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE
LibHybrisEglServerBuffer::LibHybrisEglServerBuffer(LibHybrisEglServerBufferIntegration *integration, const QImage &qimage, QtWayland::ServerBuffer::Format format)
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri
new file mode 100644
index 000000000..77f6d9410
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri
@@ -0,0 +1,16 @@
+INCLUDEPATH += $$PWD
+
+QMAKE_USE_PRIVATE += egl wayland-server wayland-egl
+
+CONFIG += wayland-scanner
+WAYLANDSERVERSOURCES += $$PWD/../../../3rdparty/protocol/linux-dmabuf-unstable-v1.xml
+
+QT += egl_support-private
+
+SOURCES += \
+ $$PWD/linuxdmabufclientbufferintegration.cpp \
+ $$PWD/linuxdmabuf.cpp
+
+HEADERS += \
+ $$PWD/linuxdmabufclientbufferintegration.h \
+ $$PWD/linuxdmabuf.h
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp
new file mode 100644
index 000000000..2ba0462c7
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "linuxdmabuf.h"
+#include "linuxdmabufclientbufferintegration.h"
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+
+#include <drm_fourcc.h>
+#include <drm_mode.h>
+#include <unistd.h>
+
+QT_BEGIN_NAMESPACE
+
+LinuxDmabuf::LinuxDmabuf(wl_display *display, LinuxDmabufClientBufferIntegration *clientBufferIntegration)
+ : zwp_linux_dmabuf_v1(display, 3 /*version*/)
+ , m_clientBufferIntegration(clientBufferIntegration)
+{
+}
+
+void LinuxDmabuf::setSupportedModifiers(const QHash<uint32_t, QVector<uint64_t>> &modifiers)
+{
+ Q_ASSERT(resourceMap().isEmpty());
+ m_modifiers = modifiers;
+}
+
+void LinuxDmabuf::zwp_linux_dmabuf_v1_bind_resource(Resource *resource)
+{
+ for (auto it = m_modifiers.constBegin(); it != m_modifiers.constEnd(); ++it) {
+ auto format = it.key();
+ auto modifiers = it.value();
+ // send DRM_FORMAT_MOD_INVALID when no modifiers are supported for a format
+ if (modifiers.isEmpty())
+ modifiers << DRM_FORMAT_MOD_INVALID;
+ for (const auto &modifier : qAsConst(modifiers)) {
+ if (resource->version() >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
+ const uint32_t modifier_lo = modifier & 0xFFFFFFFF;
+ const uint32_t modifier_hi = modifier >> 32;
+ send_modifier(resource->handle, format, modifier_hi, modifier_lo);
+ } else if (modifier == DRM_FORMAT_MOD_LINEAR || modifier == DRM_FORMAT_MOD_INVALID) {
+ send_format(resource->handle, format);
+ }
+ }
+ }
+}
+
+void LinuxDmabuf::zwp_linux_dmabuf_v1_create_params(Resource *resource, uint32_t params_id)
+{
+ wl_resource *r = wl_resource_create(resource->client(), &zwp_linux_buffer_params_v1_interface,
+ wl_resource_get_version(resource->handle), params_id);
+ new LinuxDmabufParams(m_clientBufferIntegration, r); // deleted by the client, or when it disconnects
+}
+
+LinuxDmabufParams::LinuxDmabufParams(LinuxDmabufClientBufferIntegration *clientBufferIntegration, wl_resource *resource)
+ : zwp_linux_buffer_params_v1(resource)
+ , m_clientBufferIntegration(clientBufferIntegration)
+{
+}
+
+LinuxDmabufParams::~LinuxDmabufParams()
+{
+ for (auto it = m_planes.begin(); it != m_planes.end(); ++it) {
+ if (it.value().fd != -1)
+ close(it.value().fd);
+ it.value().fd = -1;
+ }
+}
+
+bool LinuxDmabufParams::handleCreateParams(Resource *resource, int width, int height, uint format, uint flags)
+{
+ if (m_used) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
+ "Params already used");
+ return false;
+ }
+
+ if (width <= 0 || height <= 0) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
+ "Invalid dimensions in create request");
+ return false;
+ }
+
+ if (m_planes.isEmpty()) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+ "Cannot create a buffer with no planes");
+ return false;
+ }
+
+ // check for holes in plane sequence
+ auto planeIds = m_planes.keys();
+ std::sort(planeIds.begin(), planeIds.end());
+ for (int i = 0; i < planeIds.count(); ++i) {
+ if (uint(i) != planeIds[i]) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+ "No dmabuf parameters provided for plane %i", i);
+ return false;
+ }
+ }
+
+ // check for overflows
+ for (auto it = m_planes.constBegin(); it != m_planes.constEnd(); ++it) {
+ const auto planeId = it.key();
+ const auto plane = it.value();
+ if (static_cast<int64_t>(plane.offset) + plane.stride > UINT32_MAX) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Size overflow for plane %i",
+ planeId);
+ return false;
+ }
+ if (planeId == 0 && static_cast<int64_t>(plane.offset) + plane.stride * static_cast<int64_t>(height) > UINT32_MAX) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Size overflow for plane %i",
+ planeId);
+ return false;
+ }
+
+ // do not report an error as it might be caused by the kernel not supporting seeking on dmabuf
+ off_t size = lseek(plane.fd, 0, SEEK_END);
+ if (size == -1) {
+ qCDebug(qLcWaylandCompositorHardwareIntegration) << "Seeking is not supported";
+ continue;
+ }
+
+ if (static_cast<int64_t>(plane.offset) >= size) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Invalid offset %i for plane %i",
+ plane.offset, planeId);
+ return false;
+ }
+
+ if (static_cast<int64_t>(plane.offset) + static_cast<int64_t>(plane.stride) > size) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Invalid stride %i for plane %i",
+ plane.stride, planeId);
+ return false;
+ }
+
+ // only valid for first plane as other planes might be sub-sampled
+ if (planeId == 0 && plane.offset + static_cast<int64_t>(plane.stride) * height > size) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Invalid buffer stride or height for plane %i", planeId);
+ return false;
+ }
+ }
+
+ m_size = QSize(width, height);
+ m_drmFormat = format;
+ m_flags = flags;
+ m_used = true;
+
+ return true;
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ delete this;
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_add(Resource *resource, int32_t fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint32_t modifier_hi, uint32_t modifier_lo)
+{
+ const uint64_t modifiers = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_lo;
+ if (plane_idx >= LinuxDmabufWlBuffer::MaxDmabufPlanes) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
+ "Plane index %i is out of bounds", plane_idx);
+ }
+
+ if (m_planes.contains(plane_idx)) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
+ "Plane already set");
+ }
+
+ Plane plane;
+ plane.fd = fd;
+ plane.modifiers = modifiers;
+ plane.offset = offset;
+ plane.stride = stride;
+ m_planes.insert(plane_idx, plane);
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_create(Resource *resource, int32_t width, int32_t height, uint32_t format, uint32_t flags)
+{
+ if (!handleCreateParams(resource, width, height, format, flags))
+ return;
+
+ auto *buffer = new LinuxDmabufWlBuffer(resource->client(), m_clientBufferIntegration);
+ buffer->m_size = m_size;
+ buffer->m_flags = m_flags;
+ buffer->m_drmFormat = m_drmFormat;
+ buffer->m_planesNumber = m_planes.size(); // it is checked before that planes are in consecutive sequence
+ for (auto it = m_planes.begin(); it != m_planes.end(); ++it) {
+ buffer->m_planes[it.key()] = it.value();
+ it.value().fd = -1; // ownership is moved
+ }
+
+ if (!m_clientBufferIntegration->importBuffer(buffer->resource()->handle, buffer)) {
+ send_failed(resource->handle);
+ } else {
+ send_created(resource->handle, buffer->resource()->handle);
+ }
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_create_immed(Resource *resource, uint32_t buffer_id, int32_t width, int32_t height, uint32_t format, uint32_t flags)
+{
+ if (!handleCreateParams(resource, width, height, format, flags))
+ return;
+
+ auto *buffer = new LinuxDmabufWlBuffer(resource->client(), m_clientBufferIntegration, buffer_id);
+ buffer->m_size = m_size;
+ buffer->m_flags = m_flags;
+ buffer->m_drmFormat = m_drmFormat;
+ buffer->m_planesNumber = m_planes.size(); // it is checked before that planes are in consecutive sequence
+ for (auto it = m_planes.begin(); it != m_planes.end(); ++it) {
+ buffer->m_planes[it.key()] = it.value();
+ it.value().fd = -1; // ownership is moved
+ }
+
+ if (!m_clientBufferIntegration->importBuffer(buffer->resource()->handle, buffer)) {
+ // for the 'create_immed' request, the implementation can decide
+ // how to handle the failure by an unknown cause; we decide
+ // to raise a fatal error at the client
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
+ "Import of the provided DMA buffer failed");
+ }
+ // note: create signal shall not be sent for the 'create_immed' request
+}
+
+LinuxDmabufWlBuffer::LinuxDmabufWlBuffer(::wl_client *client, LinuxDmabufClientBufferIntegration *clientBufferIntegration, uint id)
+ : wl_buffer(client, id, 1 /*version*/)
+ , m_clientBufferIntegration(clientBufferIntegration)
+{
+}
+
+LinuxDmabufWlBuffer::~LinuxDmabufWlBuffer()
+{
+ m_clientBufferIntegration->removeBuffer(resource()->handle);
+ buffer_destroy(resource());
+}
+
+void LinuxDmabufWlBuffer::buffer_destroy(Resource *resource)
+{
+ Q_UNUSED(resource);
+ for (uint32_t i = 0; i < m_planesNumber; ++i) {
+ if (m_textures[i] != nullptr) {
+ m_clientBufferIntegration->deleteGLTextureWhenPossible(m_textures[i]);
+ m_textures[i] = nullptr;
+ }
+ if (m_eglImages[i] != EGL_NO_IMAGE_KHR) {
+ m_clientBufferIntegration->deleteImage(m_eglImages[i]);
+ m_eglImages[i] = EGL_NO_IMAGE_KHR;
+ }
+ if (m_planes[i].fd != -1)
+ close(m_planes[i].fd);
+ m_planes[i].fd = -1;
+ }
+ m_planesNumber = 0;
+}
+
+void LinuxDmabufWlBuffer::initImage(uint32_t plane, EGLImageKHR image)
+{
+ Q_ASSERT(plane < m_planesNumber);
+ Q_ASSERT(m_eglImages.at(plane) == EGL_NO_IMAGE_KHR);
+ m_eglImages[plane] = image;
+}
+
+void LinuxDmabufWlBuffer::initTexture(uint32_t plane, QOpenGLTexture *texture)
+{
+ Q_ASSERT(plane < m_planesNumber);
+ Q_ASSERT(m_textures.at(plane) == nullptr);
+ m_textures[plane] = texture;
+}
+
+void LinuxDmabufWlBuffer::buffer_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ delete this;
+}
+
+QT_END_NAMESPACE
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h
new file mode 100644
index 000000000..2abc2ce6b
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LINUXDMABUF_H
+#define LINUXDMABUF_H
+
+#include "qwayland-server-linux-dmabuf-unstable-v1.h"
+
+#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QSize>
+#include <QtCore/QTextStream>
+#include <QtGui/QOpenGLTexture>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+// compatibility with libdrm <= 2.4.74
+#ifndef DRM_FORMAT_RESERVED
+#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1)
+#endif
+#ifndef DRM_FORMAT_MOD_VENDOR_NONE
+#define DRM_FORMAT_MOD_VENDOR_NONE 0
+#endif
+#ifndef DRM_FORMAT_MOD_LINEAR
+#define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0)
+#endif
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandCompositor;
+class QWaylandResource;
+class LinuxDmabufParams;
+class LinuxDmabufClientBufferIntegration;
+
+struct Plane {
+ int fd = -1;
+ uint32_t offset = 0;
+ uint32_t stride = 0;
+ uint64_t modifiers = 0;
+};
+
+class LinuxDmabuf : public QtWaylandServer::zwp_linux_dmabuf_v1
+{
+public:
+ explicit LinuxDmabuf(wl_display *display, LinuxDmabufClientBufferIntegration *clientBufferIntegration);
+
+ void setSupportedModifiers(const QHash<uint32_t, QVector<uint64_t>> &modifiers);
+
+protected:
+ void zwp_linux_dmabuf_v1_bind_resource(Resource *resource) override;
+ void zwp_linux_dmabuf_v1_create_params(Resource *resource, uint32_t params_id) override;
+
+private:
+ QHash<uint32_t, QVector<uint64_t>> m_modifiers; // key=DRM format, value=supported DRM modifiers for format
+ LinuxDmabufClientBufferIntegration *m_clientBufferIntegration;
+};
+
+class LinuxDmabufParams : public QtWaylandServer::zwp_linux_buffer_params_v1
+{
+public:
+ explicit LinuxDmabufParams(LinuxDmabufClientBufferIntegration *clientBufferIntegration, wl_resource *resource);
+ ~LinuxDmabufParams() override;
+
+private:
+ bool handleCreateParams(Resource *resource, int width, int height, uint format, uint flags);
+ uint m_drmFormat = 0;
+ uint m_flags = 0;
+ QSize m_size;
+ bool m_used = false;
+ QMap<uint, Plane> m_planes;
+ LinuxDmabufClientBufferIntegration *m_clientBufferIntegration;
+
+protected:
+ void zwp_linux_buffer_params_v1_destroy(Resource *resource) override;
+ void zwp_linux_buffer_params_v1_add(Resource *resource, int32_t fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint32_t modifier_hi, uint32_t modifier_lo) override;
+ void zwp_linux_buffer_params_v1_create(Resource *resource, int32_t width, int32_t height, uint32_t format, uint32_t flags) override;
+ void zwp_linux_buffer_params_v1_create_immed(Resource *resource, uint32_t buffer_id, int32_t width, int32_t height, uint32_t format, uint32_t flags) override;
+ void zwp_linux_buffer_params_v1_destroy_resource(Resource *resource) override;
+
+ friend class LinuxDmabufClientBufferIntegrationPrivate;
+};
+
+class LinuxDmabufWlBuffer : public QtWaylandServer::wl_buffer
+{
+public:
+ explicit LinuxDmabufWlBuffer(::wl_client *client, LinuxDmabufClientBufferIntegration *clientBufferIntegration, uint id = 0);
+ ~LinuxDmabufWlBuffer() override;
+
+ void initImage(uint32_t plane, EGLImageKHR image);
+ void initTexture(uint32_t plane, QOpenGLTexture *texture);
+ inline QSize size() const { return m_size; }
+ inline uint32_t flags() const { return m_flags; }
+ inline uint32_t drmFormat() const { return m_drmFormat; }
+ inline Plane& plane(uint index) { return m_planes.at(index); }
+ inline uint32_t planesNumber() const { return m_planesNumber; }
+ inline EGLImageKHR image(uint32_t plane) { return m_eglImages.at(plane); }
+ inline QOpenGLTexture *texture(uint32_t plane) const { return m_textures.at(plane); }
+ void buffer_destroy_resource(Resource *resource) override;
+
+ static const uint32_t MaxDmabufPlanes = 4;
+
+private:
+ QSize m_size;
+ uint32_t m_flags = 0;
+ uint32_t m_drmFormat = EGL_TEXTURE_RGBA;
+ std::array<Plane, MaxDmabufPlanes> m_planes;
+ uint32_t m_planesNumber = 1;
+ LinuxDmabufClientBufferIntegration *m_clientBufferIntegration = nullptr;
+ std::array<EGLImageKHR, MaxDmabufPlanes> m_eglImages = { {EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR} };
+ std::array<QOpenGLTexture *, MaxDmabufPlanes> m_textures = { {nullptr, nullptr, nullptr, nullptr} };
+ void freeResources();
+ void buffer_destroy(Resource *resource) override;
+
+ friend class LinuxDmabufParams;
+};
+
+QT_END_NAMESPACE
+
+#endif // LINUXDMABUF_H
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp
new file mode 100644
index 000000000..a85f24542
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "linuxdmabufclientbufferintegration.h"
+#include "linuxdmabuf.h"
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLTexture>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <unistd.h>
+#include <drm_fourcc.h>
+
+QT_BEGIN_NAMESPACE
+
+static QWaylandBufferRef::BufferFormatEgl formatFromDrmFormat(EGLint format) {
+ switch (format) {
+ case DRM_FORMAT_RGB332:
+ case DRM_FORMAT_BGR233:
+ case DRM_FORMAT_XRGB4444:
+ case DRM_FORMAT_XBGR4444:
+ case DRM_FORMAT_RGBX4444:
+ case DRM_FORMAT_BGRX4444:
+ case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_XBGR1555:
+ case DRM_FORMAT_RGBX5551:
+ case DRM_FORMAT_BGRX5551:
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_RGBX1010102:
+ case DRM_FORMAT_BGRX1010102:
+ return QWaylandBufferRef::BufferFormatEgl_RGB;
+ case DRM_FORMAT_ARGB4444:
+ case DRM_FORMAT_ABGR4444:
+ case DRM_FORMAT_RGBA4444:
+ case DRM_FORMAT_BGRA4444:
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_BGRA5551:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_BGRA1010102:
+ return QWaylandBufferRef::BufferFormatEgl_RGBA;
+ case DRM_FORMAT_YUYV:
+ return QWaylandBufferRef::BufferFormatEgl_Y_XUXV;
+ default:
+ qCDebug(qLcWaylandCompositorHardwareIntegration) << "Buffer format" << hex << format << "not supported";
+ return QWaylandBufferRef::BufferFormatEgl_Null;
+ }
+}
+
+static QOpenGLTexture::TextureFormat openGLFormatFromBufferFormat(QWaylandBufferRef::BufferFormatEgl format) {
+ switch (format) {
+ case QWaylandBufferRef::BufferFormatEgl_RGB:
+ return QOpenGLTexture::RGBFormat;
+ case QWaylandBufferRef::BufferFormatEgl_RGBA:
+ return QOpenGLTexture::RGBAFormat;
+ default:
+ return QOpenGLTexture::NoFormat;
+ }
+}
+
+bool LinuxDmabufClientBufferIntegration::initSimpleTexture(LinuxDmabufWlBuffer *dmabufBuffer)
+{
+ bool success = true;
+
+ // Resolving GL functions may need a context current, so do it only here.
+ if (!gl_egl_image_target_texture_2d)
+ gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
+
+ if (dmabufBuffer->plane(0).modifiers != DRM_FORMAT_MOD_INVALID && !m_supportsDmabufModifiers) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Buffer uses dmabuf modifiers, which are not supported.";
+ success = false;
+ }
+
+ for (uint32_t i = 0; i < dmabufBuffer->planesNumber(); ++i) {
+ QVarLengthArray<EGLint, 17> attribs;
+ switch (i) {
+ case 0:
+ attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width(),
+ EGL_HEIGHT, dmabufBuffer->size().height(),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()),
+ EGL_DMA_BUF_PLANE0_FD_EXT, dmabufBuffer->plane(i).fd,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset),
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride),
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32),
+ EGL_NONE
+ };
+ break;
+ case 1:
+ attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width(),
+ EGL_HEIGHT, dmabufBuffer->size().height(),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()),
+ EGL_DMA_BUF_PLANE1_FD_EXT, dmabufBuffer->plane(i).fd,
+ EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset),
+ EGL_DMA_BUF_PLANE1_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride),
+ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32),
+ EGL_NONE
+ };
+ break;
+ case 2:
+ attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width(),
+ EGL_HEIGHT, dmabufBuffer->size().height(),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()),
+ EGL_DMA_BUF_PLANE2_FD_EXT, dmabufBuffer->plane(i).fd,
+ EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset),
+ EGL_DMA_BUF_PLANE2_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride),
+ EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32),
+ EGL_NONE
+ };
+ break;
+ case 3:
+ attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width(),
+ EGL_HEIGHT, dmabufBuffer->size().height(),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()),
+ EGL_DMA_BUF_PLANE3_FD_EXT, dmabufBuffer->plane(i).fd,
+ EGL_DMA_BUF_PLANE3_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset),
+ EGL_DMA_BUF_PLANE3_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride),
+ EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32),
+ EGL_NONE
+ };
+ break;
+ default:
+ return false;
+ }
+
+ // note: EGLImageKHR does NOT take ownership of the file descriptors
+ EGLImageKHR image = egl_create_image(m_eglDisplay,
+ EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT,
+ (EGLClientBuffer) nullptr,
+ attribs.constData());
+
+ if (image == EGL_NO_IMAGE_KHR) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "failed to create EGL image for plane" << i;
+ success = false;
+ }
+
+ dmabufBuffer->initImage(i, image);
+ }
+ return success;
+}
+
+bool LinuxDmabufClientBufferIntegration::initYuvTexture(LinuxDmabufWlBuffer *dmabufBuffer)
+{
+ bool success = true;
+
+ const YuvFormatConversion conversion = m_yuvFormats.value(dmabufBuffer->drmFormat());
+ if (conversion.inputPlanes != dmabufBuffer->planesNumber()) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Buffer for this format must provide" << conversion.inputPlanes
+ << "planes but only" << dmabufBuffer->planesNumber() << "received";
+ return false;
+ }
+
+ // Resolving GL functions may need a context current, so do it only here.
+ if (!gl_egl_image_target_texture_2d)
+ gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
+
+
+ if (dmabufBuffer->plane(0).modifiers != DRM_FORMAT_MOD_INVALID && !m_supportsDmabufModifiers) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Buffer uses dmabuf modifiers, which are not supported.";
+ success = false;
+ }
+
+ for (uint32_t i = 0; i < conversion.outputPlanes; ++i) {
+ const YuvPlaneConversion plane = conversion.plane[i];
+
+ QVarLengthArray<EGLint, 17> attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width() / plane.widthDivisor,
+ EGL_HEIGHT, dmabufBuffer->size().height() / plane.heightDivisor,
+ EGL_LINUX_DRM_FOURCC_EXT, plane.format,
+ EGL_DMA_BUF_PLANE0_FD_EXT, dmabufBuffer->plane(plane.planeIndex).fd,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGLint(dmabufBuffer->plane(plane.planeIndex).offset),
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, EGLint(dmabufBuffer->plane(plane.planeIndex).stride),
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(plane.planeIndex).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(plane.planeIndex).modifiers >> 32),
+ EGL_NONE
+ };
+
+ // note: EGLImageKHR does NOT take ownership of the file descriptors
+ EGLImageKHR image = egl_create_image(m_eglDisplay,
+ EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT,
+ (EGLClientBuffer) nullptr,
+ attribs.constData());
+
+ if (image == EGL_NO_IMAGE_KHR) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "failed to create EGL image for plane" << i;
+ success = false;
+ }
+
+ dmabufBuffer->initImage(i, image);
+ }
+ return success;
+}
+
+LinuxDmabufClientBufferIntegration::LinuxDmabufClientBufferIntegration()
+{
+ m_yuvFormats.insert(DRM_FORMAT_YUYV,
+ YuvFormatConversion {
+ .inputPlanes = 1,
+ .outputPlanes = 2,
+ {{
+ .format = DRM_FORMAT_GR88,
+ .widthDivisor = 1,
+ .heightDivisor = 1,
+ .planeIndex = 0
+ }, {
+ .format = DRM_FORMAT_ARGB8888,
+ .widthDivisor = 2,
+ .heightDivisor = 1,
+ .planeIndex = 0
+ }}
+ });
+}
+
+LinuxDmabufClientBufferIntegration::~LinuxDmabufClientBufferIntegration()
+{
+ m_importedBuffers.clear();
+}
+
+void LinuxDmabufClientBufferIntegration::initializeHardware(struct ::wl_display *display)
+{
+ m_linuxDmabuf.reset(new LinuxDmabuf(display, this));
+
+ const bool ignoreBindDisplay = !qgetenv("QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty() && qgetenv("QT_WAYLAND_IGNORE_BIND_DISPLAY").toInt() != 0;
+
+ // initialize hardware extensions
+ egl_query_dmabuf_modifiers_ext = reinterpret_cast<PFNEGLQUERYDMABUFMODIFIERSEXTPROC>(eglGetProcAddress("eglQueryDmaBufModifiersEXT"));
+ egl_query_dmabuf_formats_ext = reinterpret_cast<PFNEGLQUERYDMABUFFORMATSEXTPROC>(eglGetProcAddress("eglQueryDmaBufFormatsEXT"));
+ if (!egl_query_dmabuf_modifiers_ext || !egl_query_dmabuf_formats_ext) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not find eglQueryDmaBufModifiersEXT and eglQueryDmaBufFormatsEXT.";
+ return;
+ }
+
+ egl_bind_wayland_display = reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL"));
+ egl_unbind_wayland_display = reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglUnbindWaylandDisplayWL"));
+ if ((!egl_bind_wayland_display || !egl_unbind_wayland_display) && !ignoreBindDisplay) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.";
+ return;
+ }
+
+ egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
+ egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
+ if (!egl_create_image || !egl_destroy_image) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not find eglCreateImageKHR and eglDestroyImageKHR.";
+ return;
+ }
+
+ // initialize EGL display
+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
+ if (!nativeInterface) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. No native platform interface available.";
+ return;
+ }
+
+ m_eglDisplay = nativeInterface->nativeResourceForIntegration("EglDisplay");
+ if (!m_eglDisplay) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not get EglDisplay for window.";
+ return;
+ }
+
+ const char *extensionString = eglQueryString(m_eglDisplay, EGL_EXTENSIONS);
+ if (!extensionString || !strstr(extensionString, "EGL_EXT_image_dma_buf_import")) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. There is no EGL_EXT_image_dma_buf_import extension.";
+ return;
+ }
+ if (strstr(extensionString, "EGL_EXT_image_dma_buf_import_modifiers"))
+ m_supportsDmabufModifiers = true;
+
+ if (egl_bind_wayland_display && egl_unbind_wayland_display) {
+ m_displayBound = egl_bind_wayland_display(m_eglDisplay, display);
+ if (!m_displayBound) {
+ if (ignoreBindDisplay) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Could not bind Wayland display. Ignoring.";
+ } else {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not bind Wayland display.";
+ return;
+ }
+ }
+ }
+
+ // request and sent formats/modifiers only after egl_display is bound
+ QHash<uint32_t, QVector<uint64_t>> modifiers;
+ for (const auto &format : supportedDrmFormats()) {
+ modifiers[format] = supportedDrmModifiers(format);
+ }
+ m_linuxDmabuf->setSupportedModifiers(modifiers);
+}
+
+QVector<uint32_t> LinuxDmabufClientBufferIntegration::supportedDrmFormats()
+{
+ if (!egl_query_dmabuf_formats_ext)
+ return QVector<uint32_t>();
+
+ // request total number of formats
+ EGLint count = 0;
+ EGLBoolean success = egl_query_dmabuf_formats_ext(m_eglDisplay, 0, nullptr, &count);
+
+ if (success && count > 0) {
+ QVector<uint32_t> drmFormats(count);
+ if (egl_query_dmabuf_formats_ext(m_eglDisplay, count, (EGLint *) drmFormats.data(), &count))
+ return drmFormats;
+ }
+
+ return QVector<uint32_t>();
+}
+
+QVector<uint64_t> LinuxDmabufClientBufferIntegration::supportedDrmModifiers(uint32_t format)
+{
+ if (!egl_query_dmabuf_modifiers_ext)
+ return QVector<uint64_t>();
+
+ // request total number of formats
+ EGLint count = 0;
+ EGLBoolean success = egl_query_dmabuf_modifiers_ext(m_eglDisplay, format, 0, nullptr, nullptr, &count);
+
+ if (success && count > 0) {
+ QVector<uint64_t> modifiers(count);
+ if (egl_query_dmabuf_modifiers_ext(m_eglDisplay, format, count, modifiers.data(), nullptr, &count)) {
+ return modifiers;
+ }
+ }
+
+ return QVector<uint64_t>();
+}
+
+void LinuxDmabufClientBufferIntegration::deleteOrphanedTextures()
+{
+ Q_ASSERT(QOpenGLContext::currentContext());
+ qDeleteAll(m_orphanedTextures);
+ m_orphanedTextures.clear();
+}
+
+void LinuxDmabufClientBufferIntegration::deleteImage(EGLImageKHR image)
+{
+ egl_destroy_image(m_eglDisplay, image);
+}
+
+QtWayland::ClientBuffer *LinuxDmabufClientBufferIntegration::createBufferFor(wl_resource *resource)
+{
+ // fallback for shared memory buffers
+ if (wl_shm_buffer_get(resource))
+ return nullptr;
+
+ auto it = m_importedBuffers.find(resource);
+ if (it != m_importedBuffers.end()) {
+ m_importedBuffers.value(resource);
+ return new LinuxDmabufClientBuffer(this, it.value()->resource()->handle, m_importedBuffers.value(resource));
+ }
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "could not create client buffer for dmabuf buffer";
+ return nullptr;
+}
+
+bool LinuxDmabufClientBufferIntegration::importBuffer(wl_resource *resource, LinuxDmabufWlBuffer *linuxDmabufBuffer)
+{
+ if (m_importedBuffers.contains(resource)) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "buffer has already been added";
+ return false;
+ }
+ m_importedBuffers[resource] = linuxDmabufBuffer;
+ if (m_yuvFormats.contains(linuxDmabufBuffer->drmFormat()))
+ return initYuvTexture(linuxDmabufBuffer);
+ else
+ return initSimpleTexture(linuxDmabufBuffer);
+}
+
+void LinuxDmabufClientBufferIntegration::removeBuffer(wl_resource *resource)
+{
+ m_importedBuffers.remove(resource);
+}
+
+LinuxDmabufClientBuffer::LinuxDmabufClientBuffer(LinuxDmabufClientBufferIntegration *integration,
+ wl_resource *bufferResource,
+ LinuxDmabufWlBuffer *dmabufBuffer)
+ : ClientBuffer(bufferResource)
+ , m_integration(integration)
+{
+ d = dmabufBuffer;
+}
+
+QOpenGLTexture *LinuxDmabufClientBuffer::toOpenGlTexture(int plane)
+{
+ // At this point we should have a valid OpenGL context, so it's safe to destroy textures
+ m_integration->deleteOrphanedTextures();
+
+ if (!m_buffer)
+ return nullptr;
+
+ QOpenGLTexture *texture = d->texture(plane);
+
+ const auto target = static_cast<QOpenGLTexture::Target>(GL_TEXTURE_2D);
+
+ if (!texture) {
+ texture = new QOpenGLTexture(target);
+ texture->setFormat(openGLFormatFromBufferFormat(formatFromDrmFormat(d->drmFormat())));
+ texture->setSize(d->size().width(), d->size().height());
+ texture->create();
+ d->initTexture(plane, texture);
+ }
+
+ if (m_textureDirty) {
+ texture->bind();
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ m_integration->gl_egl_image_target_texture_2d(target, d->image(plane));
+ }
+ return texture;
+}
+
+void LinuxDmabufClientBuffer::setDestroyed()
+{
+ m_integration->removeBuffer(m_buffer);
+ ClientBuffer::setDestroyed();
+}
+
+LinuxDmabufClientBuffer::~LinuxDmabufClientBuffer()
+{
+ // resources are deleted by buffer_destroy_resource
+ m_buffer = nullptr;
+ d = nullptr;
+}
+
+QWaylandBufferRef::BufferFormatEgl LinuxDmabufClientBuffer::bufferFormatEgl() const
+{
+ return formatFromDrmFormat(d->drmFormat());
+}
+
+QSize LinuxDmabufClientBuffer::size() const
+{
+ return d->size();
+}
+
+QWaylandSurface::Origin LinuxDmabufClientBuffer::origin() const
+{
+ return (d->flags() & QtWaylandServer::zwp_linux_buffer_params_v1::flags_y_invert) ? QWaylandSurface::OriginBottomLeft : QWaylandSurface::OriginTopLeft;
+}
+
+QT_END_NAMESPACE
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h
new file mode 100644
index 000000000..914c1e7a6
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LINUXDMABUFCLIENTBUFFERINTEGRATION_H
+#define LINUXDMABUFCLIENTBUFFERINTEGRATION_H
+
+#include "linuxdmabuf.h"
+
+#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h>
+#include <QtWaylandCompositor/private/qwlclientbuffer_p.h>
+#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+
+#include <drm_fourcc.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL_compat) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+
+class LinuxDmabufClientBufferIntegrationPrivate;
+class LinuxDmabufParams;
+class LinuxDmabufClientBuffer;
+
+// buffer conversion definitions to import YUV buffers
+struct YuvPlaneConversion {
+ EGLint format = DRM_FORMAT_YUYV;
+ EGLint widthDivisor = 1;
+ EGLint heightDivisor = 1;
+ EGLint planeIndex = 0;
+};
+struct YuvFormatConversion {
+ uint32_t inputPlanes = 1;
+ uint32_t outputPlanes = 1;
+ struct YuvPlaneConversion plane[LinuxDmabufWlBuffer::MaxDmabufPlanes];
+};
+
+class LinuxDmabufClientBufferIntegration : public QtWayland::ClientBufferIntegration
+{
+public:
+ LinuxDmabufClientBufferIntegration();
+ ~LinuxDmabufClientBufferIntegration() override;
+
+ void initializeHardware(struct ::wl_display *display) override;
+ QtWayland::ClientBuffer *createBufferFor(wl_resource *resource) override;
+ bool importBuffer(wl_resource *resource, LinuxDmabufWlBuffer *linuxDmabufBuffer);
+ void removeBuffer(wl_resource *resource);
+ void deleteOrphanedTextures();
+ void deleteImage(EGLImageKHR image);
+ void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { m_orphanedTextures << texture; }
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d = nullptr;
+
+private:
+ Q_DISABLE_COPY(LinuxDmabufClientBufferIntegration)
+
+ PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display = nullptr;
+ PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display = nullptr;
+ PFNEGLCREATEIMAGEKHRPROC egl_create_image = nullptr;
+ PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image = nullptr;
+ PFNEGLQUERYDMABUFMODIFIERSEXTPROC egl_query_dmabuf_modifiers_ext = nullptr;
+ PFNEGLQUERYDMABUFFORMATSEXTPROC egl_query_dmabuf_formats_ext = nullptr;
+
+ bool initSimpleTexture(LinuxDmabufWlBuffer *dmabufBuffer);
+ bool initYuvTexture(LinuxDmabufWlBuffer *dmabufBuffer);
+ QVector<uint32_t> supportedDrmFormats();
+ QVector<uint64_t> supportedDrmModifiers(uint32_t format);
+
+ EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
+ bool m_displayBound = false;
+ QVector<QOpenGLTexture *> m_orphanedTextures;
+ QHash<EGLint, YuvFormatConversion> m_yuvFormats;
+ bool m_supportsDmabufModifiers = false;
+ QHash<struct ::wl_resource *, LinuxDmabufWlBuffer *> m_importedBuffers;
+ QScopedPointer<LinuxDmabuf> m_linuxDmabuf;
+};
+
+class LinuxDmabufClientBuffer : public QtWayland::ClientBuffer
+{
+public:
+ ~LinuxDmabufClientBuffer() override;
+
+ QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const override;
+ QSize size() const override;
+ QWaylandSurface::Origin origin() const override;
+ QOpenGLTexture *toOpenGlTexture(int plane) override;
+
+protected:
+ void setDestroyed() override;
+
+private:
+ friend class LinuxDmabufClientBufferIntegration;
+ friend class LinuxDmabufClientBufferIntegrationPrivate;
+
+ LinuxDmabufClientBuffer(LinuxDmabufClientBufferIntegration* integration, wl_resource *bufferResource, LinuxDmabufWlBuffer *dmabufBuffer);
+
+ LinuxDmabufWlBuffer *d = nullptr;
+ LinuxDmabufClientBufferIntegration *m_integration = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // LINUXDMABUFCLIENTBUFFERINTEGRATION_H
diff --git a/src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h b/src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h
index b3f1cf3a9..73a66d3af 100644
--- a/src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h
+++ b/src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h
@@ -41,6 +41,9 @@
#define XCOMPOSITEBUFFER_H
#include <qwayland-server-wayland.h>
+
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
+
#include <QtWaylandCompositor/QWaylandSurface>
#include <QtWaylandCompositor/QWaylandCompositor>
@@ -68,7 +71,7 @@ public:
QSize size() const { return mSize; }
- static XCompositeBuffer *fromResource(struct ::wl_resource *resource) { return static_cast<XCompositeBuffer*>(Resource::fromResource(resource)->buffer_object); }
+ static XCompositeBuffer *fromResource(struct ::wl_resource *resource) { return QtWayland::fromResource<XCompositeBuffer *>(resource); }
protected:
void buffer_destroy_resource(Resource *) override;
diff --git a/src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h b/src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h
index bb43ed1af..28168994c 100644
--- a/src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h
+++ b/src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h
@@ -45,7 +45,7 @@
#include "xlibinclude.h"
#include "qwayland-server-xcomposite.h"
-#include <wayland-server.h>
+#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE