diff options
Diffstat (limited to 'src')
17 files changed, 1576 insertions, 5 deletions
diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri index 5c708f891..42d99895b 100644 --- a/src/compositor/extensions/extensions.pri +++ b/src/compositor/extensions/extensions.pri @@ -8,6 +8,7 @@ WAYLANDSERVERSOURCES += \ ../extensions/touch-extension.xml \ ../extensions/qt-key-unstable-v1.xml \ ../extensions/qt-windowmanager.xml \ + ../extensions/qt-texture-sharing-unstable-v1.xml \ ../3rdparty/protocol/text-input-unstable-v2.xml \ ../3rdparty/protocol/xdg-shell-unstable-v6.xml \ ../3rdparty/protocol/xdg-shell.xml \ @@ -65,7 +66,8 @@ qtHaveModule(quick):contains(QT_CONFIG, opengl) { extensions/qwaylandwlshellintegration_p.h \ extensions/qwaylandxdgshellv5integration_p.h \ extensions/qwaylandxdgshellv6integration_p.h \ - extensions/qwaylandxdgshellintegration_p.h + extensions/qwaylandxdgshellintegration_p.h \ + extensions/qwltexturesharingextension_p.h SOURCES += \ extensions/qwaylandquickshellsurfaceitem.cpp \ @@ -73,8 +75,8 @@ qtHaveModule(quick):contains(QT_CONFIG, opengl) { extensions/qwaylandwlshellintegration.cpp \ extensions/qwaylandxdgshellv5integration.cpp \ extensions/qwaylandxdgshellv6integration.cpp \ - extensions/qwaylandxdgshellintegration.cpp - + extensions/qwaylandxdgshellintegration.cpp \ + extensions/qwltexturesharingextension.cpp } 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..1c15bb49f --- /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) + 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/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/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp index bc6fe7f05..2b39c3ffa 100644 --- a/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp +++ b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp @@ -56,6 +56,8 @@ #include <QDebug> +QT_BEGIN_NAMESPACE + static constexpr bool extraDebug = false; #define DECL_VK_FUNCTION(name) \ @@ -727,3 +729,5 @@ void VulkanWrapper::freeTextureImage(VulkanImageWrapper *imageWrapper) { d_ptr->freeTextureImage(imageWrapper); } + +QT_END_NAMESPACE 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..68a8cf757 --- /dev/null +++ b/src/imports/texture-sharing-extension/texture-sharing-extension.pro @@ -0,0 +1,11 @@ +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 + +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..bec769ecb --- /dev/null +++ b/src/imports/texture-sharing/texture-sharing.pro @@ -0,0 +1,21 @@ +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 + +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/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 |