diff options
author | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2019-10-04 11:25:19 +0200 |
---|---|---|
committer | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2019-10-25 10:09:05 +0200 |
commit | 3d161cef55eacafc4495e3ba0bcb86089c544dc1 (patch) | |
tree | aa3dd33b99f8d1e870a1595b5b14796313976b24 | |
parent | a382762ed9692d11679d769437eba7ff2df544d1 (diff) |
Client: Add Vulkan support for Wayland
Inspired by the xcb version.
hellovulkantriangle runs smootly, but freezes in some multi-monitor
setups.
[ChangeLog][QPA plugin] Added Vulkan support.
Fixes: QTBUG-78000
Change-Id: I8711b5b47e4b71cde78295aab9acb3f5945b141b
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r-- | src/client/client.pro | 14 | ||||
-rw-r--r-- | src/client/qwaylandintegration.cpp | 17 | ||||
-rw-r--r-- | src/client/qwaylandintegration_p.h | 4 | ||||
-rw-r--r-- | src/client/qwaylandnativeinterface.cpp | 12 | ||||
-rw-r--r-- | src/client/qwaylandvulkaninstance.cpp | 132 | ||||
-rw-r--r-- | src/client/qwaylandvulkaninstance_p.h | 80 | ||||
-rw-r--r-- | src/client/qwaylandvulkanwindow.cpp | 84 | ||||
-rw-r--r-- | src/client/qwaylandvulkanwindow_p.h | 68 | ||||
-rw-r--r-- | src/client/qwaylandwindow_p.h | 3 |
9 files changed, 413 insertions, 1 deletions
diff --git a/src/client/client.pro b/src/client/client.pro index d0ae9009e..458e49360 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -5,6 +5,10 @@ QT += core-private gui-private QT_FOR_PRIVATE += service_support-private QT_PRIVATE += fontdatabase_support-private eventdispatcher_support-private theme_support-private +qtConfig(vulkan) { + QT_PRIVATE += vulkan_support-private +} + # We have a bunch of C code with casts, so we can't have this option QMAKE_CXXFLAGS_WARN_ON -= -Wcast-qual @@ -97,6 +101,16 @@ include(shellintegration/shellintegration.pri) include(inputdeviceintegration/inputdeviceintegration.pri) include(global/global.pri) +qtConfig(vulkan) { + HEADERS += \ + qwaylandvulkaninstance_p.h \ + qwaylandvulkanwindow_p.h + + SOURCES += \ + qwaylandvulkaninstance.cpp \ + qwaylandvulkanwindow.cpp +} + qtConfig(cursor) { QMAKE_USE += wayland-cursor diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp index ce72c3340..9bdd9cc12 100644 --- a/src/client/qwaylandintegration.cpp +++ b/src/client/qwaylandintegration.cpp @@ -94,6 +94,11 @@ #include <QtXkbCommonSupport/private/qxkbcommon_p.h> #endif +#if QT_CONFIG(vulkan) +#include "qwaylandvulkaninstance_p.h" +#include "qwaylandvulkanwindow_p.h" +#endif + QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -158,6 +163,11 @@ QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) cons && mDisplay->clientBufferIntegration()) return mDisplay->clientBufferIntegration()->createEglWindow(window); +#if QT_CONFIG(vulkan) + if (window->surfaceType() == QSurface::VulkanSurface) + return new QWaylandVulkanWindow(window); +#endif // QT_CONFIG(vulkan) + return new QWaylandShmWindow(window); } @@ -278,6 +288,13 @@ QPlatformTheme *QWaylandIntegration::createPlatformTheme(const QString &name) co return QGenericUnixTheme::createUnixTheme(name); } +#if QT_CONFIG(vulkan) +QPlatformVulkanInstance *QWaylandIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + return new QWaylandVulkanInstance(instance); +} +#endif // QT_CONFIG(vulkan) + // May be called from non-GUI threads QWaylandClientBufferIntegration *QWaylandIntegration::clientBufferIntegration() const { diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h index a66999c7f..ff70ae25d 100644 --- a/src/client/qwaylandintegration_p.h +++ b/src/client/qwaylandintegration_p.h @@ -113,6 +113,10 @@ public: QPlatformTheme *createPlatformTheme(const QString &name) const override; +#if QT_CONFIG(vulkan) + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; +#endif + QWaylandInputDevice *createInputDevice(QWaylandDisplay *display, int version, uint32_t id); virtual QWaylandClientBufferIntegration *clientBufferIntegration() const; diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp index b4ecc0090..bf54a1a00 100644 --- a/src/client/qwaylandnativeinterface.cpp +++ b/src/client/qwaylandnativeinterface.cpp @@ -51,6 +51,9 @@ #include <QtGui/private/qguiapplication_p.h> #include <QtGui/QScreen> #include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h> +#if QT_CONFIG(vulkan) +#include <QtWaylandClient/private/qwaylandvulkanwindow_p.h> +#endif #include <QtPlatformHeaders/qwaylandwindowfunctions.h> @@ -117,6 +120,15 @@ void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourc if (lowerCaseResource == "egldisplay" && m_integration->clientBufferIntegration()) return m_integration->clientBufferIntegration()->nativeResource(QWaylandClientBufferIntegration::EglDisplay); +#if QT_CONFIG(vulkan) + if (lowerCaseResource == "vksurface") { + if (window->surfaceType() == QSurface::VulkanSurface && window->handle()) { + // return a pointer to the VkSurfaceKHR value, not the value itself + return static_cast<QWaylandVulkanWindow *>(window->handle())->surface(); + } + } +#endif + if (auto shellIntegration = m_integration->shellIntegration()) return shellIntegration->nativeResourceForWindow(resourceString, window); diff --git a/src/client/qwaylandvulkaninstance.cpp b/src/client/qwaylandvulkaninstance.cpp new file mode 100644 index 000000000..5edbd4757 --- /dev/null +++ b/src/client/qwaylandvulkaninstance.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 "qwaylandvulkaninstance_p.h" +#include "qwaylandwindow_p.h" +#include "qwaylandscreen_p.h" +#include "qwaylanddisplay_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +QWaylandVulkanInstance::QWaylandVulkanInstance(QVulkanInstance *instance) + : m_instance(instance) +{ + loadVulkanLibrary(QStringLiteral("vulkan")); +} + +QWaylandVulkanInstance::~QWaylandVulkanInstance() = default; + +void QWaylandVulkanInstance::createOrAdoptInstance() +{ + QByteArrayList extraExtensions; + extraExtensions << QByteArrayLiteral("VK_KHR_wayland_surface"); + initInstance(m_instance, extraExtensions); + + if (!m_vkInst) + return; + + m_getPhysDevPresSupport = reinterpret_cast<PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR>( + m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")); + if (!m_getPhysDevPresSupport) + qWarning() << "Failed to find vkGetPhysicalDeviceWaylandPresentationSupportKHR"; +} + +bool QWaylandVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + QWindow *window) +{ + if (!m_getPhysDevPresSupport || !m_getPhysDevSurfaceSupport) + return true; + + auto *w = static_cast<QWaylandWindow *>(window->handle()); + if (!w) { + qWarning() << "Attempted to call supportsPresent() without a valid platform window"; + return false; + } + wl_display *display = w->display()->wl_display(); + bool ok = m_getPhysDevPresSupport(physicalDevice, queueFamilyIndex, display); + + VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window); + VkBool32 supported = false; + m_getPhysDevSurfaceSupport(physicalDevice, queueFamilyIndex, surface, &supported); + ok &= bool(supported); + + return ok; +} + +VkSurfaceKHR QWaylandVulkanInstance::createSurface(QWaylandWindow *window) +{ + VkSurfaceKHR surface = VK_NULL_HANDLE; + + if (!m_createSurface) { + m_createSurface = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>( + m_vkGetInstanceProcAddr(m_vkInst, "vkCreateWaylandSurfaceKHR")); + } + if (!m_createSurface) { + qWarning() << "Failed to find vkCreateWaylandSurfaceKHR"; + return surface; + } + + VkWaylandSurfaceCreateInfoKHR surfaceInfo; + memset(&surfaceInfo, 0, sizeof(surfaceInfo)); + surfaceInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + surfaceInfo.display = window->display()->wl_display(); + surfaceInfo.surface = window->wlSurface(); + VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface); + if (err != VK_SUCCESS) + qWarning("Failed to create Vulkan surface: %d", err); + + return surface; +} + +void QWaylandVulkanInstance::presentAboutToBeQueued(QWindow *window) +{ + auto *w = static_cast<QWaylandWindow *>(window->handle()); + if (!w) { + qWarning() << "Attempted to call presentAboutToBeQueued() without a valid platform window"; + return; + } + w->handleUpdate(); +} + +} // namespace QtWaylandClient + +QT_END_NAMESPACE diff --git a/src/client/qwaylandvulkaninstance_p.h b/src/client/qwaylandvulkaninstance_p.h new file mode 100644 index 000000000..b68293b78 --- /dev/null +++ b/src/client/qwaylandvulkaninstance_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 QWAYLANDVULKANINSTANCE_P_H +#define QWAYLANDVULKANINSTANCE_P_H + +#if defined(VULKAN_H_) && !defined(VK_USE_PLATFORM_WAYLAND_KHR) +#error "vulkan.h included without Wayland WSI" +#endif + +#define VK_USE_PLATFORM_WAYLAND_KHR + +#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h> +#include <QLibrary> + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +class QWaylandWindow; + +class QWaylandVulkanInstance : public QBasicPlatformVulkanInstance +{ +public: + explicit QWaylandVulkanInstance(QVulkanInstance *instance); + ~QWaylandVulkanInstance() override; + + void createOrAdoptInstance() override; + bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override; + void presentAboutToBeQueued(QWindow *window) override; + + VkSurfaceKHR createSurface(QWaylandWindow *window); + +private: + QVulkanInstance *m_instance = nullptr; + PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR m_getPhysDevPresSupport = nullptr; + PFN_vkCreateWaylandSurfaceKHR m_createSurface = nullptr; +}; + +} // namespace QtWaylandClient + +QT_END_NAMESPACE + +#endif // QWAYLANDVULKANINSTANCE_P_H diff --git a/src/client/qwaylandvulkanwindow.cpp b/src/client/qwaylandvulkanwindow.cpp new file mode 100644 index 000000000..4c67b6b32 --- /dev/null +++ b/src/client/qwaylandvulkanwindow.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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 "qwaylandvulkanwindow_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +QWaylandVulkanWindow::QWaylandVulkanWindow(QWindow *window) + : QWaylandWindow(window) +{ +} + +QWaylandVulkanWindow::~QWaylandVulkanWindow() +{ + if (m_surface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + static_cast<QWaylandVulkanInstance *>(inst->handle())->destroySurface(m_surface); + } +} + +QWaylandWindow::WindowType QWaylandVulkanWindow::windowType() const +{ + return QWaylandWindow::Vulkan; +} + +VkSurfaceKHR *QWaylandVulkanWindow::surface() +{ + if (m_surface) + return &m_surface; + + QVulkanInstance *vulkanInstance = window()->vulkanInstance(); + if (!vulkanInstance) { + qWarning() << "Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?"; + return nullptr; + } + + auto *waylandVulkanInstance = static_cast<QWaylandVulkanInstance *>(vulkanInstance->handle()); + m_surface = waylandVulkanInstance->createSurface(this); + + return &m_surface; +} + +} // namespace QtWaylandClient + +QT_END_NAMESPACE diff --git a/src/client/qwaylandvulkanwindow_p.h b/src/client/qwaylandvulkanwindow_p.h new file mode 100644 index 000000000..d0b2de75d --- /dev/null +++ b/src/client/qwaylandvulkanwindow_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 QWAYLANDVULKANWINDOW_P_H +#define QWAYLANDVULKANWINDOW_P_H + +#include "qwaylandwindow_p.h" +#include "qwaylandvulkaninstance_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +class QWaylandVulkanWindow : public QWaylandWindow +{ +public: + explicit QWaylandVulkanWindow(QWindow *window); + ~QWaylandVulkanWindow() override; + + WindowType windowType() const override; + + VkSurfaceKHR *surface(); + +private: + VkSurfaceKHR m_surface = VK_NULL_HANDLE; +}; + +} // namespace QtWaylandClient + +QT_END_NAMESPACE + +#endif // QWAYLANDVULKANWINDOW_P_H diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 52e57c72a..8d582eb7e 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -89,7 +89,8 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformW public: enum WindowType { Shm, - Egl + Egl, + Vulkan }; QWaylandWindow(QWindow *window); |