diff options
21 files changed, 1735 insertions, 0 deletions
diff --git a/config.tests/vulkan_server_buffer/main.cpp b/config.tests/vulkan_server_buffer/main.cpp new file mode 100644 index 00000000..5bd88d33 --- /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 00000000..28dcadcb --- /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 b5146680..4f1a297e 100644 --- a/src/client/configure.json +++ b/src/client/configure.json @@ -74,6 +74,11 @@ "type": "compile", "test": "dmabuf_server_buffer", "use": "egl" + }, + "vulkan-server-buffer": { + "label": "Vulkan Buffer Sharing", + "type": "compile", + "test": "vulkan_server_buffer" } }, @@ -152,6 +157,11 @@ "condition": "features.wayland-client && features.opengl && features.egl && tests.dmabuf-server-buffer", "output": [ "privateFeature" ] }, + "wayland-vulkan-server-buffer": { + "label": "Vulkan-based server buffer integration", + "condition": "features.wayland-client && features.opengl && features.egl && tests.vulkan-server-buffer", + "output": [ "privateFeature" ] + }, "wayland-shm-emulation-server-buffer": { "label": "Shm emulation server buffer integration", "condition": "features.wayland-client && features.opengl", @@ -178,6 +188,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/compositor/configure.json b/src/compositor/configure.json index ec9327ad..ca1493af 100644 --- a/src/compositor/configure.json +++ b/src/compositor/configure.json @@ -85,6 +85,11 @@ "type": "compile", "test": "dmabuf_client_buffer", "use": "egl" + }, + "vulkan-server-buffer": { + "label": "Vulkan Buffer Sharing", + "type": "compile", + "test": "vulkan_server_buffer" } }, @@ -138,6 +143,11 @@ "condition": "features.wayland-server && features.opengl && features.egl && tests.dmabuf-client-buffer", "output": [ "privateFeature" ] }, + "wayland-vulkan-server-buffer": { + "label": "Vulkan-based server buffer integration", + "condition": "features.wayland-server && features.opengl && features.egl && tests.vulkan-server-buffer", + "output": [ "privateFeature" ] + }, "wayland-shm-emulation-server-buffer": { "label": "Shm emulation server buffer", "condition": "features.wayland-server && features.opengl", 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 00000000..211d0a7c --- /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 00000000..2e13a87b --- /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 00000000..4b2be50e --- /dev/null +++ b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** 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 "vulkanserverbufferintegration.h" +#include <QtWaylandClient/private/qwaylanddisplay_p.h> +#include <QDebug> +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> +#include <QtGui/qopengl.h> +#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 00000000..7add7426 --- /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 00000000..9e1b1ff0 --- /dev/null +++ b/src/hardwareintegration/compositor/vulkan-server/vulkan-server.pri @@ -0,0 +1,15 @@ +INCLUDEPATH += $$PWD + +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 00000000..5d63a64d --- /dev/null +++ b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** 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 "vulkanserverbufferintegration.h" + +#include "vulkanwrapper.h" + +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> +#include <QOffscreenSurface> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +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() +{ + 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) { + //server-side texture support not implemented + qWarning("VulkanServerBuffer::toOpenGlTexture not supported."); + } + return m_texture; +} + +bool VulkanServerBuffer::bufferInUse() +{ + return 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; // TODO: add more formats + default: + return false; + } +} + +//RAII +class CurrentContext +{ +public: + CurrentContext() + { + if (!QOpenGLContext::currentContext()) { + if (QOpenGLContext::globalShareContext()) { + localContext = new QOpenGLContext; + localContext->setShareContext(QOpenGLContext::globalShareContext()); + localContext->create(); + + offscreenSurface = new QOffscreenSurface; + offscreenSurface->setFormat(localContext->format()); + offscreenSurface->create(); + localContext->makeCurrent(offscreenSurface); + } else { + qCritical("VulkanServerBufferIntegration: no globalShareContext"); + } + } + } + ~CurrentContext() + { + if (localContext) { + localContext->doneCurrent(); + delete localContext; + delete offscreenSurface; + } + } + QOpenGLContext *context() { return localContext ? localContext : QOpenGLContext::currentContext(); } +private: + QOpenGLContext *localContext = nullptr; + QOffscreenSurface *offscreenSurface = nullptr; +}; + +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); +} + +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 00000000..aa1074ec --- /dev/null +++ b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** 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() override; + + struct ::wl_resource *resourceForClient(struct ::wl_client *) override; + bool bufferInUse() override; + QOpenGLTexture *toOpenGlTexture() 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; +}; + +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; +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 00000000..18cdaf8a --- /dev/null +++ b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp @@ -0,0 +1,713 @@ +/**************************************************************************** +** +** 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 "vulkanwrapper.h" + +#include <QImage> +#include <QOpenGLContext> +#include <QtGui/qopengl.h> + +#include <vulkan/vulkan.h> +#include <set> + +#include <unistd.h> + +#include <QDebug> + +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); + 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, ®ion); + + 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) +{ + if (m_initFailed) + return nullptr; + + int texWidth = img.width(); + int texHeight = img.height(); + bool ok; + const auto *pixels = img.constBits(); + VkDeviceSize imageSize = img.sizeInBytes(); + 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(imageSize, 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, imageSize, 0, &data); + if (extraDebug) qDebug() << "mapped" << data << imageSize; + memcpy(data, pixels, static_cast<size_t>(imageSize)); + vkUnmapMemory(m_device, stagingBufferMemory); + + if (extraDebug) qDebug() << "creating image..."; + + QScopedPointer<VulkanImageWrapper> imageWrapper(createImage(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, img.size(), imageSize)); + if (imageWrapper.isNull()) + return nullptr; + + if (extraDebug) qDebug() << "transition..."; + + const VkImage textureImage = imageWrapper->textureImage; + + ok = transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, 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, VK_FORMAT_R8G8B8A8_UNORM, 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_A8B8G8R8_SRGB_PACK32; f++) + int f = VK_FORMAT_R8G8B8A8_UNORM; + { + 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); +} + +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); +} diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.h b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.h new file mode 100644 index 00000000..697729bf --- /dev/null +++ b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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); + 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/plugins/hardwareintegration/client/client.pro b/src/plugins/hardwareintegration/client/client.pro index 82e431ee..7b7e8a49 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 00000000..b8f64bf2 --- /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 00000000..baadd152 --- /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 00000000..1be60f7c --- /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 59ea9141..32edf1f1 100644 --- a/src/plugins/hardwareintegration/compositor/compositor.pro +++ b/src/plugins/hardwareintegration/compositor/compositor.pro @@ -20,6 +20,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 00000000..d765dd38 --- /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 00000000..baadd152 --- /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 00000000..05365421 --- /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) |