summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Olav Tvete <paul.tvete@qt.io>2019-01-21 10:06:49 +0100
committerPaul Olav Tvete <paul.tvete@qt.io>2019-08-13 11:56:10 +0200
commit43d8a3091894ceb4ab934167b2f3eda27564eb6d (patch)
tree67739f82b8ed86ad92fa7f3ee0005ce86edf8aaf
parent3d5cec736ce17c6b40c52bb8966f8fc40b742664 (diff)
Backport texture sharing for NVIDIA
This commit backports the Vulkan server buffer and texture sharing code from Qt 5.14 to Qt 5.12 as an opt-in feature. To enable, configure with "-feature-wayland-client-texture-sharing-experimental -feature-wayland-compositor-texture-sharing-experimental" Contains code from the following commits: Add server buffer integration based on Vulkan (commit df3a1761af2f20d59ae09a7adaa2f5b959047687) Compressed texture support for vulkan server buffers (commit f710489a341713c675cfd91d22ccd7bf8f29f4dd) Implement server-side toOpenGlTexture for Vulkan (commit 19361e7259f04b08925b1e8e99faf9460770ee7b) New texture sharing protocol and infrastructure (commit 80001cbf0451f4ba2a971fb20b80dc8e25ac604d) Change-Id: I6c36ef7fddcd4db39e80d03a822d89f15eae3434 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Johan Helsing <johan.helsing@qt.io>
-rw-r--r--config.tests/vulkan_server_buffer/main.cpp60
-rw-r--r--config.tests/vulkan_server_buffer/vulkan_server_buffer.pro1
-rw-r--r--src/client/configure.json17
-rw-r--r--src/client/hardwareintegration/qwaylandserverbufferintegration_p.h3
-rw-r--r--src/compositor/configure.json15
-rw-r--r--src/compositor/extensions/extensions.pri5
-rw-r--r--src/compositor/extensions/qwltexturesharingextension.cpp497
-rw-r--r--src/compositor/extensions/qwltexturesharingextension_p.h159
-rw-r--r--src/compositor/hardware_integration/qwlserverbufferintegration_p.h19
-rw-r--r--src/extensions/qt-texture-sharing-unstable-v1.xml57
-rw-r--r--src/extensions/qt-vulkan-server-buffer-unstable-v1.xml64
-rw-r--r--src/hardwareintegration/client/vulkan-server/vulkan-server.pri12
-rw-r--r--src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp216
-rw-r--r--src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.h102
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkan-server.pri16
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp325
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.h111
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp733
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.h70
-rw-r--r--src/imports/imports.pro7
-rw-r--r--src/imports/texture-sharing-extension/plugin.cpp109
-rw-r--r--src/imports/texture-sharing-extension/qmldir3
-rw-r--r--src/imports/texture-sharing-extension/texture-sharing-extension.pro13
-rw-r--r--src/imports/texture-sharing/plugin.cpp97
-rw-r--r--src/imports/texture-sharing/qmldir3
-rw-r--r--src/imports/texture-sharing/sharedtextureprovider.cpp322
-rw-r--r--src/imports/texture-sharing/sharedtextureprovider.h118
-rw-r--r--src/imports/texture-sharing/texture-sharing.pro23
-rw-r--r--src/imports/texture-sharing/texturesharingextension.cpp86
-rw-r--r--src/imports/texture-sharing/texturesharingextension.h77
-rw-r--r--src/plugins/hardwareintegration/client/client.pro2
-rw-r--r--src/plugins/hardwareintegration/client/vulkan-server/main.cpp66
-rw-r--r--src/plugins/hardwareintegration/client/vulkan-server/vulkan-server.json3
-rw-r--r--src/plugins/hardwareintegration/client/vulkan-server/vulkan-server.pro15
-rw-r--r--src/plugins/hardwareintegration/compositor/compositor.pro2
-rw-r--r--src/plugins/hardwareintegration/compositor/vulkan-server/main.cpp62
-rw-r--r--src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.json3
-rw-r--r--src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.pro12
-rw-r--r--src/src.pro2
-rw-r--r--sync.profile2
40 files changed, 3502 insertions, 7 deletions
diff --git a/config.tests/vulkan_server_buffer/main.cpp b/config.tests/vulkan_server_buffer/main.cpp
new file mode 100644
index 000000000..5bd88d338
--- /dev/null
+++ b/config.tests/vulkan_server_buffer/main.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Compositor.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <vulkan/vulkan.h>
+
+int main()
+{
+ VkExportMemoryAllocateInfoKHR exportAllocInfo = {};
+ exportAllocInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
+ exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+ return 0;
+}
diff --git a/config.tests/vulkan_server_buffer/vulkan_server_buffer.pro b/config.tests/vulkan_server_buffer/vulkan_server_buffer.pro
new file mode 100644
index 000000000..28dcadcbf
--- /dev/null
+++ b/config.tests/vulkan_server_buffer/vulkan_server_buffer.pro
@@ -0,0 +1 @@
+SOURCES += main.cpp
diff --git a/src/client/configure.json b/src/client/configure.json
index 586da6f66..06fa87757 100644
--- a/src/client/configure.json
+++ b/src/client/configure.json
@@ -75,6 +75,11 @@
"type": "compile",
"test": "dmabuf_server_buffer",
"use": "egl"
+ },
+ "vulkan-server-buffer": {
+ "label": "Vulkan Buffer Sharing",
+ "type": "compile",
+ "test": "vulkan_server_buffer"
}
},
@@ -123,6 +128,16 @@
"condition": "features.wayland-client && features.opengl && features.egl && tests.dmabuf-server-buffer",
"output": [ "privateFeature" ]
},
+ "wayland-client-texture-sharing-experimental" : {
+ "label": "Texture sharing (experimental)",
+ "autoDetect": "false",
+ "output": [ "privateFeature" ]
+ },
+ "wayland-vulkan-server-buffer": {
+ "label": "Vulkan-based server buffer integration",
+ "condition": "features.wayland-client && features.opengl && features.egl && tests.vulkan-server-buffer && features.wayland-client-texture-sharing-experimental",
+ "output": [ "privateFeature" ]
+ },
"wayland-shm-emulation-server-buffer": {
"label": "Shm emulation server buffer integration",
"condition": "features.wayland-client && features.opengl",
@@ -149,6 +164,8 @@
"xcomposite-glx",
"wayland-drm-egl-server-buffer",
"wayland-libhybris-egl-server-buffer",
+ "wayland-dmabuf-server-buffer",
+ "wayland-vulkan-server-buffer",
"wayland-shm-emulation-server-buffer"
]
},
diff --git a/src/client/hardwareintegration/qwaylandserverbufferintegration_p.h b/src/client/hardwareintegration/qwaylandserverbufferintegration_p.h
index 7439087d8..719dad9ed 100644
--- a/src/client/hardwareintegration/qwaylandserverbufferintegration_p.h
+++ b/src/client/hardwareintegration/qwaylandserverbufferintegration_p.h
@@ -70,7 +70,8 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandServerBuffer
public:
enum Format {
RGBA32,
- A8
+ A8,
+ Custom
};
QWaylandServerBuffer();
diff --git a/src/compositor/configure.json b/src/compositor/configure.json
index 9a6655241..0412d5e3b 100644
--- a/src/compositor/configure.json
+++ b/src/compositor/configure.json
@@ -80,6 +80,11 @@
"type": "compile",
"test": "dmabuf_server_buffer",
"use": "egl"
+ },
+ "vulkan-server-buffer": {
+ "label": "Vulkan Buffer Sharing",
+ "type": "compile",
+ "test": "vulkan_server_buffer"
}
},
@@ -128,6 +133,16 @@
"condition": "features.wayland-server && features.opengl && features.egl && tests.dmabuf-server-buffer",
"output": [ "privateFeature" ]
},
+ "wayland-compositor-texture-sharing-experimental" : {
+ "label": "Texture sharing (experimental)",
+ "autoDetect": "false",
+ "output": [ "privateFeature" ]
+ },
+ "wayland-vulkan-server-buffer": {
+ "label": "Vulkan-based server buffer integration",
+ "condition": "features.wayland-server && features.opengl && features.egl && tests.vulkan-server-buffer && features.wayland-compositor-texture-sharing-experimental",
+ "output": [ "privateFeature" ]
+ },
"wayland-shm-emulation-server-buffer": {
"label": "Shm emulation server buffer",
"condition": "features.wayland-server && features.opengl",
diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri
index 5c708f891..3ca575cac 100644
--- a/src/compositor/extensions/extensions.pri
+++ b/src/compositor/extensions/extensions.pri
@@ -75,6 +75,11 @@ qtHaveModule(quick):contains(QT_CONFIG, opengl) {
extensions/qwaylandxdgshellv6integration.cpp \
extensions/qwaylandxdgshellintegration.cpp
+ qtConfig(wayland-compositor-texture-sharing-experimental) {
+ HEADERS += extensions/qwltexturesharingextension_p.h
+ SOURCES += extensions/qwltexturesharingextension.cpp
+ WAYLANDSERVERSOURCES += ../extensions/qt-texture-sharing-unstable-v1.xml
+ }
}
include ($$PWD/pregenerated/xdg-shell-v5.pri)
diff --git a/src/compositor/extensions/qwltexturesharingextension.cpp b/src/compositor/extensions/qwltexturesharingextension.cpp
new file mode 100644
index 000000000..251c5fec0
--- /dev/null
+++ b/src/compositor/extensions/qwltexturesharingextension.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qwltexturesharingextension_p.h"
+
+#include <QWaylandSurface>
+
+#include <QDebug>
+
+#include <QQuickWindow>
+
+#include <QPainter>
+#include <QPen>
+#include <QTimer>
+
+#include <QtGui/private/qtexturefilereader_p.h>
+#include <QtGui/QOpenGLTexture>
+#include <QtGui/QImageReader>
+
+#include <QtQuick/QSGTexture>
+#include <QQmlContext>
+#include <QThread>
+
+QT_BEGIN_NAMESPACE
+
+class SharedTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ SharedTexture(QtWayland::ServerBuffer *buffer);
+
+ int textureId() const override;
+ QSize textureSize() const override;
+ bool hasAlphaChannel() const override;
+ bool hasMipmaps() const override;
+
+ void bind() override;
+
+private:
+ void updateGLTexture() const;
+ QtWayland::ServerBuffer *m_buffer = nullptr;
+ mutable QOpenGLTexture *m_tex = nullptr;
+};
+
+SharedTexture::SharedTexture(QtWayland::ServerBuffer *buffer)
+ : m_buffer(buffer), m_tex(nullptr)
+{
+}
+
+int SharedTexture::textureId() const
+{
+ updateGLTexture();
+ return m_tex ? m_tex->textureId() : 0;
+}
+
+QSize SharedTexture::textureSize() const
+{
+ updateGLTexture();
+ return m_tex ? QSize(m_tex->width(), m_tex->height()) : QSize();
+}
+
+bool SharedTexture::hasAlphaChannel() const
+{
+ return true;
+}
+
+bool SharedTexture::hasMipmaps() const
+{
+ updateGLTexture();
+ return m_tex ? (m_tex->mipLevels() > 1) : false;
+}
+
+void SharedTexture::bind()
+{
+ updateGLTexture();
+ if (m_tex)
+ m_tex->bind();
+}
+
+inline void SharedTexture::updateGLTexture() const
+{
+ if (!m_tex && m_buffer)
+ m_tex = m_buffer->toOpenGlTexture();
+}
+
+class SharedTextureFactory : public QQuickTextureFactory
+{
+public:
+ SharedTextureFactory(const QtWayland::ServerBuffer *buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ ~SharedTextureFactory() override
+ {
+ if (m_buffer && !QCoreApplication::closingDown())
+ const_cast<QtWayland::ServerBuffer*>(m_buffer)->releaseOpenGlTexture();
+ }
+
+ QSize textureSize() const override
+ {
+ return m_buffer ? m_buffer->size() : QSize();
+ }
+
+ int textureByteCount() const override
+ {
+ return m_buffer ? (m_buffer->size().width() * m_buffer->size().height() * 4) : 0;
+ }
+
+ QSGTexture *createTexture(QQuickWindow *) const override
+ {
+ return new SharedTexture(const_cast<QtWayland::ServerBuffer *>(m_buffer));
+ }
+
+private:
+ const QtWayland::ServerBuffer *m_buffer = nullptr;
+};
+
+class SharedTextureImageResponse : public QQuickImageResponse
+{
+ Q_OBJECT
+public:
+ SharedTextureImageResponse(QWaylandTextureSharingExtension *extension, const QString &id)
+ : m_id(id)
+ {
+ if (extension)
+ doRequest(extension);
+ }
+
+ void doRequest(QWaylandTextureSharingExtension *extension)
+ {
+ m_extension = extension;
+ connect(extension, &QWaylandTextureSharingExtension::bufferResult, this, &SharedTextureImageResponse::doResponse);
+ QMetaObject::invokeMethod(extension, [this] { m_extension->requestBuffer(m_id); }, Qt::AutoConnection);
+ }
+
+ QQuickTextureFactory *textureFactory() const override
+ {
+ if (m_buffer) {
+// qDebug() << "Creating shared buffer texture for" << m_id;
+ return new SharedTextureFactory(m_buffer);
+ }
+// qDebug() << "Shared buffer NOT found for" << m_id;
+ m_errorString = QLatin1Literal("Shared buffer not found");
+ return nullptr;
+ }
+
+ QString errorString() const override
+ {
+ return m_errorString;
+ }
+
+public slots:
+ void doResponse(const QString &key, QtWayland::ServerBuffer *buffer)
+ {
+ if (key != m_id)
+ return; //somebody else's texture
+
+ m_buffer = buffer;
+
+ if (m_extension)
+ disconnect(m_extension, &QWaylandTextureSharingExtension::bufferResult, this, &SharedTextureImageResponse::doResponse);
+
+ emit finished();
+ }
+
+private:
+ QString m_id;
+ QWaylandTextureSharingExtension *m_extension = nullptr;
+ mutable QString m_errorString;
+ QtWayland::ServerBuffer *m_buffer = nullptr;
+};
+
+QWaylandSharedTextureProvider::QWaylandSharedTextureProvider()
+{
+}
+
+QWaylandSharedTextureProvider::~QWaylandSharedTextureProvider()
+{
+}
+
+QQuickImageResponse *QWaylandSharedTextureProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
+{
+ Q_UNUSED(requestedSize);
+
+// qDebug() << "Provider: got request for" << id;
+
+ auto *extension = QWaylandTextureSharingExtension::self();
+ auto *response = new SharedTextureImageResponse(extension, id);
+ if (!extension)
+ m_pendingResponses << response;
+
+ return response;
+}
+
+void QWaylandSharedTextureProvider::setExtensionReady(QWaylandTextureSharingExtension *extension)
+{
+ for (auto *response : qAsConst(m_pendingResponses))
+ response->doRequest(extension);
+ m_pendingResponses.clear();
+ m_pendingResponses.squeeze();
+}
+
+QWaylandTextureSharingExtension *QWaylandTextureSharingExtension::s_self = nullptr; // theoretical race conditions, but OK as long as we don't delete it while we are running
+
+QWaylandTextureSharingExtension::QWaylandTextureSharingExtension()
+{
+ s_self = this;
+}
+
+QWaylandTextureSharingExtension::QWaylandTextureSharingExtension(QWaylandCompositor *compositor)
+ :QWaylandCompositorExtensionTemplate(compositor)
+{
+ s_self = this;
+}
+
+QWaylandTextureSharingExtension::~QWaylandTextureSharingExtension()
+{
+ //qDebug() << Q_FUNC_INFO;
+ //dumpBufferInfo();
+
+ for (auto b : m_server_buffers)
+ delete b.buffer;
+
+ if (s_self == this)
+ s_self = nullptr;
+}
+
+void QWaylandTextureSharingExtension::setImageSearchPath(const QString &path)
+{
+ m_image_dirs = path.split(QLatin1Char(';'));
+
+ for (auto it = m_image_dirs.begin(); it != m_image_dirs.end(); ++it)
+ if (!(*it).endsWith(QLatin1Char('/')))
+ (*it) += QLatin1Char('/');
+}
+
+void QWaylandTextureSharingExtension::initialize()
+{
+ QWaylandCompositorExtensionTemplate::initialize();
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ init(compositor->display(), 1);
+
+ QString image_search_path = qEnvironmentVariable("QT_WAYLAND_SHAREDTEXTURE_SEARCH_PATH");
+ if (!image_search_path.isEmpty())
+ setImageSearchPath(image_search_path);
+
+ if (m_image_dirs.isEmpty())
+ m_image_dirs << QLatin1Literal(":/") << QLatin1Literal("./");
+
+ auto suffixes = QTextureFileReader::supportedFileFormats();
+ suffixes.append(QImageReader::supportedImageFormats());
+ for (auto ext : qAsConst(suffixes))
+ m_image_suffixes << QLatin1Char('.') + QString::fromLatin1(ext);
+
+ //qDebug() << "m_image_suffixes" << m_image_suffixes << "m_image_dirs" << m_image_dirs;
+
+ auto *ctx = QQmlEngine::contextForObject(this);
+ if (ctx) {
+ QQmlEngine *engine = ctx->engine();
+ if (engine) {
+ auto *provider = static_cast<QWaylandSharedTextureProvider*>(engine->imageProvider(QLatin1Literal("wlshared")));
+ if (provider)
+ provider->setExtensionReady(this);
+ }
+ }
+}
+
+QString QWaylandTextureSharingExtension::getExistingFilePath(const QString &key) const
+{
+ // The default search path blocks absolute pathnames, but this does not prevent relative
+ // paths containing '../'. We handle that here, at the price of also blocking directory
+ // names ending with two or more dots.
+
+ if (key.contains(QLatin1Literal("../")))
+ return QString();
+
+ for (auto dir : m_image_dirs) {
+ QString path = dir + key;
+ if (QFileInfo::exists(path))
+ return path;
+ }
+
+ for (auto dir : m_image_dirs) {
+ for (auto ext : m_image_suffixes) {
+ QString fp = dir + key + ext;
+ //qDebug() << "trying" << fp;
+ if (QFileInfo::exists(fp))
+ return fp;
+ }
+ }
+ return QString();
+}
+
+QtWayland::ServerBuffer *QWaylandTextureSharingExtension::getBuffer(const QString &key)
+{
+ if (!initServerBufferIntegration())
+ return nullptr;
+
+//qDebug() << "getBuffer" << key;
+
+ QtWayland::ServerBuffer *buffer = nullptr;
+
+ if ((buffer = m_server_buffers.value(key).buffer))
+ return buffer;
+
+ QByteArray pixelData;
+ QSize size;
+ uint glInternalFormat = GL_NONE;
+
+ if (customPixelData(key, &pixelData, &size, &glInternalFormat)) {
+ if (!pixelData.isEmpty()) {
+ buffer = m_server_buffer_integration->createServerBufferFromData(pixelData, size, glInternalFormat);
+ if (!buffer)
+ qWarning() << "QWaylandTextureSharingExtension: could not create buffer from custom data for key:" << key;
+ }
+ } else {
+ QString pathName = getExistingFilePath(key);
+ //qDebug() << "pathName" << pathName;
+ if (pathName.isEmpty())
+ return nullptr;
+
+ buffer = getCompressedBuffer(pathName);
+ //qDebug() << "getCompressedBuffer" << buffer;
+
+ if (!buffer) {
+ QImage img(pathName);
+ if (!img.isNull()) {
+ img = img.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
+ buffer = m_server_buffer_integration->createServerBufferFromImage(img, QtWayland::ServerBuffer::RGBA32);
+ }
+ //qDebug() << "createServerBufferFromImage" << buffer;
+ }
+ }
+ if (buffer)
+ m_server_buffers.insert(key, BufferInfo(buffer));
+
+ //qDebug() << ">>>>" << key << buffer;
+
+ return buffer;
+}
+
+// Compositor requesting image for its own UI
+void QWaylandTextureSharingExtension::requestBuffer(const QString &key)
+{
+ //qDebug() << "requestBuffer" << key;
+
+ if (thread() != QThread::currentThread())
+ qWarning("QWaylandTextureSharingExtension::requestBuffer() called from outside main thread: possible race condition");
+
+ auto *buffer = getBuffer(key);
+
+ if (buffer)
+ m_server_buffers[key].usedLocally = true;
+
+ //dumpBufferInfo();
+
+ emit bufferResult(key, buffer);
+}
+
+void QWaylandTextureSharingExtension::zqt_texture_sharing_v1_request_image(Resource *resource, const QString &key)
+{
+ //qDebug() << "texture_sharing_request_image" << key;
+ auto *buffer = getBuffer(key);
+ if (buffer) {
+ struct ::wl_client *client = resource->client();
+ struct ::wl_resource *buffer_resource = buffer->resourceForClient(client);
+ //qDebug() << " server_buffer resource" << buffer_resource;
+ if (buffer_resource)
+ send_provide_buffer(resource->handle, buffer_resource, key);
+ else
+ qWarning() << "QWaylandTextureSharingExtension: no buffer resource for client";
+ } else {
+ send_image_failed(resource->handle, key, QString());
+ }
+ //dumpBufferInfo();
+}
+
+void QWaylandTextureSharingExtension::zqt_texture_sharing_v1_abandon_image(Resource *resource, const QString &key)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(key);
+// qDebug() << Q_FUNC_INFO << resource << key;
+ QTimer::singleShot(100, this, &QWaylandTextureSharingExtension::cleanupBuffers);
+}
+
+// A client has disconnected
+void QWaylandTextureSharingExtension::zqt_texture_sharing_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+// qDebug() << "texture_sharing_destroy_resource" << resource->handle << resource->handle->object.id << "client" << resource->client();
+// dumpBufferInfo();
+ QTimer::singleShot(1000, this, &QWaylandTextureSharingExtension::cleanupBuffers);
+}
+
+bool QWaylandTextureSharingExtension::initServerBufferIntegration()
+{
+ if (!m_server_buffer_integration) {
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+
+ m_server_buffer_integration = QWaylandCompositorPrivate::get(compositor)->serverBufferIntegration();
+ if (!m_server_buffer_integration) {
+ qWarning("QWaylandTextureSharingExtension initialization failed: No Server Buffer Integration");
+ if (qEnvironmentVariableIsEmpty("QT_WAYLAND_SERVER_BUFFER_INTEGRATION"))
+ qWarning("Set the environment variable 'QT_WAYLAND_SERVER_BUFFER_INTEGRATION' to specify.");
+ return false;
+ }
+ }
+ return true;
+}
+
+QtWayland::ServerBuffer *QWaylandTextureSharingExtension::getCompressedBuffer(const QString &pathName)
+{
+ QFile f(pathName);
+ if (!f.open(QIODevice::ReadOnly))
+ return nullptr;
+
+ QTextureFileReader r(&f, pathName);
+
+ if (!r.canRead())
+ return nullptr;
+
+ QTextureFileData td(r.read());
+
+ //qDebug() << "QWaylandTextureSharingExtension: reading compressed texture data" << td;
+
+ if (!td.isValid()) {
+ qWarning() << "VulkanServerBufferIntegration:" << pathName << "not valid compressed texture";
+ return nullptr;
+ }
+
+ QByteArray pixelData = QByteArray::fromRawData(td.data().constData() + td.dataOffset(), td.dataLength());
+
+ return m_server_buffer_integration->createServerBufferFromData(pixelData, td.size(), td.glInternalFormat());
+}
+
+void QWaylandTextureSharingExtension::cleanupBuffers()
+{
+ for (auto it = m_server_buffers.begin(); it != m_server_buffers.end(); ) {
+ auto *buffer = it.value().buffer;
+ if (!it.value().usedLocally && !buffer->bufferInUse()) {
+ //qDebug() << "deleting buffer for" << it.key();
+ it = m_server_buffers.erase(it);
+ delete buffer;
+ } else {
+ ++it;
+ }
+ }
+ //dumpBufferInfo();
+}
+
+void QWaylandTextureSharingExtension::dumpBufferInfo()
+{
+ qDebug() << "shared buffers:" << m_server_buffers.count();
+ for (auto it = m_server_buffers.cbegin(); it != m_server_buffers.cend(); ++it)
+ qDebug() << " " << it.key() << ":" << it.value().buffer << "in use" << it.value().buffer->bufferInUse() << "usedLocally" << it.value().usedLocally ;
+}
+
+QT_END_NAMESPACE
+
+#include "qwltexturesharingextension.moc"
diff --git a/src/compositor/extensions/qwltexturesharingextension_p.h b/src/compositor/extensions/qwltexturesharingextension_p.h
new file mode 100644
index 000000000..8f442a200
--- /dev/null
+++ b/src/compositor/extensions/qwltexturesharingextension_p.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QWLTEXTURESHARINGEXTENSION_P_H
+#define QWLTEXTURESHARINGEXTENSION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "wayland-util.h"
+
+#include <QtCore/QMap>
+#include <QtCore/QHash>
+
+#include <QtWaylandCompositor/QWaylandCompositorExtensionTemplate>
+#include <QtWaylandCompositor/QWaylandQuickExtension>
+#include <QtWaylandCompositor/QWaylandCompositor>
+
+#include <QQuickImageProvider>
+
+#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
+#include <QtWaylandCompositor/private/qwlserverbufferintegration_p.h>
+
+#include <QtWaylandCompositor/private/qwayland-server-qt-texture-sharing-unstable-v1.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWayland
+{
+ class ServerBufferIntegration;
+}
+
+class QWaylandTextureSharingExtension;
+class SharedTextureImageResponse;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandSharedTextureProvider : public QQuickAsyncImageProvider
+{
+public:
+ QWaylandSharedTextureProvider();
+ ~QWaylandSharedTextureProvider() override;
+
+ QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
+ void setExtensionReady(QWaylandTextureSharingExtension *extension);
+
+private:
+ QVector<SharedTextureImageResponse*> m_pendingResponses;
+};
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandTextureSharingExtension
+ : public QWaylandCompositorExtensionTemplate<QWaylandTextureSharingExtension>
+ , public QtWaylandServer::zqt_texture_sharing_v1
+{
+ Q_OBJECT
+ Q_PROPERTY(QString imageSearchPath WRITE setImageSearchPath)
+public:
+ QWaylandTextureSharingExtension();
+ QWaylandTextureSharingExtension(QWaylandCompositor *compositor);
+ ~QWaylandTextureSharingExtension() override;
+
+ void initialize() override;
+
+ void setImageSearchPath(const QString &path);
+
+ static QWaylandTextureSharingExtension *self() { return s_self; }
+
+public slots:
+ void requestBuffer(const QString &key);
+
+signals:
+ void bufferResult(const QString &key, QtWayland::ServerBuffer *buffer);
+
+protected slots:
+ void cleanupBuffers();
+
+protected:
+ void zqt_texture_sharing_v1_request_image(Resource *resource, const QString &key) override;
+ void zqt_texture_sharing_v1_abandon_image(Resource *resource, const QString &key) override;
+ void zqt_texture_sharing_v1_destroy_resource(Resource *resource) override;
+
+ virtual bool customPixelData(const QString &key, QByteArray *data, QSize *size, uint *glInternalFormat)
+ {
+ Q_UNUSED(key);
+ Q_UNUSED(data);
+ Q_UNUSED(size);
+ Q_UNUSED(glInternalFormat);
+ return false;
+ }
+
+private:
+ QtWayland::ServerBuffer *getBuffer(const QString &key);
+ bool initServerBufferIntegration();
+ QtWayland::ServerBuffer *getCompressedBuffer(const QString &key);
+ QString getExistingFilePath(const QString &key) const;
+ void dumpBufferInfo();
+
+ struct BufferInfo
+ {
+ BufferInfo(QtWayland::ServerBuffer *b = nullptr) : buffer(b) {}
+ QtWayland::ServerBuffer *buffer = nullptr;
+ bool usedLocally = false;
+ };
+
+ QStringList m_image_dirs;
+ QStringList m_image_suffixes;
+ QHash<QString, BufferInfo> m_server_buffers;
+ QtWayland::ServerBufferIntegration *m_server_buffer_integration = nullptr;
+
+ static QWaylandTextureSharingExtension *s_self;
+};
+
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandTextureSharingExtension)
+
+QT_END_NAMESPACE
+
+#endif // QWLTEXTURESHARINGEXTENSION_P_H
diff --git a/src/compositor/hardware_integration/qwlserverbufferintegration_p.h b/src/compositor/hardware_integration/qwlserverbufferintegration_p.h
index 7d8901d58..b8d9fa99d 100644
--- a/src/compositor/hardware_integration/qwlserverbufferintegration_p.h
+++ b/src/compositor/hardware_integration/qwlserverbufferintegration_p.h
@@ -55,8 +55,7 @@
#include <QtCore/QSize>
#include <QtGui/qopengl.h>
-#include <QtWaylandCompositor/qtwaylandcompositorglobal.h>
-
+#include <QtWaylandCompositor/private/qtwaylandcompositorglobal_p.h>
struct wl_client;
struct wl_resource;
@@ -75,7 +74,8 @@ class Q_WAYLAND_COMPOSITOR_EXPORT ServerBuffer
public:
enum Format {
RGBA32,
- A8
+ A8,
+ Custom
};
ServerBuffer(const QSize &size, ServerBuffer::Format format);
@@ -85,7 +85,9 @@ public:
virtual bool bufferInUse() { return true; }
virtual QOpenGLTexture *toOpenGlTexture() = 0;
-
+#if QT_CONFIG(wayland_compositor_texture_sharing_experimental)
+ virtual void releaseOpenGlTexture() {}
+#endif
virtual bool isYInverted() const;
QSize size() const;
@@ -105,6 +107,15 @@ public:
virtual bool supportsFormat(ServerBuffer::Format format) const = 0;
virtual ServerBuffer *createServerBufferFromImage(const QImage &qimage, ServerBuffer::Format format) = 0;
+#if QT_CONFIG(wayland_compositor_texture_sharing_experimental)
+ virtual ServerBuffer *createServerBufferFromData(const QByteArray &data, const QSize &size, uint glInternalFormat)
+ {
+ Q_UNUSED(data);
+ Q_UNUSED(size);
+ Q_UNUSED(glInternalFormat);
+ return nullptr;
+ }
+#endif
};
}
diff --git a/src/extensions/qt-texture-sharing-unstable-v1.xml b/src/extensions/qt-texture-sharing-unstable-v1.xml
new file mode 100644
index 000000000..262ae487c
--- /dev/null
+++ b/src/extensions/qt-texture-sharing-unstable-v1.xml
@@ -0,0 +1,57 @@
+<protocol name="qt_texture_sharing_unstable_v1">
+
+ <copyright>
+ Copyright (C) 2019 The Qt Company Ltd.
+ Contact: http://www.qt.io/licensing/
+
+ This file is part of the plugins of the Qt Toolkit.
+
+ $QT_BEGIN_LICENSE:BSD$
+ You may use this file under the terms of the BSD license as follows:
+
+ "Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of The Qt Company Ltd nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+
+ $QT_END_LICENSE$
+ </copyright>
+
+ <interface name="zqt_texture_sharing_v1" version="1">
+ <request name="request_image">
+ <arg name="key" type="string"/>
+ </request>
+ <request name="abandon_image">
+ <arg name="key" type="string"/>
+ </request>
+ <event name="image_failed">
+ <arg name="key" type="string"/>
+ <arg name="error_message" type="string"/>
+ </event>
+ <event name="provide_buffer">
+ <arg name="buffer" type="object" interface="qt_server_buffer"/>
+ <arg name="key" type="string"/>
+ </event>
+ </interface>
+</protocol>
diff --git a/src/extensions/qt-vulkan-server-buffer-unstable-v1.xml b/src/extensions/qt-vulkan-server-buffer-unstable-v1.xml
new file mode 100644
index 000000000..211d0a7c7
--- /dev/null
+++ b/src/extensions/qt-vulkan-server-buffer-unstable-v1.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="qt_vulkan_server_buffer_unstable_v1">
+ <copyright>
+ Copyright (C) 2019 The Qt Company Ltd.
+ Contact: http://www.qt.io/licensing/
+
+ This file is part of the plugins of the Qt Toolkit.
+
+ $QT_BEGIN_LICENSE:BSD$
+ You may use this file under the terms of the BSD license as follows:
+
+ "Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of The Qt Company Ltd nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+
+ $QT_END_LICENSE$
+ </copyright>
+ <interface name="zqt_vulkan_server_buffer_v1" version="1">
+ <description summary="Internal protocol for buffer sharing using Vulkan external memory">
+ This protocol is used internally by Qt for implementing the
+ qt_server_buffer extension on hardware that supports Vulkan external memory .
+
+ This protocol is not part of the Qt API. It exists purely as an
+ implementation detail and may change from version to
+ version without notice, or even be removed.
+ </description>
+ <event name="server_buffer_created">
+ <description summary="vulkan buffer information">
+ Informs the client about a newly created server buffer.
+ The "fd" argument is a POSIX file descriptor representing the
+ underlying resources of a Vulkan device memory object as defined
+ in the GL_EXT_memory_object_fd extension.
+ </description>
+ <arg name="id" type="new_id" interface="qt_server_buffer"/>
+ <arg name="fd" type="fd" summary="GL_EXT_memory_object_fd"/>
+ <arg name="width" type="uint"/>
+ <arg name="height" type="uint"/>
+ <arg name="memory_size" type="uint" summary="size in bytes"/>
+ <arg name="format" type="uint" summary="GL internal format"/>
+ </event>
+ </interface>
+</protocol>
diff --git a/src/hardwareintegration/client/vulkan-server/vulkan-server.pri b/src/hardwareintegration/client/vulkan-server/vulkan-server.pri
new file mode 100644
index 000000000..2e13a87b7
--- /dev/null
+++ b/src/hardwareintegration/client/vulkan-server/vulkan-server.pri
@@ -0,0 +1,12 @@
+INCLUDEPATH += $$PWD
+
+QMAKE_USE += wayland-client
+
+SOURCES += \
+ $$PWD/vulkanserverbufferintegration.cpp
+
+HEADERS += \
+ $$PWD/vulkanserverbufferintegration.h
+
+CONFIG += wayland-scanner
+WAYLANDCLIENTSOURCES += $$PWD/../../../extensions/qt-vulkan-server-buffer-unstable-v1.xml
diff --git a/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp
new file mode 100644
index 000000000..7e1d5966f
--- /dev/null
+++ b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+#define GL_GLEXT_PROTOTYPES
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "vulkanserverbufferintegration.h"
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QDebug>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLTexture>
+#include <QtGui/QImage>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+static constexpr bool extraDebug =
+#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
+ true;
+#else
+ false;
+#endif
+
+#define DECL_GL_FUNCTION(name, type) \
+ type name
+
+#define FIND_GL_FUNCTION(name, type) \
+ do { \
+ name = reinterpret_cast<type>(glContext->getProcAddress(#name)); \
+ if (!name) { \
+ qWarning() << "ERROR in GL proc lookup. Could not find " #name; \
+ return false; \
+ } \
+ } while (0)
+
+struct VulkanServerBufferGlFunctions
+{
+ DECL_GL_FUNCTION(glCreateMemoryObjectsEXT, PFNGLCREATEMEMORYOBJECTSEXTPROC);
+ DECL_GL_FUNCTION(glImportMemoryFdEXT, PFNGLIMPORTMEMORYFDEXTPROC);
+ DECL_GL_FUNCTION(glTextureStorageMem2DEXT, PFNGLTEXTURESTORAGEMEM2DEXTPROC);
+ DECL_GL_FUNCTION(glTexStorageMem2DEXT, PFNGLTEXSTORAGEMEM2DEXTPROC);
+ DECL_GL_FUNCTION(glDeleteMemoryObjectsEXT, PFNGLDELETEMEMORYOBJECTSEXTPROC);
+
+ bool init(QOpenGLContext *glContext)
+ {
+ FIND_GL_FUNCTION(glCreateMemoryObjectsEXT, PFNGLCREATEMEMORYOBJECTSEXTPROC);
+ FIND_GL_FUNCTION(glImportMemoryFdEXT, PFNGLIMPORTMEMORYFDEXTPROC);
+ FIND_GL_FUNCTION(glTextureStorageMem2DEXT, PFNGLTEXTURESTORAGEMEM2DEXTPROC);
+ FIND_GL_FUNCTION(glTexStorageMem2DEXT, PFNGLTEXSTORAGEMEM2DEXTPROC);
+ FIND_GL_FUNCTION(glDeleteMemoryObjectsEXT, PFNGLDELETEMEMORYOBJECTSEXTPROC);
+
+ return true;
+ }
+ static bool create(QOpenGLContext *glContext);
+};
+
+static VulkanServerBufferGlFunctions *funcs = nullptr;
+
+bool VulkanServerBufferGlFunctions::create(QOpenGLContext *glContext)
+{
+ if (funcs)
+ return true;
+ funcs = new VulkanServerBufferGlFunctions;
+ if (!funcs->init(glContext)) {
+ delete funcs;
+ funcs = nullptr;
+ return false;
+ }
+ return true;
+}
+
+VulkanServerBuffer::VulkanServerBuffer(VulkanServerBufferIntegration *integration, struct ::qt_server_buffer *id,
+ int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format)
+ : m_integration(integration)
+ , m_server_buffer(id)
+ , m_fd(fd)
+ , m_memorySize(memory_size)
+ , m_internalFormat(format)
+{
+ m_size = QSize(width, height);
+}
+
+VulkanServerBuffer::~VulkanServerBuffer()
+{
+ if (QCoreApplication::closingDown())
+ return; // can't trust anything at this point
+
+ if (m_texture) { //only do gl cleanup if import has been called
+ m_integration->deleteGLTextureWhenPossible(m_texture);
+
+ if (extraDebug) qDebug() << "glDeleteMemoryObjectsEXT" << m_memoryObject;
+ funcs->glDeleteMemoryObjectsEXT(1, &m_memoryObject);
+ }
+ qt_server_buffer_release(m_server_buffer);
+ qt_server_buffer_destroy(m_server_buffer);
+}
+
+void VulkanServerBuffer::import()
+{
+ if (m_texture)
+ return;
+
+ if (extraDebug) qDebug() << "importing" << m_fd << hex << glGetError();
+
+ auto *glContext = QOpenGLContext::currentContext();
+ if (!glContext)
+ return;
+
+ if (!funcs && !VulkanServerBufferGlFunctions::create(glContext))
+ return;
+
+ funcs->glCreateMemoryObjectsEXT(1, &m_memoryObject);
+ if (extraDebug) qDebug() << "glCreateMemoryObjectsEXT" << hex << glGetError();
+ funcs->glImportMemoryFdEXT(m_memoryObject, m_memorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, m_fd);
+ if (extraDebug) qDebug() << "glImportMemoryFdEXT" << hex << glGetError();
+
+
+ m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ m_texture->create();
+
+ if (extraDebug) qDebug() << "created texture" << m_texture->textureId() << hex << glGetError();
+
+ m_texture->bind();
+ if (extraDebug) qDebug() << "bound texture" << hex << glGetError();
+ funcs->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, m_internalFormat, m_size.width(), m_size.height(), m_memoryObject, 0 );
+ if (extraDebug) qDebug() << "glTexStorageMem2DEXT" << hex << glGetError();
+ if (extraDebug) qDebug() << "format" << hex << m_internalFormat << GL_RGBA8;
+}
+
+QOpenGLTexture *VulkanServerBuffer::toOpenGlTexture()
+{
+ m_integration->deleteOrphanedTextures();
+ if (!m_texture)
+ import();
+ return m_texture;
+}
+
+void VulkanServerBufferIntegration::initialize(QWaylandDisplay *display)
+{
+ m_display = display;
+ display->addRegistryListener(&wlDisplayHandleGlobal, this);
+}
+
+QWaylandServerBuffer *VulkanServerBufferIntegration::serverBuffer(struct qt_server_buffer *buffer)
+{
+ return static_cast<QWaylandServerBuffer *>(qt_server_buffer_get_user_data(buffer));
+}
+
+void VulkanServerBufferIntegration::wlDisplayHandleGlobal(void *data, ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
+{
+ Q_UNUSED(version);
+ if (interface == "zqt_vulkan_server_buffer_v1") {
+ auto *integration = static_cast<VulkanServerBufferIntegration *>(data);
+ integration->QtWayland::zqt_vulkan_server_buffer_v1::init(registry, id, 1);
+ }
+}
+
+void VulkanServerBufferIntegration::zqt_vulkan_server_buffer_v1_server_buffer_created(qt_server_buffer *id, int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format)
+{
+ if (extraDebug) qDebug() << "vulkan_server_buffer_server_buffer_created" << fd;
+ auto *server_buffer = new VulkanServerBuffer(this, id, fd, width, height, memory_size, format);
+ qt_server_buffer_set_user_data(id, server_buffer);
+}
+
+void VulkanServerBufferIntegration::deleteOrphanedTextures()
+{
+ if (!QOpenGLContext::currentContext()) {
+ qWarning("VulkanServerBufferIntegration::deleteOrphanedTextures with no current context!");
+ return;
+ }
+ qDeleteAll(orphanedTextures);
+ orphanedTextures.clear();
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.h b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.h
new file mode 100644
index 000000000..7add74269
--- /dev/null
+++ b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 VULKANSERVERBUFFERINTEGRATION_H
+#define VULKANSERVERBUFFERINTEGRATION_H
+
+#include <QtWaylandClient/private/qwayland-wayland.h>
+#include "qwayland-qt-vulkan-server-buffer-unstable-v1.h"
+#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
+
+#include "vulkanserverbufferintegration.h"
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtCore/QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class VulkanServerBufferIntegration;
+
+class VulkanServerBuffer : public QWaylandServerBuffer
+{
+public:
+ VulkanServerBuffer(VulkanServerBufferIntegration *integration, struct ::qt_server_buffer *id, int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format);
+ ~VulkanServerBuffer() override;
+ QOpenGLTexture* toOpenGlTexture() override;
+
+private:
+ void import();
+
+ VulkanServerBufferIntegration *m_integration = nullptr;
+ struct ::qt_server_buffer *m_server_buffer = nullptr;
+ QOpenGLTexture *m_texture = nullptr;
+ int m_fd = -1;
+ uint m_memorySize = 0;
+ uint m_internalFormat = 0;
+ GLuint m_memoryObject = 0;
+};
+
+class VulkanServerBufferIntegration
+ : public QWaylandServerBufferIntegration
+ , public QtWayland::zqt_vulkan_server_buffer_v1
+{
+public:
+ void initialize(QWaylandDisplay *display) override;
+
+ QWaylandServerBuffer *serverBuffer(struct qt_server_buffer *buffer) override;
+
+ void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { orphanedTextures << texture; }
+ void deleteOrphanedTextures();
+
+protected:
+ void zqt_vulkan_server_buffer_v1_server_buffer_created(qt_server_buffer *id, int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format) override;
+
+private:
+ static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id,
+ const QString &interface, uint32_t version);
+ QWaylandDisplay *m_display = nullptr;
+ QVector<QOpenGLTexture *> orphanedTextures;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkan-server.pri b/src/hardwareintegration/compositor/vulkan-server/vulkan-server.pri
new file mode 100644
index 000000000..63a96ad0f
--- /dev/null
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkan-server.pri
@@ -0,0 +1,16 @@
+INCLUDEPATH += $$PWD $$PWD/../../../3rdparty/util
+
+QT += vulkan_support-private
+
+QMAKE_USE_PRIVATE += wayland-server
+
+SOURCES += \
+ $$PWD/vulkanserverbufferintegration.cpp \
+ $$PWD/vulkanwrapper.cpp
+
+HEADERS += \
+ $$PWD/vulkanserverbufferintegration.h \
+ $$PWD/vulkanwrapper.h
+
+CONFIG += wayland-scanner
+WAYLANDSERVERSOURCES += $$PWD/../../../extensions/qt-vulkan-server-buffer-unstable-v1.xml
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp
new file mode 100644
index 000000000..7f9f8a151
--- /dev/null
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp
@@ -0,0 +1,325 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+#define GL_GLEXT_PROTOTYPES
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "vulkanserverbufferintegration.h"
+
+#include "vulkanwrapper.h"
+
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLTexture>
+#include <QtGui/QOffscreenSurface>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+static constexpr bool extraDebug = false;
+
+#define DECL_GL_FUNCTION(name, type) \
+ type name
+
+#define FIND_GL_FUNCTION(name, type) \
+ do { \
+ name = reinterpret_cast<type>(glContext->getProcAddress(#name)); \
+ if (!name) { \
+ qWarning() << "ERROR in GL proc lookup. Could not find " #name; \
+ return false; \
+ } \
+ } while (0)
+
+struct VulkanServerBufferGlFunctions
+{
+ DECL_GL_FUNCTION(glCreateMemoryObjectsEXT, PFNGLCREATEMEMORYOBJECTSEXTPROC);
+ DECL_GL_FUNCTION(glImportMemoryFdEXT, PFNGLIMPORTMEMORYFDEXTPROC);
+ //DECL_GL_FUNCTION(glTextureStorageMem2DEXT, PFNGLTEXTURESTORAGEMEM2DEXTPROC);
+ DECL_GL_FUNCTION(glTexStorageMem2DEXT, PFNGLTEXSTORAGEMEM2DEXTPROC);
+ DECL_GL_FUNCTION(glDeleteMemoryObjectsEXT, PFNGLDELETEMEMORYOBJECTSEXTPROC);
+
+ bool init(QOpenGLContext *glContext)
+ {
+ FIND_GL_FUNCTION(glCreateMemoryObjectsEXT, PFNGLCREATEMEMORYOBJECTSEXTPROC);
+ FIND_GL_FUNCTION(glImportMemoryFdEXT, PFNGLIMPORTMEMORYFDEXTPROC);
+ //FIND_GL_FUNCTION(glTextureStorageMem2DEXT, PFNGLTEXTURESTORAGEMEM2DEXTPROC);
+ FIND_GL_FUNCTION(glTexStorageMem2DEXT, PFNGLTEXSTORAGEMEM2DEXTPROC);
+ FIND_GL_FUNCTION(glDeleteMemoryObjectsEXT, PFNGLDELETEMEMORYOBJECTSEXTPROC);
+
+ return true;
+ }
+ static bool create(QOpenGLContext *glContext);
+};
+
+static VulkanServerBufferGlFunctions *funcs = nullptr;
+
+//RAII
+class CurrentContext
+{
+public:
+ CurrentContext()
+ {
+ if (!QOpenGLContext::currentContext()) {
+ if (QOpenGLContext::globalShareContext()) {
+ if (!localContext) {
+ localContext = new QOpenGLContext;
+ localContext->setShareContext(QOpenGLContext::globalShareContext());
+ localContext->create();
+ }
+ if (!offscreenSurface) {
+ offscreenSurface = new QOffscreenSurface;
+ offscreenSurface->setFormat(localContext->format());
+ offscreenSurface->create();
+ }
+ localContext->makeCurrent(offscreenSurface);
+ localContextInUse = true;
+ } else {
+ qCritical("VulkanServerBufferIntegration: no globalShareContext");
+ }
+ }
+ }
+ ~CurrentContext()
+ {
+ if (localContextInUse)
+ localContext->doneCurrent();
+ }
+ QOpenGLContext *context() { return localContextInUse ? localContext : QOpenGLContext::currentContext(); }
+private:
+ static QOpenGLContext *localContext;
+ static QOffscreenSurface *offscreenSurface;
+ bool localContextInUse = false;
+};
+
+QOpenGLContext *CurrentContext::localContext = nullptr;
+QOffscreenSurface *CurrentContext::offscreenSurface = nullptr;
+
+bool VulkanServerBufferGlFunctions::create(QOpenGLContext *glContext)
+{
+ if (funcs)
+ return true;
+ funcs = new VulkanServerBufferGlFunctions;
+ if (!funcs->init(glContext)) {
+ delete funcs;
+ funcs = nullptr;
+ return false;
+ }
+ return true;
+}
+
+VulkanServerBuffer::VulkanServerBuffer(VulkanServerBufferIntegration *integration, const QImage &qimage, QtWayland::ServerBuffer::Format format)
+ : QtWayland::ServerBuffer(qimage.size(),format)
+ , m_integration(integration)
+ , m_width(qimage.width())
+ , m_height(qimage.height())
+{
+ m_format = format;
+ switch (m_format) {
+ case RGBA32:
+ m_glInternalFormat = GL_RGBA8;
+ break;
+ // case A8:
+ // m_glInternalFormat = GL_R8;
+ // break;
+ default:
+ qWarning("VulkanServerBuffer: unsupported format");
+ m_glInternalFormat = GL_RGBA8;
+ break;
+ }
+
+ auto vulkanWrapper = m_integration->vulkanWrapper();
+ m_vImage = vulkanWrapper->createTextureImage(qimage);
+ if (m_vImage)
+ m_fd = vulkanWrapper->getImageInfo(m_vImage, &m_memorySize);
+}
+
+VulkanServerBuffer::VulkanServerBuffer(VulkanServerBufferIntegration *integration, VulkanImageWrapper *vImage, uint glInternalFormat, const QSize &size)
+ : QtWayland::ServerBuffer(size, QtWayland::ServerBuffer::Custom)
+ , m_integration(integration)
+ , m_width(size.width())
+ , m_height(size.height())
+ , m_vImage(vImage)
+ , m_glInternalFormat(glInternalFormat)
+{
+ auto vulkanWrapper = m_integration->vulkanWrapper();
+ m_fd = vulkanWrapper->getImageInfo(m_vImage, &m_memorySize);
+}
+
+VulkanServerBuffer::~VulkanServerBuffer()
+{
+ delete m_texture; //this is always nullptr for now
+ auto vulkanWrapper = m_integration->vulkanWrapper();
+ vulkanWrapper->freeTextureImage(m_vImage);
+}
+
+struct ::wl_resource *VulkanServerBuffer::resourceForClient(struct ::wl_client *client)
+{
+ auto *bufferResource = resourceMap().value(client);
+ if (!bufferResource) {
+ auto integrationResource = m_integration->resourceMap().value(client);
+ if (!integrationResource) {
+ qWarning("VulkanServerBuffer::resourceForClient: Trying to get resource for ServerBuffer. But client is not bound to the vulkan interface");
+ return nullptr;
+ }
+ struct ::wl_resource *shm_integration_resource = integrationResource->handle;
+ Resource *resource = add(client, 1);
+ m_integration->send_server_buffer_created(shm_integration_resource, resource->handle, m_fd, m_width, m_height, m_memorySize, m_glInternalFormat);
+ return resource->handle;
+ }
+ return bufferResource->handle;
+}
+
+QOpenGLTexture *VulkanServerBuffer::toOpenGlTexture()
+{
+ if (m_texture && m_texture->isCreated())
+ return m_texture;
+
+ CurrentContext current;
+
+ if (!funcs && !VulkanServerBufferGlFunctions::create(current.context()))
+ return nullptr;
+
+ funcs->glCreateMemoryObjectsEXT(1, &m_memoryObject);
+ if (extraDebug) qDebug() << "glCreateMemoryObjectsEXT" << hex << glGetError();
+
+
+ int dupfd = fcntl(m_fd, F_DUPFD_CLOEXEC, 0);
+ if (dupfd < 0) {
+ perror("VulkanServerBuffer::toOpenGlTexture() Could not dup fd:");
+ return nullptr;
+ }
+
+ funcs->glImportMemoryFdEXT(m_memoryObject, m_memorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, dupfd);
+ if (extraDebug) qDebug() << "glImportMemoryFdEXT" << hex << glGetError();
+
+
+ if (!m_texture)
+ m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ m_texture->create();
+
+ GLuint texId = m_texture->textureId();
+ if (extraDebug) qDebug() << "created texture" << texId << hex << glGetError();
+
+ m_texture->bind();
+ if (extraDebug) qDebug() << "bound texture" << texId << hex << glGetError();
+ funcs->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, m_glInternalFormat, m_size.width(), m_size.height(), m_memoryObject, 0 );
+ if (extraDebug) qDebug() << "glTexStorageMem2DEXT" << hex << glGetError();
+ if (extraDebug) qDebug() << "format" << hex << m_glInternalFormat << GL_RGBA8;
+
+
+ return m_texture;
+}
+
+void VulkanServerBuffer::releaseOpenGlTexture()
+{
+ if (!m_texture || !m_texture->isCreated())
+ return;
+
+ CurrentContext current;
+ m_texture->destroy();
+ funcs->glDeleteMemoryObjectsEXT(1, &m_memoryObject);
+}
+
+
+bool VulkanServerBuffer::bufferInUse()
+{
+ return (m_texture && m_texture->isCreated()) || resourceMap().count() > 0;
+}
+
+void VulkanServerBuffer::server_buffer_release(Resource *resource)
+{
+ qCDebug(qLcWaylandCompositorHardwareIntegration) << "server_buffer RELEASE resource" << resource->handle << wl_resource_get_id(resource->handle) << "for client" << resource->client();
+ wl_resource_destroy(resource->handle);
+}
+
+VulkanServerBufferIntegration::VulkanServerBufferIntegration()
+{
+}
+
+VulkanServerBufferIntegration::~VulkanServerBufferIntegration()
+{
+}
+
+void VulkanServerBufferIntegration::initializeHardware(QWaylandCompositor *compositor)
+{
+ Q_ASSERT(QGuiApplication::platformNativeInterface());
+
+ QtWaylandServer::zqt_vulkan_server_buffer_v1::init(compositor->display(), 1);
+}
+
+bool VulkanServerBufferIntegration::supportsFormat(QtWayland::ServerBuffer::Format format) const
+{
+ switch (format) {
+ case QtWayland::ServerBuffer::RGBA32:
+ return true;
+ case QtWayland::ServerBuffer::A8:
+ return false;
+ default:
+ return false;
+ }
+}
+
+QtWayland::ServerBuffer *VulkanServerBufferIntegration::createServerBufferFromImage(const QImage &qimage, QtWayland::ServerBuffer::Format format)
+{
+ if (!m_vulkanWrapper) {
+ CurrentContext current;
+ m_vulkanWrapper = new VulkanWrapper(current.context());
+ }
+ return new VulkanServerBuffer(this, qimage, format);
+}
+
+QtWayland::ServerBuffer *VulkanServerBufferIntegration::createServerBufferFromData(const QByteArray &data, const QSize &size, uint glInternalFormat)
+{
+ if (!m_vulkanWrapper) {
+ CurrentContext current;
+ m_vulkanWrapper = new VulkanWrapper(current.context());
+ }
+
+ auto *vImage = m_vulkanWrapper->createTextureImageFromData(reinterpret_cast<const uchar*>(data.constData()), data.size(), size, glInternalFormat);
+
+ if (vImage)
+ return new VulkanServerBuffer(this, vImage, glInternalFormat, size);
+
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "could not load compressed texture";
+ return nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.h b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.h
new file mode 100644
index 000000000..7246e36df
--- /dev/null
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 VULKANSERVERBUFFERINTEGRATION_H
+#define VULKANSERVERBUFFERINTEGRATION_H
+
+#include <QtWaylandCompositor/private/qwlserverbufferintegration_p.h>
+
+#include "qwayland-server-qt-vulkan-server-buffer-unstable-v1.h"
+
+#include <QtGui/QImage>
+#include <QtGui/QWindow>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtGui/QGuiApplication>
+
+#include <QtWaylandCompositor/qwaylandcompositor.h>
+#include <QtWaylandCompositor/private/qwayland-server-server-buffer-extension.h>
+
+QT_BEGIN_NAMESPACE
+
+class VulkanServerBufferIntegration;
+class VulkanWrapper;
+struct VulkanImageWrapper;
+
+class VulkanServerBuffer : public QtWayland::ServerBuffer, public QtWaylandServer::qt_server_buffer
+{
+public:
+ VulkanServerBuffer(VulkanServerBufferIntegration *integration, const QImage &qimage, QtWayland::ServerBuffer::Format format);
+ VulkanServerBuffer(VulkanServerBufferIntegration *integration, VulkanImageWrapper *vImage, uint glInternalFormat, const QSize &size);
+ ~VulkanServerBuffer() override;
+
+ struct ::wl_resource *resourceForClient(struct ::wl_client *) override;
+ bool bufferInUse() override;
+ QOpenGLTexture *toOpenGlTexture() override;
+ void releaseOpenGlTexture() override;
+
+protected:
+ void server_buffer_release(Resource *resource) override;
+
+private:
+ VulkanServerBufferIntegration *m_integration = nullptr;
+
+ int m_width;
+ int m_height;
+ int m_memorySize;
+ int m_fd = -1;
+ VulkanImageWrapper *m_vImage = nullptr;
+ QOpenGLTexture *m_texture = nullptr;
+ uint m_glInternalFormat;
+ GLuint m_memoryObject;
+};
+
+class VulkanServerBufferIntegration :
+ public QtWayland::ServerBufferIntegration,
+ public QtWaylandServer::zqt_vulkan_server_buffer_v1
+{
+public:
+ VulkanServerBufferIntegration();
+ ~VulkanServerBufferIntegration() override;
+
+ VulkanWrapper *vulkanWrapper() const { return m_vulkanWrapper; }
+
+ void initializeHardware(QWaylandCompositor *) override;
+
+ bool supportsFormat(QtWayland::ServerBuffer::Format format) const override;
+ QtWayland::ServerBuffer *createServerBufferFromImage(const QImage &qimage, QtWayland::ServerBuffer::Format format) override;
+ QtWayland::ServerBuffer *createServerBufferFromData(const QByteArray &data, const QSize &size, uint glInternalFormat) override;
+
+private:
+ VulkanWrapper *m_vulkanWrapper = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp
new file mode 100644
index 000000000..fe66adf55
--- /dev/null
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp
@@ -0,0 +1,733 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+// NOTE: Some of the code below is adapted from the public domain code at https://vulkan-tutorial.com/
+
+#define GL_GLEXT_PROTOTYPES
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <QtVulkanSupport/private/qvkconvenience_p.h>
+
+#include "vulkanwrapper.h"
+
+#include <QImage>
+#include <QOpenGLContext>
+
+#include <set>
+
+#include <unistd.h>
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+static constexpr bool extraDebug = false;
+
+#define DECL_VK_FUNCTION(name) \
+ PFN_ ## name name = nullptr;
+
+#define IMPL_VK_FUNCTION(name) \
+ name = reinterpret_cast<PFN_ ## name>(f_glGetVkProcAddrNV(#name)); \
+ if (!name) { \
+ qCritical() << "ERROR in Vulkan proc lookup. Could not find " #name; \
+ }
+
+struct QueueFamilyIndices {
+ int graphicsFamily = -1;
+ int presentFamily = -1;
+
+ bool isComplete() {
+ return graphicsFamily >= 0 && presentFamily >= 0;
+ }
+};
+
+class VulkanWrapperPrivate
+{
+public:
+ explicit VulkanWrapperPrivate(QOpenGLContext *glContext);
+
+ VulkanImageWrapper *createTextureImage(const QImage &img);
+ VulkanImageWrapper *createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, VkFormat vkFormat);
+
+ void freeTextureImage(VulkanImageWrapper *imageWrapper);
+
+private:
+ DECL_VK_FUNCTION(vkAllocateCommandBuffers);
+ DECL_VK_FUNCTION(vkAllocateMemory);
+ DECL_VK_FUNCTION(vkBeginCommandBuffer);
+ DECL_VK_FUNCTION(vkBindImageMemory);
+ DECL_VK_FUNCTION(vkCmdCopyBufferToImage);
+ DECL_VK_FUNCTION(vkCmdPipelineBarrier);
+ DECL_VK_FUNCTION(vkCreateImage);
+ DECL_VK_FUNCTION(vkDestroyImage);
+ DECL_VK_FUNCTION(vkDestroyBuffer);
+ DECL_VK_FUNCTION(vkEndCommandBuffer);
+ DECL_VK_FUNCTION(vkFreeCommandBuffers);
+ DECL_VK_FUNCTION(vkFreeMemory);
+ DECL_VK_FUNCTION(vkGetImageMemoryRequirements);
+ DECL_VK_FUNCTION(vkGetPhysicalDeviceMemoryProperties);
+ DECL_VK_FUNCTION(vkMapMemory);
+ DECL_VK_FUNCTION(vkQueueSubmit);
+ DECL_VK_FUNCTION(vkQueueWaitIdle);
+ DECL_VK_FUNCTION(vkUnmapMemory);
+ DECL_VK_FUNCTION(vkCreateBuffer);
+ DECL_VK_FUNCTION(vkGetBufferMemoryRequirements);
+ DECL_VK_FUNCTION(vkBindBufferMemory);
+
+ DECL_VK_FUNCTION(vkCreateInstance);
+ DECL_VK_FUNCTION(vkEnumeratePhysicalDevices);
+ DECL_VK_FUNCTION(vkGetPhysicalDeviceProperties);
+ DECL_VK_FUNCTION(vkCreateDevice);
+ DECL_VK_FUNCTION(vkGetPhysicalDeviceFormatProperties);
+
+ DECL_VK_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties);
+ DECL_VK_FUNCTION(vkCreateCommandPool);
+
+ DECL_VK_FUNCTION(vkGetDeviceQueue);
+ DECL_VK_FUNCTION(vkGetImageMemoryRequirements2KHR);
+ DECL_VK_FUNCTION(vkGetMemoryFdKHR);
+
+ //DECL_VK_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR);
+
+ void initFunctions(PFNGLGETVKPROCADDRNVPROC f_glGetVkProcAddrNV) {
+ IMPL_VK_FUNCTION(vkAllocateCommandBuffers);
+ IMPL_VK_FUNCTION(vkAllocateMemory);
+ IMPL_VK_FUNCTION(vkBeginCommandBuffer);
+ IMPL_VK_FUNCTION(vkBindImageMemory);
+ IMPL_VK_FUNCTION(vkCmdCopyBufferToImage);
+ IMPL_VK_FUNCTION(vkCmdPipelineBarrier);
+ IMPL_VK_FUNCTION(vkCreateImage);
+ IMPL_VK_FUNCTION(vkDestroyImage);
+ IMPL_VK_FUNCTION(vkDestroyBuffer);
+ IMPL_VK_FUNCTION(vkEndCommandBuffer);
+ IMPL_VK_FUNCTION(vkFreeCommandBuffers);
+ IMPL_VK_FUNCTION(vkFreeMemory);
+ IMPL_VK_FUNCTION(vkGetImageMemoryRequirements);
+ IMPL_VK_FUNCTION(vkGetPhysicalDeviceMemoryProperties);
+ IMPL_VK_FUNCTION(vkMapMemory);
+ IMPL_VK_FUNCTION(vkQueueSubmit);
+ IMPL_VK_FUNCTION(vkQueueWaitIdle);
+ IMPL_VK_FUNCTION(vkUnmapMemory);
+ IMPL_VK_FUNCTION(vkCreateBuffer);
+ IMPL_VK_FUNCTION(vkGetBufferMemoryRequirements);
+ IMPL_VK_FUNCTION(vkBindBufferMemory);
+
+ IMPL_VK_FUNCTION(vkCreateInstance);
+ IMPL_VK_FUNCTION(vkEnumeratePhysicalDevices);
+ IMPL_VK_FUNCTION(vkGetPhysicalDeviceProperties);
+ IMPL_VK_FUNCTION(vkCreateDevice);
+ IMPL_VK_FUNCTION(vkGetPhysicalDeviceFormatProperties);
+
+ IMPL_VK_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties);
+ IMPL_VK_FUNCTION(vkCreateCommandPool);
+
+ IMPL_VK_FUNCTION(vkGetDeviceQueue);
+ IMPL_VK_FUNCTION(vkGetImageMemoryRequirements2KHR);
+ IMPL_VK_FUNCTION(vkGetMemoryFdKHR);
+
+ //IMPL_VK_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR);
+ }
+
+ int findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
+
+ VulkanImageWrapper *createImage(VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, const QSize &size, int memSize);
+ bool transitionImageLayout(VkImage image, VkFormat /*format*/, VkImageLayout oldLayout, VkImageLayout newLayout);
+ bool createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory);
+ VkCommandBuffer beginSingleTimeCommands();
+ void endSingleTimeCommands(VkCommandBuffer commandBuffer);
+ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height);
+ void createCommandPool();
+ QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
+ bool createLogicalDevice();
+
+private:
+ VkInstance m_instance = VK_NULL_HANDLE;
+ VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
+ VkDevice m_device = VK_NULL_HANDLE;
+ VkCommandPool m_commandPool = VK_NULL_HANDLE;
+
+ VkQueue m_graphicsQueue = VK_NULL_HANDLE;
+
+ bool m_initFailed = false;
+};
+
+struct VulkanImageWrapper
+{
+ VkImage textureImage = VK_NULL_HANDLE;
+ int imgMemSize = -1;
+ QSize imgSize;
+ int imgFd = -1;
+ VkDeviceMemory textureImageMemory = VK_NULL_HANDLE;
+};
+
+int VulkanWrapperPrivate::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
+{
+ VkPhysicalDeviceMemoryProperties memProperties;
+ vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memProperties);
+
+ for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
+ if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
+ return i;
+ }
+ }
+
+ qCritical("VulkanWrapper: failed to find suitable memory type!");
+ return -1;
+}
+
+
+VulkanImageWrapper *VulkanWrapperPrivate::createImage(VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, const QSize &size, int memSize)
+{
+ VkImageCreateInfo imageInfo = {};
+ imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ imageInfo.imageType = VK_IMAGE_TYPE_2D;
+ imageInfo.extent.width = size.width();
+ imageInfo.extent.height = size.height();
+ imageInfo.extent.depth = 1;
+ imageInfo.mipLevels = 1;
+ imageInfo.arrayLayers = 1;
+ imageInfo.format = format;
+ imageInfo.tiling = tiling;
+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ imageInfo.usage = usage;
+ imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+ imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+ VkImage image = VK_NULL_HANDLE;
+
+ if (vkCreateImage(m_device, &imageInfo, nullptr, &image) != VK_SUCCESS) {
+ qCritical("VulkanWrapper: failed to create image!");
+ return nullptr;
+ }
+
+ QScopedPointer<VulkanImageWrapper> imageWrapper(new VulkanImageWrapper);
+ imageWrapper->textureImage = image;
+ imageWrapper->imgMemSize = memSize;
+ imageWrapper->imgSize = size;
+
+ VkMemoryRequirements memRequirements;
+ vkGetImageMemoryRequirements(m_device, image, &memRequirements);
+
+ VkExportMemoryAllocateInfoKHR exportAllocInfo = {};
+ exportAllocInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
+ exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+ VkMemoryAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocInfo.allocationSize = memRequirements.size;
+ int memoryType = findMemoryType(memRequirements.memoryTypeBits, properties);
+ if (memoryType < 0)
+ return nullptr;
+ allocInfo.memoryTypeIndex = memoryType;
+ allocInfo.pNext = &exportAllocInfo;
+
+ if (vkAllocateMemory(m_device, &allocInfo, nullptr, &imageWrapper->textureImageMemory) != VK_SUCCESS) {
+ qCritical("VulkanWrapper: failed to allocate image memory!");
+ return nullptr;
+ }
+
+ int res = vkBindImageMemory(m_device, image, imageWrapper->textureImageMemory, 0);
+ Q_UNUSED(res);
+ if (extraDebug) qDebug() << "vkBindImageMemory res" << res;
+
+ VkMemoryGetFdInfoKHR memoryFdInfo = {};
+ memoryFdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
+ memoryFdInfo.memory = imageWrapper->textureImageMemory;
+ memoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+ res = vkGetMemoryFdKHR(m_device, &memoryFdInfo, &imageWrapper->imgFd);
+ if (extraDebug) qDebug() << "vkGetMemoryFdKHR res" << res << "fd" << imageWrapper->imgFd;
+
+ return imageWrapper.take();
+}
+
+
+bool VulkanWrapperPrivate::transitionImageLayout(VkImage image, VkFormat /*format*/, VkImageLayout oldLayout, VkImageLayout newLayout)
+{
+ VkCommandBuffer commandBuffer = beginSingleTimeCommands();
+
+ VkImageMemoryBarrier barrier = {};
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier.oldLayout = oldLayout;
+ barrier.newLayout = newLayout;
+ barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.image = image;
+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ barrier.subresourceRange.baseMipLevel = 0;
+ barrier.subresourceRange.levelCount = 1;
+ barrier.subresourceRange.baseArrayLayer = 0;
+ barrier.subresourceRange.layerCount = 1;
+
+ VkPipelineStageFlags sourceStage;
+ VkPipelineStageFlags destinationStage;
+
+ if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+
+ sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ } else {
+ qCritical("VulkanWrapper: unsupported layout transition!");
+ return false;
+ }
+
+ vkCmdPipelineBarrier(
+ commandBuffer,
+ sourceStage, destinationStage,
+ 0,
+ 0, nullptr,
+ 0, nullptr,
+ 1, &barrier
+ );
+
+ endSingleTimeCommands(commandBuffer);
+ return true;
+}
+
+bool VulkanWrapperPrivate::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory)
+{
+ VkBufferCreateInfo bufferInfo = {};
+ bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferInfo.size = size;
+ bufferInfo.usage = usage;
+ bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+ if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {
+ qCritical("VulkanWrapper: failed to create buffer!");
+ return false;
+ }
+
+ VkMemoryRequirements memRequirements;
+ vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements);
+
+ VkMemoryAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocInfo.allocationSize = memRequirements.size;
+ allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);
+
+ if (vkAllocateMemory(m_device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {
+ qCritical("VulkanWrapper: failed to allocate buffer memory!");
+ return false;
+ }
+
+ vkBindBufferMemory(m_device, buffer, bufferMemory, 0);
+ return true;
+}
+
+
+VkCommandBuffer VulkanWrapperPrivate::beginSingleTimeCommands()
+{
+ VkCommandBufferAllocateInfo allocInfo = {};
+ allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ allocInfo.commandPool = m_commandPool;
+ allocInfo.commandBufferCount = 1;
+
+ if (extraDebug) qDebug() << "allocating...";
+
+ VkCommandBuffer commandBuffer;
+ int res = vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer);
+ Q_UNUSED(res);
+ if (extraDebug) qDebug() << "vkAllocateCommandBuffers res" << res;
+
+ VkCommandBufferBeginInfo beginInfo = {};
+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+
+ res = vkBeginCommandBuffer(commandBuffer, &beginInfo);
+ if (extraDebug) qDebug() << "BEGIN res" << res;
+
+ return commandBuffer;
+}
+
+void VulkanWrapperPrivate::endSingleTimeCommands(VkCommandBuffer commandBuffer)
+{
+ int res = vkEndCommandBuffer(commandBuffer);
+ Q_UNUSED(res);
+ if (extraDebug) qDebug() << "END res" << res;
+
+ VkSubmitInfo submitInfo = {};
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &commandBuffer;
+
+ vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
+ vkQueueWaitIdle(m_graphicsQueue);
+
+ vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
+}
+
+void VulkanWrapperPrivate::copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
+{
+ VkCommandBuffer commandBuffer = beginSingleTimeCommands();
+
+ VkBufferImageCopy region = {};
+ region.bufferOffset = 0;
+ region.bufferRowLength = 0;
+ region.bufferImageHeight = 0;
+ region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ region.imageSubresource.mipLevel = 0;
+ region.imageSubresource.baseArrayLayer = 0;
+ region.imageSubresource.layerCount = 1;
+ region.imageOffset = {0, 0, 0};
+ region.imageExtent = {
+ width,
+ height,
+ 1
+ };
+
+ vkCmdCopyBufferToImage(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+
+ endSingleTimeCommands(commandBuffer);
+}
+
+void VulkanWrapperPrivate::createCommandPool()
+{
+ QueueFamilyIndices queueFamilyIndices = findQueueFamilies(m_physicalDevice);
+
+ VkCommandPoolCreateInfo poolInfo = {};
+ poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily;
+
+ if (vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool) != VK_SUCCESS) {
+ m_initFailed = true;
+ qCritical("VulkanWrapperPrivate: could not create command pool");
+ }
+}
+
+QueueFamilyIndices VulkanWrapperPrivate::findQueueFamilies(VkPhysicalDevice device)
+{
+ QueueFamilyIndices indices;
+
+ uint32_t queueFamilyCount = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
+ if (extraDebug) qDebug() << "queueFamilyCount" << queueFamilyCount;
+
+
+ std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
+ vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
+
+#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
+ for (const auto& queueFamily : queueFamilies) {
+ qDebug() << "....q" << "count" << queueFamily.queueCount << queueFamily.timestampValidBits << hex << queueFamily.queueFlags;
+ }
+#endif
+
+ int i = 0;
+ for (const auto& queueFamily : queueFamilies) {
+ if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ indices.graphicsFamily = i;
+ break;
+ }
+ i++;
+ }
+
+ return indices;
+}
+
+bool VulkanWrapperPrivate::createLogicalDevice()
+{
+ QueueFamilyIndices indices = findQueueFamilies(m_physicalDevice);
+
+ std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
+ std::set<int> uniqueQueueFamilies = {indices.graphicsFamily}; //////, indices.presentFamily};
+
+ float queuePriority = 1.0f;
+ for (int queueFamily : uniqueQueueFamilies) {
+ VkDeviceQueueCreateInfo queueCreateInfo = {};
+ queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queueCreateInfo.queueFamilyIndex = queueFamily;
+ queueCreateInfo.queueCount = 1;
+ queueCreateInfo.pQueuePriorities = &queuePriority;
+ queueCreateInfos.push_back(queueCreateInfo);
+ }
+
+ VkPhysicalDeviceFeatures deviceFeatures = {};
+
+ VkDeviceCreateInfo createInfo = {};
+ createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+
+ createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
+ createInfo.pQueueCreateInfos = queueCreateInfos.data();
+
+ createInfo.pEnabledFeatures = &deviceFeatures;
+
+ if (vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device) != VK_SUCCESS) {
+ qCritical("VulkanWrapper: failed to create logical device!");
+ return false;
+ }
+
+ vkGetDeviceQueue(m_device, indices.graphicsFamily, 0, &m_graphicsQueue);
+ return true;
+}
+
+VulkanImageWrapper *VulkanWrapperPrivate::createTextureImage(const QImage &img)
+{
+ return createTextureImageFromData(img.constBits(), img.sizeInBytes(), img.size(), VK_FORMAT_R8G8B8A8_UNORM);
+}
+
+VulkanImageWrapper *VulkanWrapperPrivate::createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, VkFormat vkFormat)
+{
+ if (m_initFailed)
+ return nullptr;
+
+ int texWidth = size.width();
+ int texHeight = size.height();
+ bool ok;
+ if (extraDebug) qDebug("image load %p %dx%d", pixels, texWidth, texHeight);
+ if (!pixels) {
+ qCritical("VulkanWrapper: failed to load texture image!");
+ return nullptr;
+ }
+
+ VkBuffer stagingBuffer;
+ VkDeviceMemory stagingBufferMemory;
+ ok = createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
+
+ if (!ok)
+ return nullptr;
+
+ void* data;
+ vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &data);
+ if (extraDebug) qDebug() << "mapped" << data << bufferSize;
+ memcpy(data, pixels, static_cast<size_t>(bufferSize));
+ vkUnmapMemory(m_device, stagingBufferMemory);
+
+ if (extraDebug) qDebug() << "creating image...";
+
+ QScopedPointer<VulkanImageWrapper> imageWrapper(createImage(vkFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, size, bufferSize));
+ if (imageWrapper.isNull())
+ return nullptr;
+
+ if (extraDebug) qDebug() << "transition...";
+
+ const VkImage textureImage = imageWrapper->textureImage;
+
+ ok = transitionImageLayout(textureImage, vkFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ if (!ok)
+ return nullptr;
+
+ if (extraDebug) qDebug() << "copyBufferToImage...";
+ copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
+ transitionImageLayout(textureImage, vkFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+ vkDestroyBuffer(m_device, stagingBuffer, nullptr);
+ vkFreeMemory(m_device, stagingBufferMemory, nullptr);
+
+ return imageWrapper.take();
+}
+
+void VulkanWrapperPrivate::freeTextureImage(VulkanImageWrapper *imageWrapper)
+{
+ if (!imageWrapper)
+ return;
+
+ //"To avoid leaking resources, the application must release ownership of the file descriptor using the close system call"
+ ::close(imageWrapper->imgFd);
+
+ // clean up the image memory
+ vkDestroyImage(m_device, imageWrapper->textureImage, nullptr);
+ vkFreeMemory(m_device, imageWrapper->textureImageMemory, nullptr);
+}
+
+VulkanWrapperPrivate::VulkanWrapperPrivate(QOpenGLContext *glContext)
+{
+ if (extraDebug) qDebug("Creating Vulkan instance");
+ VkApplicationInfo applicationInfo = {};
+ applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ applicationInfo.pNext = nullptr;
+ applicationInfo.pApplicationName = nullptr;
+ applicationInfo.applicationVersion = 0;
+ applicationInfo.pEngineName = nullptr;
+ applicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+ applicationInfo.apiVersion = VK_MAKE_VERSION(1, 0, 5);
+
+ VkInstanceCreateInfo instanceCreateInfo = {};
+ instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ instanceCreateInfo.pNext = nullptr;
+ instanceCreateInfo.flags = 0;
+ instanceCreateInfo.pApplicationInfo = &applicationInfo;
+ instanceCreateInfo.enabledLayerCount = 0;
+ instanceCreateInfo.ppEnabledLayerNames = nullptr;
+ instanceCreateInfo.enabledExtensionCount = 0;
+ instanceCreateInfo.ppEnabledExtensionNames = nullptr;
+
+ auto f_glGetVkProcAddrNV = reinterpret_cast<PFNGLGETVKPROCADDRNVPROC>(glContext->getProcAddress("glGetVkProcAddrNV"));
+
+ if (!f_glGetVkProcAddrNV) {
+ qCritical("VulkanWrapper: Could not find Vulkan/GL interop function glGetVkProcAddrNV");
+ m_initFailed = true;
+ return;
+ }
+
+ initFunctions(f_glGetVkProcAddrNV);
+
+ VkResult instanceCreationResult = vkCreateInstance(&instanceCreateInfo, nullptr, &m_instance);
+
+ if (extraDebug) qDebug() << "result" << instanceCreationResult;
+
+ if (instanceCreationResult != VK_SUCCESS) {
+ qCritical() << "VulkanWrapper: Failed to create Vulkan instance: Error "
+ << instanceCreationResult;
+ m_initFailed = true;
+ return;
+ }
+
+ uint32_t devCount;
+
+ auto res = vkEnumeratePhysicalDevices(m_instance, &devCount, nullptr);
+ if (extraDebug) qDebug() << "vkEnumeratePhysicalDevices res =" << res << "count =" << devCount;
+
+ QVarLengthArray<VkPhysicalDevice, 5> dev(devCount);
+
+ res = vkEnumeratePhysicalDevices(m_instance, &devCount, dev.data());
+ if (extraDebug) qDebug() << "...devs res =" << res << "count =" << devCount;
+
+#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
+ VkPhysicalDeviceProperties props;
+
+ vkGetPhysicalDeviceProperties(dev[0], &props);
+
+ qDebug() << "Properties " << hex
+ << "apiVersion" << props.apiVersion
+ << "driverVersion" << props.driverVersion
+ << "vendorID" << props.vendorID
+ << "deviceID" << props.deviceID
+ << "deviceType" << props.deviceType
+ << "deviceName" << props.deviceName;
+#endif
+
+ m_physicalDevice = dev[0]; //TODO handle the case of multiple GPUs where only some support Vulkan
+
+ bool ok = createLogicalDevice();
+ if (!ok) {
+ qCritical("VulkanWrapperPrivate: could not create logical device");
+ m_initFailed = true;
+ return;
+ }
+
+ VkPhysicalDeviceMemoryProperties memProps;
+
+
+ vkGetPhysicalDeviceMemoryProperties(dev[0], &memProps);
+
+#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
+ qDebug() << "Physical memory properties:\n" << "types:" << memProps.memoryTypeCount << "heaps:" << memProps.memoryHeapCount;
+ for (uint i = 0; i < memProps.memoryTypeCount; ++i)
+ qDebug() << " " << i << "heap" << memProps.memoryTypes[i].heapIndex << "flags" << hex << memProps.memoryTypes[i].propertyFlags;
+
+ for (uint i = 0; i < memProps.memoryHeapCount; ++i)
+ qDebug() << " " << i << "size" << memProps.memoryHeaps[i].size << "flags" << hex << memProps.memoryHeaps[i].flags;
+#endif
+
+ int gpuMemoryType = -1;
+
+ for (uint i = 0; i < memProps.memoryTypeCount; ++i) {
+ if (memProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
+ gpuMemoryType = i;
+ break;
+ }
+ }
+
+ if (gpuMemoryType < 0) {
+ qCritical("VulkanWrapper: Could not find GPU memory!");
+ m_initFailed = true;
+ return;
+ }
+
+#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
+ qDebug() << "GPU memory type:" << gpuMemoryType << "heap:" << memProps.memoryTypes[gpuMemoryType].heapIndex;
+
+ for (int f = 0; f <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK; f++)
+ {
+ VkFormatProperties formatProps;
+ vkGetPhysicalDeviceFormatProperties(dev[0], VkFormat(f), &formatProps);
+ qDebug() << "format" << f << "features" << hex << formatProps.linearTilingFeatures << formatProps.optimalTilingFeatures << formatProps.bufferFeatures;
+ }
+#endif
+ createCommandPool();
+}
+
+
+VulkanWrapper::VulkanWrapper(QOpenGLContext *glContext)
+ : d_ptr(new VulkanWrapperPrivate(glContext))
+{
+}
+
+VulkanImageWrapper *VulkanWrapper::createTextureImage(const QImage &img)
+{
+ return d_ptr->createTextureImage(img);
+}
+
+VulkanImageWrapper *VulkanWrapper::createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, uint glInternalFormat)
+{
+ VkFormat vkFormat = VkFormat(QVkConvenience::vkFormatFromGlFormat(glInternalFormat));
+
+ if (vkFormat == VK_FORMAT_UNDEFINED)
+ return nullptr;
+
+ return d_ptr->createTextureImageFromData(pixels, bufferSize, size, vkFormat);
+}
+
+int VulkanWrapper::getImageInfo(const VulkanImageWrapper *imgWrapper, int *memSize, int *w, int *h)
+{
+ if (memSize)
+ *memSize = imgWrapper->imgMemSize;
+ if (w)
+ *w = imgWrapper->imgSize.width();
+ if (h)
+ *h = imgWrapper->imgSize.height();
+ return imgWrapper->imgFd;
+}
+
+void VulkanWrapper::freeTextureImage(VulkanImageWrapper *imageWrapper)
+{
+ d_ptr->freeTextureImage(imageWrapper);
+}
+
+QT_END_NAMESPACE
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.h b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.h
new file mode 100644
index 000000000..541618fb3
--- /dev/null
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 VULKANWRAPPER_H
+#define VULKANWRAPPER_H
+
+#include <QOpenGLContext>
+
+QT_BEGIN_NAMESPACE
+
+class VulkanWrapper;
+struct VulkanImageWrapper;
+class VulkanWrapperPrivate;
+
+class QOpenGLContext;
+class QImage;
+
+class VulkanWrapper
+{
+public:
+ VulkanWrapper(QOpenGLContext *glContext);
+
+ VulkanImageWrapper *createTextureImage(const QImage &img);
+ VulkanImageWrapper *createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, uint glInternalFormat);
+ int getImageInfo(const VulkanImageWrapper *imgWrapper, int *memSize, int *w = nullptr, int *h = nullptr);
+ void freeTextureImage(VulkanImageWrapper *imageWrapper);
+
+private:
+ VulkanWrapperPrivate *d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // VULKANWRAPPER_H
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index c57c95d20..c8394f0c1 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,3 +1,8 @@
TEMPLATE = subdirs
-qtHaveModule(quick): SUBDIRS += compositor
+qtHaveModule(quick): {
+ SUBDIRS += \
+ compositor \
+ texture-sharing \
+ texture-sharing-extension
+}
diff --git a/src/imports/texture-sharing-extension/plugin.cpp b/src/imports/texture-sharing-extension/plugin.cpp
new file mode 100644
index 000000000..42dcd8e2d
--- /dev/null
+++ b/src/imports/texture-sharing-extension/plugin.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqmlengine.h>
+
+#include "QtWaylandCompositor/private/qwltexturesharingextension_p.h"
+
+/*!
+ \qmlmodule QtWayland.Compositor.TextureSharingExtension 1
+ \title Qt Wayland Shared Texture Provider
+ \ingroup qmlmodules
+ \brief Adds a mechanism to share GPU memory
+
+ \section2 Summary
+
+ This module lets the compositor export graphical resources that can be used by clients,
+ without allocating any graphics memory in the client.
+
+ \section2 Usage
+
+ This module is imported like this:
+
+ \code
+ import QtWayland.Compositor.TextureSharingExtension 1.0
+ \endcode
+
+ To use this module in a compositor, instantiate the extension object as a child of the compositor object, like this:
+
+
+ \code
+ WaylandCompositor {
+ //...
+ TextureSharingExtension {
+ }
+ }
+ \endcode
+
+ The sharing functionality is provided through a QQuickImageProvider. Use
+ the "image:" scheme for the URL source of the image, followed by the
+ identifier \e wlshared, followed by the image file path. For example:
+
+ \code
+ Image { source: "image://wlshared/wallpapers/mybackground.jpg" }
+ \endcode
+
+*/
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandTextureSharingExtensionPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+public:
+ QWaylandTextureSharingExtensionPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) {}
+
+ void registerTypes(const char *uri) override
+ {
+ Q_ASSERT(uri == QStringLiteral("QtWayland.Compositor.TextureSharingExtension"));
+ qmlRegisterType<QWaylandTextureSharingExtensionQuickExtension>("QtWayland.Compositor.TextureSharingExtension", 1, 0, "TextureSharingExtension");
+ }
+
+ void initializeEngine(QQmlEngine *engine, const char *uri) override
+ {
+ Q_UNUSED(uri);
+ engine->addImageProvider("wlshared", new QWaylandSharedTextureProvider);
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/imports/texture-sharing-extension/qmldir b/src/imports/texture-sharing-extension/qmldir
new file mode 100644
index 000000000..182e5c0ee
--- /dev/null
+++ b/src/imports/texture-sharing-extension/qmldir
@@ -0,0 +1,3 @@
+module QtWayland.Compositor.TextureSharingExtension
+plugin qwaylandtexturesharingextension
+classname QWaylandTextureSharingExtensionPlugin
diff --git a/src/imports/texture-sharing-extension/texture-sharing-extension.pro b/src/imports/texture-sharing-extension/texture-sharing-extension.pro
new file mode 100644
index 000000000..577ab58e7
--- /dev/null
+++ b/src/imports/texture-sharing-extension/texture-sharing-extension.pro
@@ -0,0 +1,13 @@
+CXX_MODULE = qml
+TARGET = qwaylandtexturesharingextension
+TARGETPATH = QtWayland/Compositor/TextureSharingExtension
+IMPORT_VERSION = 1.$$QT_MINOR_VERSION
+
+SOURCES += \
+ plugin.cpp
+
+QT += quick-private qml gui-private core-private waylandcompositor waylandcompositor-private
+
+requires(qtConfig(wayland-compositor-texture-sharing-experimental))
+
+load(qml_plugin)
diff --git a/src/imports/texture-sharing/plugin.cpp b/src/imports/texture-sharing/plugin.cpp
new file mode 100644
index 000000000..9cf6bbca1
--- /dev/null
+++ b/src/imports/texture-sharing/plugin.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandClient 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 <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqmlengine.h>
+
+#include "sharedtextureprovider.h"
+
+/*!
+ \qmlmodule QtWayland.Client.TextureSharing 1
+ \title Qt Wayland Shared Texture Provider
+ \ingroup qmlmodules
+ \brief Adds an image provider which utilizes shared GPU memory
+
+ \section2 Summary
+
+ This module allows Qt Wayland clients to use graphical resources exported
+ by the compositor, without allocating any graphics memory in the client.
+ \section2 Usage
+
+ To use this module, import it like this:
+ \code
+ import QtWayland.Client.TextureSharing 1.0
+ \endcode
+
+ The sharing functionality is provided through a QQuickImageProvider. Use
+ the "image:" scheme for the URL source of the image, followed by the
+ identifier \e wlshared, followed by the image file path. For example:
+
+ \code
+ Image { source: "image://wlshared/wallpapers/mybackground.jpg" }
+ \endcode
+
+ The shared texture module does not provide any directly usable QML types.
+*/
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandTextureSharingPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+public:
+ QWaylandTextureSharingPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) {}
+
+ void registerTypes(const char *uri) override
+ {
+ Q_ASSERT(uri == QStringLiteral("QtWayland.Client.TextureSharing"));
+ qmlRegisterModule(uri, 1, 0);
+ }
+
+ void initializeEngine(QQmlEngine *engine, const char *uri) override
+ {
+ Q_UNUSED(uri);
+ engine->addImageProvider("wlshared", new SharedTextureProvider);
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/imports/texture-sharing/qmldir b/src/imports/texture-sharing/qmldir
new file mode 100644
index 000000000..cf3b74c48
--- /dev/null
+++ b/src/imports/texture-sharing/qmldir
@@ -0,0 +1,3 @@
+module QtWayland.Client.TextureSharing
+plugin qwaylandtexturesharing
+classname QWaylandTextureSharingPlugin
diff --git a/src/imports/texture-sharing/sharedtextureprovider.cpp b/src/imports/texture-sharing/sharedtextureprovider.cpp
new file mode 100644
index 000000000..707e94ae6
--- /dev/null
+++ b/src/imports/texture-sharing/sharedtextureprovider.cpp
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+
+#include "sharedtextureprovider.h"
+
+#include <QFile>
+#include <QDebug>
+#include <qopenglfunctions.h>
+#include <QQuickWindow>
+
+#include <QtWaylandClient/private/qwaylandintegration_p.h>
+#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
+#include <QtGui/QGuiApplication>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtGui/QWindow>
+#include <QOpenGLTexture>
+#include <QImageReader>
+
+#include <QTimer>
+
+#include "texturesharingextension.h"
+
+QT_BEGIN_NAMESPACE
+
+SharedTexture::SharedTexture(QtWaylandClient::QWaylandServerBuffer *buffer)
+ : m_buffer(buffer), m_tex(nullptr)
+{
+}
+
+int SharedTexture::textureId() const
+{
+ updateGLTexture();
+ return m_tex ? m_tex->textureId() : 0;
+}
+
+QSize SharedTexture::textureSize() const
+{
+ updateGLTexture();
+ return m_tex ? QSize(m_tex->width(), m_tex->height()) : QSize();
+}
+
+bool SharedTexture::hasAlphaChannel() const
+{
+ return true;
+}
+
+bool SharedTexture::hasMipmaps() const
+{
+ updateGLTexture();
+ return m_tex ? (m_tex->mipLevels() > 1) : false;
+}
+
+void SharedTexture::bind()
+{
+ updateGLTexture();
+ if (m_tex)
+ m_tex->bind();
+}
+
+inline void SharedTexture::updateGLTexture() const
+{
+ if (!m_tex && m_buffer)
+ m_tex = m_buffer->toOpenGlTexture();
+}
+
+class SharedTextureFactory : public QQuickTextureFactory
+{
+public:
+ SharedTextureFactory(const QtWaylandClient::QWaylandServerBuffer *buffer, const QString &id, SharedTextureRegistry *registry)
+ : m_buffer(buffer), m_id(id), m_registry(registry)
+ {
+ }
+
+ ~SharedTextureFactory() override
+ {
+ //qDebug() << "====> DESTRUCTOR SharedTextureFactory" << this;
+ if (m_registry)
+ m_registry->abandonBuffer(m_id);
+ delete m_buffer; // TODO: make sure we are not keeping references to this elsewhere
+ //qDebug() << "buffer deleted";
+ }
+
+ QSize textureSize() const override
+ {
+ return m_buffer ? m_buffer->size() : QSize();
+ }
+
+ int textureByteCount() const override
+ {
+ return m_buffer ? (m_buffer->size().width() * m_buffer->size().height() * 4) : 0;
+ }
+
+ QSGTexture *createTexture(QQuickWindow *) const override
+ {
+ return new SharedTexture(const_cast<QtWaylandClient::QWaylandServerBuffer *>(m_buffer));
+ }
+
+private:
+ const QtWaylandClient::QWaylandServerBuffer *m_buffer = nullptr;
+ QString m_id;
+ QPointer<SharedTextureRegistry> m_registry;
+};
+
+
+SharedTextureRegistry::SharedTextureRegistry()
+ : m_extension(new TextureSharingExtension)
+{
+ connect(m_extension, &TextureSharingExtension::bufferReceived, this, &SharedTextureRegistry::receiveBuffer);
+ connect(m_extension, &TextureSharingExtension::activeChanged, this, &SharedTextureRegistry::handleExtensionActive);
+}
+
+SharedTextureRegistry::~SharedTextureRegistry()
+{
+ delete m_extension;
+}
+
+const QtWaylandClient::QWaylandServerBuffer *SharedTextureRegistry::bufferForId(const QString &id) const
+{
+ return m_buffers.value(id);
+}
+
+void SharedTextureRegistry::requestBuffer(const QString &id)
+{
+ if (!m_extension->isActive()) {
+ //qDebug() << "Extension not active, adding" << id << "to queue";
+ m_pendingBuffers << id;
+ return;
+ }
+ m_extension->requestImage(id);
+}
+
+void SharedTextureRegistry::abandonBuffer(const QString &id)
+{
+ m_buffers.remove(id);
+ m_extension->abandonImage(id);
+}
+
+
+void SharedTextureRegistry::handleExtensionActive()
+{
+ //qDebug() << "handleExtensionActive, queue:" << m_pendingBuffers;
+ if (m_extension->isActive())
+ while (!m_pendingBuffers.isEmpty())
+ requestBuffer(m_pendingBuffers.takeFirst());
+}
+
+bool SharedTextureRegistry::preinitialize()
+{
+ auto *serverBufferIntegration = QGuiApplicationPrivate::platformIntegration()->nativeInterface()->nativeResourceForIntegration("server_buffer_integration");
+
+ if (!serverBufferIntegration) {
+ qWarning() << "Wayland Server Buffer Integration not available.";
+ return false;
+ }
+
+ return true;
+}
+
+void SharedTextureRegistry::receiveBuffer(QtWaylandClient::QWaylandServerBuffer *buffer, const QString& id)
+{
+ //qDebug() << "ReceiveBuffer for id" << id;
+ if (buffer)
+ m_buffers.insert(id, buffer);
+ emit replyReceived(id);
+}
+
+class SharedTextureImageResponse : public QQuickImageResponse
+{
+ Q_OBJECT
+public:
+ SharedTextureImageResponse(SharedTextureRegistry *registry, const QString &id)
+ : m_id(id), m_registry(registry)
+ {
+ if (!m_registry || m_registry->bufferForId(id)) {
+ // Shortcut: no server roundtrip needed, just let the event loop call the slot
+ QMetaObject::invokeMethod(this, "doResponse", Qt::QueuedConnection, Q_ARG(QString, id));
+
+ } else {
+ // TBD: timeout?
+ connect(registry, &SharedTextureRegistry::replyReceived, this, &SharedTextureImageResponse::doResponse);
+ registry->requestBuffer(id);
+ }
+ }
+
+ QQuickTextureFactory *textureFactory() const override
+ {
+ if (m_registry) {
+ const QtWaylandClient::QWaylandServerBuffer *buffer = m_registry->bufferForId(m_id);
+ if (buffer) {
+ //qDebug() << "Creating shared buffer texture for" << m_id;
+ return new SharedTextureFactory(buffer, m_id, m_registry);
+ }
+ //qDebug() << "Shared buffer NOT found for" << m_id;
+ }
+
+ // No shared buffer, do fallback
+ QString fbPath = fallbackPath();
+ if (fbPath.isEmpty()) {
+ m_errorString = QStringLiteral("Shared buffer not found, and no fallback path set.");
+ return nullptr;
+ }
+
+ QImageReader reader(fbPath + m_id);
+ QImage img = reader.read();
+ if (img.isNull()) {
+ qWarning() << "Could not load local image from id/path" << reader.fileName();
+ m_errorString = QStringLiteral("Shared buffer not found, and fallback local file loading failed: ") + reader.errorString();
+ return nullptr;
+ }
+ return QQuickTextureFactory::textureFactoryForImage(img);
+ }
+
+ QString errorString() const override
+ {
+ return m_errorString;
+ }
+
+ static QString fallbackPath()
+ {
+ static QString fbPath;
+ static bool isInit = false;
+ if (!isInit) {
+ isInit = true;
+ QByteArray envVal = qgetenv("QT_SHAREDTEXTURE_FALLBACK_DIR");
+ if (!envVal.isEmpty()) {
+ fbPath = QString::fromLocal8Bit(envVal);
+ if (!fbPath.endsWith(QLatin1Char('/')))
+ fbPath.append(QLatin1Char('/'));
+ }
+ }
+ return fbPath;
+ }
+
+
+public slots:
+ void doResponse(const QString &key) {
+ if (key != m_id)
+ return; // not our buffer
+
+ // No need to be called again
+ if (m_registry)
+ disconnect(m_registry, &SharedTextureRegistry::replyReceived, this, &SharedTextureImageResponse::doResponse);
+
+ emit finished();
+ }
+
+private:
+ QString m_id;
+ SharedTextureRegistry *m_registry = nullptr;
+ mutable QString m_errorString;
+};
+
+
+SharedTextureProvider::SharedTextureProvider()
+{
+ m_sharingAvailable = SharedTextureRegistry::preinitialize();
+ if (!m_sharingAvailable) {
+ if (SharedTextureImageResponse::fallbackPath().isEmpty())
+ qWarning() << "Shared buffer images not available, and no fallback directory set.";
+ else
+ qWarning() << "Shared buffer images not available, will fallback to local image files from" << SharedTextureImageResponse::fallbackPath();
+ }
+}
+
+SharedTextureProvider::~SharedTextureProvider()
+{
+ delete m_registry;
+}
+
+QQuickImageResponse *SharedTextureProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
+{
+ Q_UNUSED(requestedSize);
+
+ //qDebug() << "Provider: got request for" << id;
+
+ if (m_sharingAvailable && !m_registry)
+ m_registry = new SharedTextureRegistry;
+
+ return new SharedTextureImageResponse(m_registry, id);
+}
+
+QT_END_NAMESPACE
+
+#include "sharedtextureprovider.moc"
diff --git a/src/imports/texture-sharing/sharedtextureprovider.h b/src/imports/texture-sharing/sharedtextureprovider.h
new file mode 100644
index 000000000..f25c7de9c
--- /dev/null
+++ b/src/imports/texture-sharing/sharedtextureprovider.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 SHAREDTEXTUREPROVIDER_H
+#define SHAREDTEXTUREPROVIDER_H
+
+#include <QOpenGLFunctions>
+#include <QQuickImageProvider>
+#include <QtQuick/QSGTexture>
+#include <QScopedPointer>
+#include <QHash>
+
+#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class TextureSharingExtension;
+
+class SharedTextureRegistry : public QObject
+{
+ Q_OBJECT
+public:
+ SharedTextureRegistry();
+ ~SharedTextureRegistry() override;
+
+ const QtWaylandClient::QWaylandServerBuffer *bufferForId(const QString &id) const;
+ void requestBuffer(const QString &id);
+ void abandonBuffer(const QString &id);
+
+ static bool preinitialize();
+
+public slots:
+ void receiveBuffer(QtWaylandClient::QWaylandServerBuffer *buffer, const QString &id);
+
+signals:
+ void replyReceived(const QString &id);
+
+private slots:
+ void handleExtensionActive();
+
+private:
+ TextureSharingExtension *m_extension = nullptr;
+ QHash<QString, QtWaylandClient::QWaylandServerBuffer *> m_buffers;
+ QStringList m_pendingBuffers;
+};
+
+class SharedTextureProvider : public QQuickAsyncImageProvider
+{
+public:
+ SharedTextureProvider();
+ ~SharedTextureProvider() override;
+
+ QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
+
+private:
+ SharedTextureRegistry *m_registry = nullptr;
+ bool m_sharingAvailable = false;
+};
+
+class SharedTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ SharedTexture(QtWaylandClient::QWaylandServerBuffer *buffer);
+
+ int textureId() const override;
+ QSize textureSize() const override;
+ bool hasAlphaChannel() const override;
+ bool hasMipmaps() const override;
+
+ void bind() override;
+
+private:
+ void updateGLTexture() const;
+ QtWaylandClient::QWaylandServerBuffer *m_buffer = nullptr;
+ mutable QOpenGLTexture *m_tex = nullptr;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // SHAREDTEXTUREPROVIDER_H
diff --git a/src/imports/texture-sharing/texture-sharing.pro b/src/imports/texture-sharing/texture-sharing.pro
new file mode 100644
index 000000000..eb5c0a9af
--- /dev/null
+++ b/src/imports/texture-sharing/texture-sharing.pro
@@ -0,0 +1,23 @@
+CXX_MODULE = qml
+TARGET = qwaylandtexturesharing
+TARGETPATH = QtWayland/Client/TextureSharing
+IMPORT_VERSION = 1.$$QT_MINOR_VERSION
+
+HEADERS += \
+ sharedtextureprovider.h \
+ texturesharingextension.h
+
+SOURCES += \
+ plugin.cpp \
+ sharedtextureprovider.cpp \
+ texturesharingextension.cpp
+
+QT += quick-private qml gui-private core-private waylandclient waylandclient-private
+CONFIG += wayland-scanner
+
+requires(qtConfig(wayland-client-texture-sharing-experimental))
+
+WAYLANDCLIENTSOURCES += ../../extensions/qt-texture-sharing-unstable-v1.xml
+
+
+load(qml_plugin)
diff --git a/src/imports/texture-sharing/texturesharingextension.cpp b/src/imports/texture-sharing/texturesharingextension.cpp
new file mode 100644
index 000000000..31106d694
--- /dev/null
+++ b/src/imports/texture-sharing/texturesharingextension.cpp
@@ -0,0 +1,86 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+#include "texturesharingextension.h"
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtWaylandClient/private/qwaylandintegration_p.h>
+#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
+#include <QtGui/QGuiApplication>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/QWindow>
+#include <QtGui/QPlatformSurfaceEvent>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+TextureSharingExtension::TextureSharingExtension()
+ : QWaylandClientExtensionTemplate(/* Supported protocol version */ 1 )
+{
+ auto *wayland_integration = static_cast<QtWaylandClient::QWaylandIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ m_server_buffer_integration = wayland_integration->serverBufferIntegration();
+ if (!m_server_buffer_integration) {
+ qCritical() << "This application requires a working serverBufferIntegration";
+ QGuiApplication::quit();
+ }
+}
+
+void TextureSharingExtension::zqt_texture_sharing_v1_provide_buffer(struct ::qt_server_buffer *buffer, const QString &key)
+{
+ QtWaylandClient::QWaylandServerBuffer *serverBuffer = m_server_buffer_integration->serverBuffer(buffer);
+ emit bufferReceived(serverBuffer, key);
+}
+
+void TextureSharingExtension::zqt_texture_sharing_v1_image_failed(const QString &key, const QString &message)
+{
+ qWarning() << "TextureSharingExtension" << key << "not found" << message;
+ emit bufferReceived(nullptr, key);
+}
+void TextureSharingExtension::requestImage(const QString &key)
+{
+ request_image(key);
+}
+
+void TextureSharingExtension::abandonImage(const QString &key)
+{
+ abandon_image(key);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/texture-sharing/texturesharingextension.h b/src/imports/texture-sharing/texturesharingextension.h
new file mode 100644
index 000000000..7b864fbc8
--- /dev/null
+++ b/src/imports/texture-sharing/texturesharingextension.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 TEXTURESHARINGEXTENSION_H
+#define TEXTURESHARINGEXTENSION_H
+
+#include <qpa/qwindowsysteminterface.h>
+#include <QtWaylandClient/private/qwayland-wayland.h>
+#include <QtWaylandClient/qwaylandclientextension.h>
+#include "qwayland-qt-texture-sharing-unstable-v1.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+ class QWaylandServerBuffer;
+ class QWaylandServerBufferIntegration;
+};
+
+class TextureSharingExtension : public QWaylandClientExtensionTemplate<TextureSharingExtension>
+ , public QtWayland::zqt_texture_sharing_v1
+{
+ Q_OBJECT
+public:
+ TextureSharingExtension();
+
+public slots:
+ void requestImage(const QString &key);
+ void abandonImage(const QString &key);
+
+signals:
+ void bufferReceived(QtWaylandClient::QWaylandServerBuffer *buffer, const QString &key);
+
+private:
+ void zqt_texture_sharing_v1_provide_buffer(struct ::qt_server_buffer *buffer, const QString &key) override;
+ void zqt_texture_sharing_v1_image_failed(const QString &key, const QString &message) override;
+ QtWaylandClient::QWaylandServerBufferIntegration *m_server_buffer_integration = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // TEXTURESHARINGEXTENSION_H
diff --git a/src/plugins/hardwareintegration/client/client.pro b/src/plugins/hardwareintegration/client/client.pro
index 82e431ee8..7b7e8a49a 100644
--- a/src/plugins/hardwareintegration/client/client.pro
+++ b/src/plugins/hardwareintegration/client/client.pro
@@ -18,3 +18,5 @@ qtConfig(wayland-shm-emulation-server-buffer): \
SUBDIRS += shm-emulation-server
qtConfig(wayland-dmabuf-server-buffer): \
SUBDIRS += dmabuf-server
+qtConfig(wayland-vulkan-server-buffer): \
+ SUBDIRS += vulkan-server
diff --git a/src/plugins/hardwareintegration/client/vulkan-server/main.cpp b/src/plugins/hardwareintegration/client/vulkan-server/main.cpp
new file mode 100644
index 000000000..b8f64bf22
--- /dev/null
+++ b/src/plugins/hardwareintegration/client/vulkan-server/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+#include <QtWaylandClient/private/qwaylandserverbufferintegrationplugin_p.h>
+#include "vulkanserverbufferintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class VulkanServerBufferPlugin : public QWaylandServerBufferIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QWaylandServerBufferIntegrationFactoryInterface_iid FILE "vulkan-server.json")
+public:
+ QWaylandServerBufferIntegration *create(const QString&, const QStringList&) override;
+};
+
+QWaylandServerBufferIntegration *VulkanServerBufferPlugin::create(const QString& key, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ Q_UNUSED(key);
+ return new VulkanServerBufferIntegration();
+}
+
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/hardwareintegration/client/vulkan-server/vulkan-server.json b/src/plugins/hardwareintegration/client/vulkan-server/vulkan-server.json
new file mode 100644
index 000000000..baadd1529
--- /dev/null
+++ b/src/plugins/hardwareintegration/client/vulkan-server/vulkan-server.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "vulkan-server" ]
+}
diff --git a/src/plugins/hardwareintegration/client/vulkan-server/vulkan-server.pro b/src/plugins/hardwareintegration/client/vulkan-server/vulkan-server.pro
new file mode 100644
index 000000000..1be60f7c1
--- /dev/null
+++ b/src/plugins/hardwareintegration/client/vulkan-server/vulkan-server.pro
@@ -0,0 +1,15 @@
+# We have a bunch of C code with casts, so we can't have this option
+QMAKE_CXXFLAGS_WARN_ON -= -Wcast-qual
+
+QT += waylandclient-private
+
+include(../../../../hardwareintegration/client/vulkan-server/vulkan-server.pri)
+
+OTHER_FILES += \
+ vulkan-server.json
+
+SOURCES += main.cpp
+
+PLUGIN_TYPE = wayland-graphics-integration-client
+PLUGIN_CLASS_NAME = VulkanServerBufferPlugin
+load(qt_plugin)
diff --git a/src/plugins/hardwareintegration/compositor/compositor.pro b/src/plugins/hardwareintegration/compositor/compositor.pro
index 66272e830..1912d1e9f 100644
--- a/src/plugins/hardwareintegration/compositor/compositor.pro
+++ b/src/plugins/hardwareintegration/compositor/compositor.pro
@@ -18,6 +18,8 @@ qtConfig(wayland-shm-emulation-server-buffer): \
SUBDIRS += shm-emulation-server
qtConfig(wayland-dmabuf-server-buffer): \
SUBDIRS += dmabuf-server
+qtConfig(wayland-vulkan-server-buffer): \
+ SUBDIRS += vulkan-server
qtConfig(wayland-egl): \
SUBDIRS += wayland-eglstream-controller
diff --git a/src/plugins/hardwareintegration/compositor/vulkan-server/main.cpp b/src/plugins/hardwareintegration/compositor/vulkan-server/main.cpp
new file mode 100644
index 000000000..d765dd389
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/vulkan-server/main.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+#include <QtWaylandCompositor/private/qwlserverbufferintegrationplugin_p.h>
+#include "vulkanserverbufferintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class VulkanServerBufferIntegrationPlugin : public QtWayland::ServerBufferIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QtWaylandServerBufferIntegrationFactoryInterface_iid FILE "vulkan-server.json")
+public:
+ QtWayland::ServerBufferIntegration *create(const QString&, const QStringList&) override;
+};
+
+QtWayland::ServerBufferIntegration *VulkanServerBufferIntegrationPlugin::create(const QString& key, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ Q_UNUSED(key);
+ return new VulkanServerBufferIntegration();
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.json b/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.json
new file mode 100644
index 000000000..baadd1529
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "vulkan-server" ]
+}
diff --git a/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.pro b/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.pro
new file mode 100644
index 000000000..053654218
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.pro
@@ -0,0 +1,12 @@
+QT = waylandcompositor waylandcompositor-private core-private gui-private
+
+OTHER_FILES += vulkan-server.json
+
+SOURCES += \
+ main.cpp
+
+include($PWD/../../../../../hardwareintegration/compositor/vulkan-server/vulkan-server.pri)
+
+PLUGIN_TYPE = wayland-graphics-integration-server
+PLUGIN_CLASS_NAME = VulkanServerBufferIntegrationPlugin
+load(qt_plugin)
diff --git a/src/src.pro b/src/src.pro
index 4ecbc71b9..db7d72753 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -20,7 +20,7 @@ qtConfig(wayland-client) {
SUBDIRS += sub_compositor
sub_imports.subdir = imports
- sub_imports.depends += sub-compositor
+ sub_imports.depends += sub-compositor sub-client
sub_imports.target = sub-imports
SUBDIRS += sub_imports
diff --git a/sync.profile b/sync.profile
index 756674cda..f8faa614e 100644
--- a/sync.profile
+++ b/sync.profile
@@ -58,6 +58,7 @@
"^qwayland-server-ivi-application.h",
"^qwayland-server-qt-windowmanager.h",
"^qwayland-server-qt-key-unstable-v1.h",
+ "^qwayland-server-qt-texture-sharing-unstable-v1.h",
"^qwayland-server-server-buffer-extension.h",
"^qwayland-server-text-input-unstable-v2.h",
"^qwayland-server-touch-extension.h",
@@ -69,6 +70,7 @@
"^wayland-ivi-application-server-protocol.h",
"^wayland-qt-windowmanager-server-protocol.h",
"^wayland-qt-key-unstable-v1-server-protocol.h",
+ "^wayland-qt-texture-sharing-unstable-v1-server-protocol.h",
"^wayland-server-buffer-extension-server-protocol.h",
"^wayland-text-input-unstable-v2-server-protocol.h",
"^wayland-touch-extension-server-protocol.h",