From f1a23a546720e4f1541404185ff8e765463e6bf6 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 31 Jan 2017 15:04:33 +0100 Subject: [PATCH] Basic Vulkan enablers For Android, Windows and xcb. Verified on Win10 with NVIDIA, Win10 with AMD, Android with Tegra K1, Android aarch64 with Tegra X1, and Linux aarch64 with Tegra X1 (Jetson TX1, L4T). Introduce QPA-based Vulkan library loader, core function resolver, and instance creation support. In addition to creating a new VkInstance, adopting an existing one from an external engine is supported as well. The WSI specifics are hidden in the platform plugins. Vulkan-capable windows use the new surface type VulkanSurface and are associated with a QVulkanInstance. On Windows VULKAN_SDK is picked up automatically so finding vulkan.h needs no additional manual steps once the LunarG SDK is installed. [ChangeLog][QtGui] Added support for rendering to QWindow via the Vulkan graphics API. Task-number: QTBUG-55981 Change-Id: I50fa92d313fa440e0cc73939c6d7510ca317fbc9 Reviewed-by: Qt CI Bot Reviewed-by: Oswald Buddenhagen Reviewed-by: Andy Nichols --- config.tests/qpa/vulkan/vulkan.cpp | 58 + config.tests/qpa/vulkan/vulkan.pro | 1 + mkspecs/common/linux.conf | 1 + mkspecs/common/msvc-desktop.conf | 1 + mkspecs/common/windows-vulkan.conf | 5 + mkspecs/win32-g++/qmake.conf | 1 + mkspecs/win32-icc/qmake.conf | 1 + src/gui/configure.json | 15 + src/gui/gui.pro | 1 + src/gui/kernel/qplatformintegration.cpp | 22 + src/gui/kernel/qplatformintegration.h | 6 + src/gui/kernel/qsurface.cpp | 2 + src/gui/kernel/qsurface.h | 1 + src/gui/kernel/qwindow.cpp | 24 + src/gui/kernel/qwindow.h | 8 + src/gui/kernel/qwindow_p.h | 7 + src/gui/vulkan/qplatformvulkaninstance.cpp | 88 + src/gui/vulkan/qplatformvulkaninstance.h | 91 + src/gui/vulkan/qvulkanfunctions.cpp | 177 + src/gui/vulkan/qvulkaninstance.cpp | 836 +++ src/gui/vulkan/qvulkaninstance.h | 163 + src/gui/vulkan/vk.xml | 5269 +++++++++++++++++ src/gui/vulkan/vulkan.pri | 47 + src/platformsupport/platformsupport.pro | 3 + .../qbasicvulkanplatforminstance.cpp | 357 ++ .../qbasicvulkanplatforminstance_p.h | 106 + .../vkconvenience/vkconvenience.pro | 16 + src/plugins/platforms/android/android.pro | 9 + .../android/qandroidplatformintegration.cpp | 36 + .../android/qandroidplatformintegration.h | 7 + .../qandroidplatformvulkaninstance.cpp | 66 + .../android/qandroidplatformvulkaninstance.h | 63 + .../android/qandroidplatformvulkanwindow.cpp | 210 + .../android/qandroidplatformvulkanwindow.h | 91 + src/plugins/platforms/direct2d/direct2d.pro | 2 + .../platforms/windows/qwindowsintegration.cpp | 7 + .../platforms/windows/qwindowsintegration.h | 4 + .../windows/qwindowsnativeinterface.cpp | 12 +- .../windows/qwindowsvulkaninstance.cpp | 136 + .../windows/qwindowsvulkaninstance.h | 76 + .../platforms/windows/qwindowswindow.cpp | 72 +- .../platforms/windows/qwindowswindow.h | 10 + src/plugins/platforms/windows/windows.pri | 5 + src/plugins/platforms/windows/windows.pro | 2 + src/plugins/platforms/xcb/qxcbintegration.cpp | 26 +- src/plugins/platforms/xcb/qxcbintegration.h | 4 + .../platforms/xcb/qxcbnativeinterface.cpp | 15 +- .../platforms/xcb/qxcbnativeinterface.h | 3 +- .../platforms/xcb/qxcbvulkaninstance.cpp | 156 + .../platforms/xcb/qxcbvulkaninstance.h | 79 + .../platforms/xcb/qxcbvulkanwindow.cpp | 83 + src/plugins/platforms/xcb/qxcbvulkanwindow.h | 65 + src/plugins/platforms/xcb/xcb_qpa_lib.pro | 12 + src/src.pro | 8 + src/tools/qvkgen/qvkgen.cpp | 530 ++ src/tools/qvkgen/qvkgen.pro | 5 + sync.profile | 7 +- tests/auto/gui/gui.pro | 3 + tests/auto/gui/qvulkan/qvulkan.pro | 9 + tests/auto/gui/qvulkan/tst_qvulkan.cpp | 159 + tests/manual/manual.pro | 2 + tests/manual/qvulkaninstance/main.cpp | 713 +++ .../qvulkaninstance/qvulkaninstance.pro | 6 + 63 files changed, 9981 insertions(+), 19 deletions(-) create mode 100644 config.tests/qpa/vulkan/vulkan.cpp create mode 100644 config.tests/qpa/vulkan/vulkan.pro create mode 100644 mkspecs/common/windows-vulkan.conf create mode 100644 src/gui/vulkan/qplatformvulkaninstance.cpp create mode 100644 src/gui/vulkan/qplatformvulkaninstance.h create mode 100644 src/gui/vulkan/qvulkanfunctions.cpp create mode 100644 src/gui/vulkan/qvulkaninstance.cpp create mode 100644 src/gui/vulkan/qvulkaninstance.h create mode 100644 src/gui/vulkan/vk.xml create mode 100644 src/gui/vulkan/vulkan.pri create mode 100644 src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp create mode 100644 src/platformsupport/vkconvenience/qbasicvulkanplatforminstance_p.h create mode 100644 src/platformsupport/vkconvenience/vkconvenience.pro create mode 100644 src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp create mode 100644 src/plugins/platforms/android/qandroidplatformvulkaninstance.h create mode 100644 src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp create mode 100644 src/plugins/platforms/android/qandroidplatformvulkanwindow.h create mode 100644 src/plugins/platforms/windows/qwindowsvulkaninstance.cpp create mode 100644 src/plugins/platforms/windows/qwindowsvulkaninstance.h create mode 100644 src/plugins/platforms/xcb/qxcbvulkaninstance.cpp create mode 100644 src/plugins/platforms/xcb/qxcbvulkaninstance.h create mode 100644 src/plugins/platforms/xcb/qxcbvulkanwindow.cpp create mode 100644 src/plugins/platforms/xcb/qxcbvulkanwindow.h create mode 100644 src/tools/qvkgen/qvkgen.cpp create mode 100644 src/tools/qvkgen/qvkgen.pro create mode 100644 tests/auto/gui/qvulkan/qvulkan.pro create mode 100644 tests/auto/gui/qvulkan/tst_qvulkan.cpp create mode 100644 tests/manual/qvulkaninstance/main.cpp create mode 100644 tests/manual/qvulkaninstance/qvulkaninstance.pro diff --git a/config.tests/qpa/vulkan/vulkan.cpp b/config.tests/qpa/vulkan/vulkan.cpp new file mode 100644 index 0000000000..22f5edf9f2 --- /dev/null +++ b/config.tests/qpa/vulkan/vulkan.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the config.tests 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$ +** +****************************************************************************/ + +// This is a header-only test. Qt does not rely on linking to a Vulkan library directly. + +#include + +// The pData parameter has changed from uint32_t* to void* at some point. +// Ensure the headers have the updated one to prevent compile errors later on. +PFN_vkCmdUpdateBuffer cmdUpdBuf; +void testUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData) +{ + cmdUpdBuf(commandBuffer, dstBuffer, dstOffset, dataSize, pData); +} + +int main(int, char **) +{ + VkInstanceCreateInfo info; + testUpdateBuffer(0, 0, 0, 0, 0); + + return 0; +} diff --git a/config.tests/qpa/vulkan/vulkan.pro b/config.tests/qpa/vulkan/vulkan.pro new file mode 100644 index 0000000000..5f05bc49aa --- /dev/null +++ b/config.tests/qpa/vulkan/vulkan.pro @@ -0,0 +1 @@ +SOURCES = vulkan.cpp diff --git a/mkspecs/common/linux.conf b/mkspecs/common/linux.conf index 13916a5646..5e2b5b59eb 100644 --- a/mkspecs/common/linux.conf +++ b/mkspecs/common/linux.conf @@ -35,6 +35,7 @@ QMAKE_LIBS_OPENGL = -lGL QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 QMAKE_LIBS_OPENVG = -lOpenVG QMAKE_LIBS_THREAD = -lpthread +QMAKE_LIBS_VULKAN = QMAKE_INCDIR_WAYLAND = QMAKE_LIBS_WAYLAND_CLIENT = -lwayland-client diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf index 0ca27fe4ec..bd9098d7f1 100644 --- a/mkspecs/common/msvc-desktop.conf +++ b/mkspecs/common/msvc-desktop.conf @@ -106,3 +106,4 @@ VCSOLUTION_EXTENSION = .sln VCPROJ_KEYWORD = Qt4VSv1.0 include(windows-gles.conf) +include(windows-vulkan.conf) diff --git a/mkspecs/common/windows-vulkan.conf b/mkspecs/common/windows-vulkan.conf new file mode 100644 index 0000000000..c928a8f315 --- /dev/null +++ b/mkspecs/common/windows-vulkan.conf @@ -0,0 +1,5 @@ +# Pick up the VULKAN_SDK env var set by the LunarG SDK so that the Vulkan +# headers are found out-of-the-box on typical Windows setups. + +QMAKE_INCDIR_VULKAN = $(VULKAN_SDK)\\include +QMAKE_LIBS_VULKAN = diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf index 5f98bd1d03..224c81fb4a 100644 --- a/mkspecs/win32-g++/qmake.conf +++ b/mkspecs/win32-g++/qmake.conf @@ -80,6 +80,7 @@ QMAKE_OBJCOPY = $${CROSS_COMPILE}objcopy QMAKE_NM = $${CROSS_COMPILE}nm -P include(../common/windows-gles.conf) +include(../common/windows-vulkan.conf) include(../common/gcc-base.conf) load(qt_config) diff --git a/mkspecs/win32-icc/qmake.conf b/mkspecs/win32-icc/qmake.conf index 9a86407043..171145690e 100644 --- a/mkspecs/win32-icc/qmake.conf +++ b/mkspecs/win32-icc/qmake.conf @@ -59,5 +59,6 @@ QMAKE_LIB = xilib /NOLOGO DSP_EXTENSION = .dsp include(../common/windows-gles.conf) +include(../common/windows-vulkan.conf) load(qt_config) diff --git a/src/gui/configure.json b/src/gui/configure.json index a8ae656bcb..6e1af4521d 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -38,6 +38,7 @@ "qpa-platform-guard": "boolean", "sm": { "type": "boolean", "name": "sessionmanager" }, "tslib": "boolean", + "vulkan": "boolean", "xcb": { "type": "enum", "values": [ "no", "yes", "qt", "system" ] }, "xcb-xlib": "boolean", "xinput2": "boolean", @@ -211,6 +212,14 @@ "-lts" ] }, + "vulkan": { + "label": "Vulkan", + "test": "qpa/vulkan", + "sources": [ + { "type": "pkgConfig", "args": "vulkan" }, + { "type": "makeSpec", "spec": "VULKAN" } + ] + }, "wayland_server": { "label": "Wayland Server", "test": "qpa/wayland-server", @@ -605,6 +614,11 @@ "condition": "features.opengl-desktop || features.opengl-dynamic || features.opengles2", "output": [ "publicFeature", "feature" ] }, + "vulkan": { + "label": "Vulkan", + "condition": "libs.vulkan", + "output": [ "publicFeature" ] + }, "openvg": { "label": "OpenVG", "condition": "libs.openvg", @@ -1096,6 +1110,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla "opengles31" ] }, + "vulkan", "sessionmanager" ] }, diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 511cfd1d22..0682fd2274 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -46,6 +46,7 @@ include(math3d/math3d.pri) include(opengl/opengl.pri) include(animation/animation.pri) include(itemmodels/itemmodels.pri) +include(vulkan/vulkan.pri) QMAKE_LIBS += $$QMAKE_LIBS_GUI diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 9673ad673a..873ec3a33b 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -629,4 +629,26 @@ void QPlatformIntegration::setApplicationIcon(const QIcon &icon) const Q_UNUSED(icon); } +#if QT_CONFIG(vulkan) + +/*! + Factory function for QPlatformVulkanInstance. The \a instance parameter is a + pointer to the instance for which a platform-specific backend needs to be + created. + + Returns a pointer to a QPlatformOpenGLContext instance or \c NULL if the context could + not be created. + + \sa QVulkanInstance + \since 5.10 +*/ +QPlatformVulkanInstance *QPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + Q_UNUSED(instance); + qWarning("This plugin does not support createPlatformVulkanInstance"); + return nullptr; +} + +#endif // QT_CONFIG(vulkan) + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index 49d41dd576..eeaa7574f7 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -78,6 +78,8 @@ class QPlatformSessionManager; class QKeyEvent; class QPlatformOffscreenSurface; class QOffscreenSurface; +class QPlatformVulkanInstance; +class QVulkanInstance; class Q_GUI_EXPORT QPlatformIntegration { @@ -190,6 +192,10 @@ public: virtual void beep() const; +#if QT_CONFIG(vulkan) + virtual QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const; +#endif + protected: void screenAdded(QPlatformScreen *screen, bool isPrimary = false); void destroyScreen(QPlatformScreen *screen); diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp index 3cdd11de8c..63651ee822 100644 --- a/src/gui/kernel/qsurface.cpp +++ b/src/gui/kernel/qsurface.cpp @@ -78,6 +78,8 @@ QT_BEGIN_NAMESPACE requires the use of private API. \value OpenVGSurface The surface is an OpenVG compatible surface and can be used in conjunction with OpenVG contexts. + \value VulkanSurface The surface is a Vulkan compatible surface and can be used + in conjunction with the Vulkan graphics API. */ diff --git a/src/gui/kernel/qsurface.h b/src/gui/kernel/qsurface.h index a96b7a6422..7e09449d12 100644 --- a/src/gui/kernel/qsurface.h +++ b/src/gui/kernel/qsurface.h @@ -66,6 +66,7 @@ public: OpenGLSurface, RasterGLSurface, OpenVGSurface, + VulkanSurface }; virtual ~QSurface(); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 887d79f455..8471102aee 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2797,6 +2797,30 @@ QDebug operator<<(QDebug debug, const QWindow *window) } #endif // !QT_NO_DEBUG_STREAM +#if QT_CONFIG(vulkan) + +/*! + Associates this window with the specified Vulkan \a instance. + + \a instance must stay valid as long as this QWindow instance exists. + */ +void QWindow::setVulkanInstance(QVulkanInstance *instance) +{ + Q_D(QWindow); + d->vulkanInstance = instance; +} + +/*! + \return the associrated Vulkan instance or \c null if there is none. + */ +QVulkanInstance *QWindow::vulkanInstance() const +{ + Q_D(const QWindow); + return d->vulkanInstance; +} + +#endif // QT_CONFIG(vulkan) + QT_END_NAMESPACE #include "moc_qwindow.cpp" diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index 033678cf5a..529589e67b 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -88,6 +88,9 @@ class QWindowContainer; #ifndef QT_NO_DEBUG_STREAM class QDebug; #endif +#if QT_CONFIG(vulkan) +class QVulkanInstance; +#endif class Q_GUI_EXPORT QWindow : public QObject, public QSurface { @@ -269,6 +272,11 @@ public: static QWindow *fromWinId(WId id); +#if QT_CONFIG(vulkan) + void setVulkanInstance(QVulkanInstance *instance); + QVulkanInstance *vulkanInstance() const; +#endif + public Q_SLOTS: Q_REVISION(1) void requestActivate(); diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index a3b39fb9ca..e8d5830eee 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -105,6 +105,9 @@ public: , hasCursor(false) #endif , compositing(false) +#if QT_CONFIG(vulkan) + , vulkanInstance(nullptr) +#endif { isWindow = true; } @@ -196,6 +199,10 @@ public: bool compositing; QElapsedTimer lastComposeTime; + +#if QT_CONFIG(vulkan) + QVulkanInstance *vulkanInstance; +#endif }; diff --git a/src/gui/vulkan/qplatformvulkaninstance.cpp b/src/gui/vulkan/qplatformvulkaninstance.cpp new file mode 100644 index 0000000000..6201d3ec11 --- /dev/null +++ b/src/gui/vulkan/qplatformvulkaninstance.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui 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 "qplatformvulkaninstance.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QPlatformVulkanInstance + \since 5.10 + \internal + \preliminary + \ingroup qpa + + \brief The QPlatformVulkanInstance class provides an abstraction for Vulkan instances. + + The platform Vulkan instance is responsible for loading a Vulkan library, + resolving the basic entry points for creating instances, providing support + for creating new or adopting existing VkInstances, and abstracting some + WSI-specifics like checking if a given queue family can be used to present + using a given window. + + \note platform plugins will typically subclass not this class, but rather + QBasicVulkanPlatformInstance. + + \note Vulkan instance creation is split into two phases: a new + QPlatformVulkanInstance is expected to load the Vulkan library and do basic + initialization, after which the supported layers and extensions can be + queried. Everything else is deferred into createOrAdoptInstance(). +*/ + +class QPlatformVulkanInstancePrivate +{ +public: + QPlatformVulkanInstancePrivate() { } +}; + +QPlatformVulkanInstance::QPlatformVulkanInstance() + : d_ptr(new QPlatformVulkanInstancePrivate) +{ +} + +QPlatformVulkanInstance::~QPlatformVulkanInstance() +{ +} + +void QPlatformVulkanInstance::presentQueued(QWindow *window) +{ + Q_UNUSED(window); +} + +QT_END_NAMESPACE diff --git a/src/gui/vulkan/qplatformvulkaninstance.h b/src/gui/vulkan/qplatformvulkaninstance.h new file mode 100644 index 0000000000..5513d1767d --- /dev/null +++ b/src/gui/vulkan/qplatformvulkaninstance.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui 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 QPLATFORMVULKANINSTANCE_H +#define QPLATFORMVULKANINSTANCE_H + +// +// W A R N I N G +// ------------- +// +// This file is part of the QPA API and is not meant to be used +// in applications. Usage of this API may make your code +// source and binary incompatible with future versions of Qt. +// + +#include + +#if QT_CONFIG(vulkan) + +#include + +QT_BEGIN_NAMESPACE + +class QPlatformVulkanInstancePrivate; + +class Q_GUI_EXPORT QPlatformVulkanInstance +{ + Q_DECLARE_PRIVATE(QPlatformVulkanInstance) + +public: + QPlatformVulkanInstance(); + virtual ~QPlatformVulkanInstance(); + + virtual QVulkanInfoVector supportedLayers() const = 0; + virtual QVulkanInfoVector supportedExtensions() const = 0; + virtual void createOrAdoptInstance() = 0; + virtual bool isValid() const = 0; + virtual VkResult errorCode() const = 0; + virtual VkInstance vkInstance() const = 0; + virtual QByteArrayList enabledLayers() const = 0; + virtual QByteArrayList enabledExtensions() const = 0; + virtual PFN_vkVoidFunction getInstanceProcAddr(const char *name) = 0; + virtual bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) = 0; + virtual void presentQueued(QWindow *window); + +private: + QScopedPointer d_ptr; + Q_DISABLE_COPY(QPlatformVulkanInstance) +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(vulkan) + +#endif // QPLATFORMVULKANINSTANCE_H diff --git a/src/gui/vulkan/qvulkanfunctions.cpp b/src/gui/vulkan/qvulkanfunctions.cpp new file mode 100644 index 0000000000..c342535780 --- /dev/null +++ b/src/gui/vulkan/qvulkanfunctions.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui 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 "qvulkanfunctions_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVulkanFunctions + \since 5.10 + \ingroup painting-3D + \inmodule QtGui + \wrapper + + \brief The QVulkanFunctions class provides cross-platform access to the + instance level core Vulkan 1.0 API. + + Qt and Qt applications do not link to any Vulkan libraries by default. + Instead, all functions are resolved dynamically at run time. Each + QVulkanInstance provides a QVulkanFunctions object retrievable via + QVulkanInstance::functions(). This does not contain device level functions + in order to avoid the potential overhead of an internal dispatching. + Instead, functions that rely on a device, or a dispatchable child object of + a device, are exposed via QVulkanDeviceFunctions and + QVulkanInstance::deviceFunctions(). QVulkanFunctions and + QVulkanDeviceFunctions together provides access to the full core Vulkan + API, excluding any extensions. + + \note QVulkanFunctions instances cannot be constructed directly. + + The typical usage is the following: + + \code + void Window::render() + { + QVulkanInstance *inst = vulkanInstance(); + QVulkanFunctions *f = inst->functions(); + ... + VkResult err = f->vkAllocateCommandBuffers(device, &cmdBufInfo, &cmdBuf); + ... + } + \endcode + + \note Windowing system interface (WSI) specifics and extensions are + excluded. This class only covers core Vulkan commands, with the exception + of instance creation, destruction, and function resolving, since such + functionality is covered by QVulkanInstance itself. + + To access additional functions, applications can use + QVulkanInstance::getInstanceProcAddr() and vkGetDeviceProcAddr(). + Applications can also decide to link to a Vulkan library directly, as + platforms with an appropriate loader will typically export function symbols + for the core commands. See + \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html}{the + man page for vkGetInstanceProcAddr} for more information. + + \sa QVulkanInstance, QVulkanDeviceFunctions, QWindow::setVulkanInstance(), QWindow::setSurfaceType() +*/ + +/*! + \class QVulkanDeviceFunctions + \since 5.10 + \ingroup painting-3D + \inmodule QtGui + \wrapper + + \brief The QVulkanDeviceFunctions class provides cross-platform access to + the device level core Vulkan 1.0 API. + + Qt and Qt applications do not link to any Vulkan libraries by default. + Instead, all functions are resolved dynamically at run time. Each + QVulkanInstance provides a QVulkanFunctions object retrievable via + QVulkanInstance::functions(). This does not contain device level functions + in order to avoid the potential overhead of an internal dispatching. + Instead, functions that rely on a device, or a dispatchable child object of + a device, are exposed via QVulkanDeviceFunctions and + QVulkanInstance::deviceFunctions(). QVulkanFunctions and + QVulkanDeviceFunctions together provides access to the full core Vulkan + API, excluding any extensions. + + \note QVulkanDeviceFunctions instances cannot be constructed directly. + + The typical usage is the following: + + \code + void Window::render() + { + QVulkanInstance *inst = vulkanInstance(); + QVulkanDeviceFunctions *df = inst->deviceFunctions(device); + VkResult err = df->vkAllocateCommandBuffers(device, &cmdBufInfo, &cmdBuf); + ... + } + \endcode + + The QVulkanDeviceFunctions object specific to the provided VkDevice is + created when QVulkanInstance::deviceFunctions() is first called with the + device in question. The object is then cached internally. + + To access additional functions, applications can use + QVulkanInstance::getInstanceProcAddr() and vkGetDeviceProcAddr(). + Applications can also decide to link to a Vulkan library directly, as many + implementations export function symbols for the core commands. See + \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html}{the + man page for vkGetInstanceProcAddr} for more information. + + \sa QVulkanInstance, QVulkanFunctions, QWindow::setVulkanInstance(), QWindow::setSurfaceType() +*/ + +/* + Constructs a new QVulkanFunctions for \a inst. + \internal + */ +QVulkanFunctions::QVulkanFunctions(QVulkanInstance *inst) + : d_ptr(new QVulkanFunctionsPrivate(inst)) +{ +} + +/* + Destructor. + */ +QVulkanFunctions::~QVulkanFunctions() +{ +} + +/* + Constructs a new QVulkanDeviceFunctions for \a inst and the given \a device. + \internal + */ +QVulkanDeviceFunctions::QVulkanDeviceFunctions(QVulkanInstance *inst, VkDevice device) + : d_ptr(new QVulkanDeviceFunctionsPrivate(inst, device)) +{ +} + +/* + Destructor. + */ +QVulkanDeviceFunctions::~QVulkanDeviceFunctions() +{ +} + +QT_END_NAMESPACE diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp new file mode 100644 index 0000000000..c58b9fe916 --- /dev/null +++ b/src/gui/vulkan/qvulkaninstance.cpp @@ -0,0 +1,836 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui 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 "qvulkaninstance.h" +#include "qvulkanfunctions_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QVulkanInstance + \since 5.10 + \inmodule QtGui + + \brief The QVulkanInstance class represents a native Vulkan instance, enabling + Vulkan rendering onto a QSurface. + + \l{https://www.khronos.org/vulkan/}{Vulkan} is a cross-platform, explicit + graphics and compute API. This class provides support for loading a Vulkan + library and creating an \c instance in a cross-platform manner. For an + introduction on Vulkan instances, refer + \l{https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#initialization-instances}{to + section 3.2 of the specification}. + + \note Platform-specific support for Vulkan instances and windows with + Vulkan-capable surfaces is provided by the various platform plugins. Not + all of them will support Vulkan, however. When running on such a platform, + create() will fail and always return \c false. + + \note Vulkan support may get automatically disabled for a given Qt build due + to not having the necessary Vulkan headers available at build time. When + this is the case, and the output of \c configure indicates Vulkan support is + disabled, the QVulkan* classes will be unavailable. + + \note Some functions changed their signature between the various Vulkan + header revisions. When building Qt and only headers with the old, + conflicting signatures are present in a system, Vulkan support will get + disabled. It is recommended to use headers from Vulkan 1.0.39 or newer. + + \section1 Initialization + + Similarly to QOpenGLContext, any actual Vulkan instance creation happens + only when calling create(). This allows using QVulkanInstance as a plain + member variable while retaining control over when to perform + initialization. + + Querying the supported instance-level layers and extensions is possible by + calling supportedLayers() and supportedExtensions(). These ensure the + Vulkan library is loaded, and can therefore be called safely before + create() as well. + + Instances store per-application Vulkan state and creating a \c VkInstance + object initializes the Vulkan library. In practice there will typically be + a single instance constructed early on in main(). The object then stays + alive until exiting the application. + + Every Vulkan-based QWindow must be associated with a QVulkanInstance by + calling QWindow::setVulkanInstance(). Thus a typical application pattern is + the following: + + \code + int main(int argc, char **argv) + { + QGuiApplication app(argc, argv); + + QVulkanInstance inst; + if (!inst.create()) + return 1; + + ... + window->setVulkanInstance(&inst); + window->show(); + + return app.exec(); + } + \endcode + + \section1 Configuration + + QVulkanInstance automatically enables the minimum set of extensions it + needs on the newly created instance. In practice this means the + \c{VK_KHR_*_surface} family of extensions. + + By default Vulkan debug output, for example messages from the validation + layers, is routed to qDebug(). This can be disabled by passing the flag + \c NoDebugOutputRedirect to setFlags() before invoking create(). + + To enable additional layers and extensions, provide the list via + setLayers() and setExtensions() before invoking create(). When a + given layer or extension is not reported as available from the instance, + the request is ignored. After a successful call to create(), the values + returned from functions like layers() and extensions() reflect the actual + enabled layers and extensions. When necessary, for example to avoid + requesting extensions that conflict and thus would fail the Vulkan instance + creation, the list of actually supported layers and extensions can be + examined via supportedLayers() and supportedExtensions() before calling + create(). + + For example, to enable the standard validation layers, one could do the + following: + + \code + QVulkanInstance inst; + + // Enable validation layer, if supported. Messages go to qDebug by default. + inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation"); + + bool ok = inst.create(); + if (!ok) + ... // Vulkan not available + if (!inst.layers().contains("VK_LAYER_LUNARG_standard_validation")) + ... // validation layer not available + \endcode + + Or, alternatively, to make decisions before attempting to create a Vulkan + instance: + + \code + QVulkanInstance inst; + + if (inst.supportedLayers().contains("VK_LAYER_LUNARG_standard_validation")) + ... + + bool ok = inst.create(); + ... + \endcode + + \section1 Adopting an Existing Instance + + By default QVulkanInstance creates a new Vulkan instance. When working with + external engines and renderers, this may sometimes not be desirable. When + there is a \c VkInstance handle already available, call setVkInstance() + before invoking create(). This way no additional instances will get + created, and QVulkanInstance will not own the handle. + + \note It is up to the component creating the external instance to ensure + the necessary extensions are enabled on it. These are: \c{VK_KHR_surface}, + the WSI-specific \c{VK_KHR_*_surface} that is appropriate for the platform + in question, and \c{VK_EXT_debug_report} in case QVulkanInstance's debug + output redirection is desired. + + \section1 Accessing Core Vulkan Commands + + To access the \c VkInstance handle the QVulkanInstance wraps, call + vkInstance(). To resolve Vulkan functions, call getInstanceProcAddr(). For + core Vulkan commands manual resolving is not necessary as they are provided + via the QVulkanFunctions object accessible by calling functions(). + + \section1 Getting a Native Vulkan Surface for a Window + + The two common windowing system specific operations are getting a surface + (a \c{VkSurfaceKHR} handle) for a window, and querying if a given queue + family supports presenting to a given surface. To avoid WSI-specific bits + in the applications, these are abstracted by QVulkanInstance and the + underlying QPA layers. + + To create a Vulkan surface for a window, or retrieve an existing one, + call surfaceForWindow(). Most platforms will only create the surface via + \c{VK_KHR_*_surface} when first calling surfaceForWindow(), but there may be + platform-specific variations in the internal behavior. Once created, + subsequent calls to surfaceForWindow() just return the same handle. This + fits the structure of typical Vulkan-enabled QWindow subclasses well. + + To query if a given queue family within a physical device can be used to + perform presentation to a given surface, call supportsPresent(). This + encapsulates both the generic \c vkGetPhysicalDeviceSurfaceSupportKHR and + the WSI-specific \c{vkGetPhysicalDevice*PresentationSupportKHR} checks. + + \section1 Troubleshooting + + Besides returning \c false from create() or \c 0 from surfaceForWindow(), + critical errors will also get printed to the debug output via qWarning(). + Additional logging can be requested by enabling debug output for the + logging category \c{qt.vulkan}. The actual Vulkan error code from instance + creation can be retrieved by calling errorCode() after a failing create(). + + In some special cases it may be necessary to override the Vulkan + library name. This can be achieved by setting the \c{QT_VULKAN_LIB} + environment variable. + + \section1 Example + + The following is the basic outline of creating a Vulkan-capable QWindow: + + \code + class VulkanWindow : public QWindow + { + public: + VulkanWindow() { + setSurfaceType(VulkanSurface); + } + + void exposeEvent(QExposeEvent *) { + if (isExposed()) { + if (!m_initialized) { + m_initialized = true; + // initialize device, swapchain, etc. + QVulkanInstance *inst = vulkanInstance(); + QVulkanFunctions *f = inst->functions(); + uint32_t devCount = 0; + f->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, nullptr); + ... + // build the first frame + render(); + } + } + } + + bool event(QEvent *e) { + if (e->type == QEvent::UpdateRequest) + render(); + return QWindow::event(e); + } + + void render() { + ... + requestUpdate(); // render continuously + } + + private: + bool m_initialized = false; + }; + + int main(int argc, char **argv) + { + QGuiApplication app(argc, argv); + + QVulkanInstance inst; + if (!inst.create()) { + qWarning("Vulkan not available"); + return 1; + } + + VulkanWindow window; + window.showMaximized(); + + return app.exec(); + + } + \endcode + + \note In addition to expose, a well-behaving window implementation will + also have to take care of additional events like resize and + QPlatformSurfaceEvent in order to ensure proper management of the + swap chain. Additionally, some platforms may require releasing resources + when not being exposed anymore. + + \section1 Using C++ Bindings for Vulkan + + Combining Qt's Vulkan enablers with a C++ Vulkan wrapper, for example + \l{https://github.com/KhronosGroup/Vulkan-Hpp}{Vulkan-Hpp}, is possible as + well. The pre-requisite here is that the C++ layer must be able to adopt + native handles (VkInstance, VkSurfaceKHR) in its classes without taking + ownership (since the ownership stays with QVulkanInstance and QWindow). + Consider also the following: + + \list + + \li Some wrappers require exception support to be enabled. Qt does not use + exceptions. To enable exceptions for the application, add \c{CONFIG += exceptions} + to the \c{.pro} file. + + \li Some wrappers call Vulkan functions directly, assuming \c{vulkan.h} + provides prototypes and the application links to a Vulkan library exporting + all necessary symbols. Qt may not directly link to a Vulkan library. + Therefore, on some platforms it may be necessary to add + \c{LIBS += -lvulkan} or similar in the application's \c{.pro} file. + + \li The headers for the QVulkan classes may include \c{vulkan.h} with + \c{VK_NO_PROTOTYPES} enabled. This can cause issues in C++ wrapper headers + that rely on the prototypes. Hence in application code it may be + necessary to include \c{vulkan.hpp} or similar before any of the QVulkan + headers. + + \endlist + + \sa QVulkanFunctions, QSurface::SurfaceType +*/ + +/*! + \enum QVulkanInstance::Flag + \since 5.10 + + This enum describes the flags that can be passed to setFlags(). These control + the behavior of create(). + + \value NoDebugOutputRedirect Disables Vulkan debug output (\c{VK_EXT_debug_report}) redirection to qDebug. +*/ + +class QVulkanInstancePrivate +{ +public: + QVulkanInstancePrivate(QVulkanInstance *q) + : q_ptr(q), + vkInst(VK_NULL_HANDLE), + flags(0), + errorCode(VK_SUCCESS) + { } + ~QVulkanInstancePrivate() { reset(); } + + bool ensureVulkan(); + void reset(); + + QVulkanInstance *q_ptr; + QScopedPointer platformInst; + VkInstance vkInst; + QVulkanInstance::Flags flags; + QByteArrayList layers; + QByteArrayList extensions; + QVersionNumber apiVersion; + VkResult errorCode; + QScopedPointer funcs; + QHash deviceFuncs; +}; + +bool QVulkanInstancePrivate::ensureVulkan() +{ + if (!platformInst) { + platformInst.reset(QGuiApplicationPrivate::platformIntegration()->createPlatformVulkanInstance(q_ptr)); + if (!platformInst) { + qWarning("QVulkanInstance: Failed to initialize Vulkan"); + return false; + } + } + return true; +} + +void QVulkanInstancePrivate::reset() +{ + qDeleteAll(deviceFuncs); + deviceFuncs.clear(); + funcs.reset(); + platformInst.reset(); + vkInst = VK_NULL_HANDLE; + errorCode = VK_SUCCESS; +} + +/*! + Constructs a new instance. + + \note No Vulkan initialization is performed in the constructor. + */ +QVulkanInstance::QVulkanInstance() + : d_ptr(new QVulkanInstancePrivate(this)) +{ +} + +/*! + Destructor. + + \note current() will return \c nullptr once the instance is destroyed. + */ +QVulkanInstance::~QVulkanInstance() +{ + destroy(); +} + +/*! + \struct QVulkanLayer + \brief Represents information about a Vulkan layer. + */ + +/*! + \value QVulkanLayer::name + \brief The name of the layer. + */ + +/*! + \value QVulkanLayer::version + \brief The version of the layer. This is an integer, increasing with each backward + compatible change. + */ + +/*! + \value QVulkanLayer::specVersion + \brief The Vulkan version the layer was written against. + */ + +/*! + \value QVulkanLayer::description + \brief The description of the layer. + */ + +/*! + \struct QVulkanExtension + \brief Represents information about a Vulkan extension. + */ + +/*! + \value QVulkanExtension::name + \brief The name of the extension. + */ + +/*! + \value QVulkanExtension::version + \brief The version of the extension. This is an integer, increasing with each backward + compatible change. + */ + +/*! + \class QVulkanInfoVector + \brief A specialized QVector for QVulkanLayer and QVulkanExtension. + */ + +/*! + \fn bool QVulkanInfoVector::contains(const QByteArray &name) const + + \return true if the vector contains a layer or extension with the given \a name. + */ + +/*! + \fn bool QVulkanInfoVector::contains(const QByteArray &name, int minVersion) const + + \return true if the vector contains a layer or extension with the given + \a name and a version same as or newer than \a minVersion. + */ + +/*! + \return the list of supported instance-level layers. + + \note This function can be called before create(). + */ +QVulkanInfoVector QVulkanInstance::supportedLayers() +{ + return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedLayers() : QVulkanInfoVector(); +} + +/*! + \return the list of supported instance-level extensions. + + \note This function can be called before create(). + */ +QVulkanInfoVector QVulkanInstance::supportedExtensions() +{ + return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedExtensions() : QVulkanInfoVector(); +} + +/*! + Makes QVulkanInstance adopt an existing VkInstance handle instead of + creating a new one. + + \note \a existingVkInstance must have at least \c{VK_KHR_surface} and the + appropriate WSI-specific \c{VK_KHR_*_surface} extensions enabled. To ensure + debug output redirection is functional, \c{VK_EXT_debug_report} is needed as + well. + + \note This function can only be called before create() and has no effect if + called afterwards. + */ +void QVulkanInstance::setVkInstance(VkInstance existingVkInstance) +{ + if (isValid()) { + qWarning("QVulkanInstance already created; setVkInstance() has no effect"); + return; + } + + d_ptr->vkInst = existingVkInstance; +} + +/*! + Configures the behavior of create() based on the provided \a flags. + + \note This function can only be called before create() and has no effect if + called afterwards. + */ +void QVulkanInstance::setFlags(Flags flags) +{ + if (isValid()) { + qWarning("QVulkanInstance already created; setFlags() has no effect"); + return; + } + + d_ptr->flags = flags; +} + +/*! + Specifies the list of instance \a layers to enable. It is safe to specify + unsupported layers as well because these get ignored when not supported at + run time. + + \note This function can only be called before create() and has no effect if + called afterwards. + */ +void QVulkanInstance::setLayers(const QByteArrayList &layers) +{ + if (isValid()) { + qWarning("QVulkanInstance already created; setLayers() has no effect"); + return; + } + + d_ptr->layers = layers; +} + +/*! + Specifies the list of additional instance \a extensions to enable. It is + safe to specify unsupported extensions as well because these get ignored + when not supported at run time. The surface-related extensions required by + Qt will always be added automatically, no need to include them in this + list. + + \note This function can only be called before create() and has no effect if + called afterwards. + */ +void QVulkanInstance::setExtensions(const QByteArrayList &extensions) +{ + if (isValid()) { + qWarning("QVulkanInstance already created; setExtensions() has no effect"); + return; + } + + d_ptr->extensions = extensions; +} + +/*! + Specifies the Vulkan API against which the application expects to run. + + By default no \a vulkanVersion is specified, and so no version check is performed + during Vulkan instance creation. + + \note This function can only be called before create() and has no effect if + called afterwards. + */ +void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion) +{ + if (isValid()) { + qWarning("QVulkanInstance already created; setApiVersion() has no effect"); + return; + } + + d_ptr->apiVersion = vulkanVersion; +} + +/*! + Initializes the Vulkan library and creates a new or adopts and existing + Vulkan instance. + + \return true if successful, false on error or when Vulkan is not supported. + + When successful, the pointer to this QVulkanInstance is retrievable via the + static function current(). + + The Vulkan instance and library is available as long as this + QVulkanInstance exists, or until destroy() is called. + */ +bool QVulkanInstance::create() +{ + if (isValid()) + destroy(); + + if (!d_ptr->ensureVulkan()) + return false; + + d_ptr->platformInst->createOrAdoptInstance(); + + if (d_ptr->platformInst->isValid()) { + d_ptr->vkInst = d_ptr->platformInst->vkInstance(); + d_ptr->layers = d_ptr->platformInst->enabledLayers(); + d_ptr->extensions = d_ptr->platformInst->enabledExtensions(); + d_ptr->errorCode = VK_SUCCESS; + d_ptr->funcs.reset(new QVulkanFunctions(this)); + return true; + } + + qWarning("Failed to create platform Vulkan instance"); + if (d_ptr->platformInst) { + d_ptr->errorCode = d_ptr->platformInst->errorCode(); + d_ptr->platformInst.reset(); + } else { + d_ptr->errorCode = VK_NOT_READY; + } + return false; +} + +/*! + Destroys the underlying platform instance, thus destroying the VkInstance + (when owned). The QVulkanInstance object is still reusable by calling + create() again. + */ +void QVulkanInstance::destroy() +{ + d_ptr->reset(); +} + +/*! + \return true if create() was successful and the instance is valid. + */ +bool QVulkanInstance::isValid() const +{ + return d_ptr->platformInst && d_ptr->platformInst->isValid(); +} + +/*! + \return the Vulkan error code after an unsuccessful create(), \c VK_SUCCESS otherwise. + + The value is typically the return value from vkCreateInstance() (when + creating a new Vulkan instance instead of adopting an existing one), but + may also be \c VK_NOT_READY if the platform plugin does not support Vulkan. + */ +VkResult QVulkanInstance::errorCode() const +{ + return d_ptr->errorCode; +} + +/*! + \return the VkInstance handle this QVulkanInstance wraps, or \c null if + create() has not yet been successfully called and no existing instance has + been provided via setVkInstance(). + */ +VkInstance QVulkanInstance::vkInstance() const +{ + return d_ptr->vkInst; +} + +/*! + \return the requested flags. + */ +QVulkanInstance::Flags QVulkanInstance::flags() const +{ + return d_ptr->flags; +} + +/*! + \return the enabled instance layers, if create() was called and was successful. The + requested layers otherwise. + */ +QByteArrayList QVulkanInstance::layers() const +{ + return d_ptr->layers; +} + +/*! + \return the enabled instance extensions, if create() was called and was + successful. The requested extensions otherwise. + */ +QByteArrayList QVulkanInstance::extensions() const +{ + return d_ptr->extensions; +} + +/*! + \return the requested Vulkan API version against which the application + expects to run, or a null version number if setApiVersion() was not called + before create(). + */ +QVersionNumber QVulkanInstance::apiVersion() const +{ + return d_ptr->apiVersion; +} + +/*! + Resolves the Vulkan function with the given \a name. + + For core Vulkan commands use functions() and QVulkanFunctions instead. + + \note When resolving device-specific extensions, prefer using + QVulkanFunctions::vkGetDeviceProcAddr() as explained + \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetDeviceProcAddr.html}{in + the Vulkan specification}. + */ +PFN_vkVoidFunction QVulkanInstance::getInstanceProcAddr(const char *name) +{ + // The return value is PFN_vkVoidFunction instead of QFunctionPointer or + // similar because on some platforms honoring VKAPI_PTR is important. + return d_ptr->platformInst->getInstanceProcAddr(name); +} + +/*! + \return the platform Vulkan instance corresponding to this QVulkanInstance. + + \internal + */ +QPlatformVulkanInstance *QVulkanInstance::handle() const +{ + return d_ptr->platformInst.data(); +} + +/*! + \return the corresponding QVulkanFunctions object that exposes the core + Vulkan command set, excluding device level functions, and is guaranteed to + be functional cross-platform. + + \note The returned object is owned and managed by the QVulkanInstance. Do + not destroy or alter it. + + \sa deviceFunctions() + */ +QVulkanFunctions *QVulkanInstance::functions() const +{ + return d_ptr->funcs.data(); +} + +/*! + \return the QVulkanDeviceFunctions object that exposes the device level + core Vulkan command set and is guaranteed to be functional cross-platform. + + \note The Vulkan functions in the returned object must only be called with + \a device or a child object (VkQueue, VkCommandBuffer) of \a device as + their first parameter. This is because these functions are resolved via + \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetDeviceProcAddr.html}{vkGetDeviceProcAddr} + in order to avoid the potential overhead of internal dispatching. + + \note The returned object is owned and managed by the QVulkanInstance. Do + not destroy or alter it. + + \note The object is cached so calling this function with the same \a device + again is a cheap operation. However, when the device gets destroyed, it is up + to the application to notify the QVulkanInstance by calling + resetDeviceFunctions(). + + \sa functions(), resetDeviceFunctions() + */ +QVulkanDeviceFunctions *QVulkanInstance::deviceFunctions(VkDevice device) +{ + QVulkanDeviceFunctions *&f(d_ptr->deviceFuncs[device]); + if (!f) + f = new QVulkanDeviceFunctions(this, device); + return f; +} + +/*! + Invalidates and destroys the QVulkanDeviceFunctions object for the given + \a device. + + This function must be called when a VkDevice, for which deviceFunctions() + was called, gets destroyed while the application intends to continue + running, possibly creating a new logical Vulkan device later on. + + There is no need to call this before destroying the QVulkanInstance since + clean up is then performed automatically. + + \sa deviceFunctions() + */ +void QVulkanInstance::resetDeviceFunctions(VkDevice device) +{ + QVulkanDeviceFunctions *&f(d_ptr->deviceFuncs[device]); + delete f; + f = nullptr; +} + +/*! + Creates or retrieves the already existing \c{VkSurfaceKHR} handle for the + given \a window. + + \return the Vulkan surface handle or 0 when failed. + */ +VkSurfaceKHR QVulkanInstance::surfaceForWindow(QWindow *window) +{ + QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface(); + // VkSurfaceKHR is non-dispatchable and maps to a pointer on x64 and a uint64 on x86. + // Therefore a pointer is returned from the platform plugin, not the value itself. + void *p = nativeInterface->nativeResourceForWindow(QByteArrayLiteral("vkSurface"), window); + return p ? *static_cast(p) : 0; +} + +/*! + \return true if the queue family with \a queueFamilyIndex within the + \a physicalDevice supports presenting to \a window. + + Call this function when examining the queues of a given Vulkan device, in + order to decide which queue can be used for performing presentation. + */ +bool QVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) +{ + return d_ptr->platformInst->supportsPresent(physicalDevice, queueFamilyIndex, window); +} + +/*! + This function should be called by the application's renderer after queuing + a present operation for \a window. + + While on some platforms this will be a no-op, some may perform windowing + system dependent synchronization. For example, on X11 this will update + \c{_NET_WM_SYNC_REQUEST_COUNTER}. + */ +void QVulkanInstance::presentQueued(QWindow *window) +{ + d_ptr->platformInst->presentQueued(window); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QVulkanLayer &layer) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "QVulkanLayer(" << layer.name << " " << layer.version + << " " << layer.specVersion << " " << layer.description << ")"; + return dbg; +} + +QDebug operator<<(QDebug dbg, const QVulkanExtension &extension) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "QVulkanExtension(" << extension.name << " " << extension.version << ")"; + return dbg; +} +#endif + +QT_END_NAMESPACE diff --git a/src/gui/vulkan/qvulkaninstance.h b/src/gui/vulkan/qvulkaninstance.h new file mode 100644 index 0000000000..b3f08cf0d8 --- /dev/null +++ b/src/gui/vulkan/qvulkaninstance.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui 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 QVULKANINSTANCE_H +#define QVULKANINSTANCE_H + +#include + +#if QT_CONFIG(vulkan) + +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QVulkanInstancePrivate; +class QPlatformVulkanInstance; +class QVulkanFunctions; +class QVulkanDeviceFunctions; +class QWindow; + +struct Q_GUI_EXPORT QVulkanLayer +{ + QByteArray name; + uint32_t version; + QVersionNumber specVersion; + QByteArray description; + bool operator==(const QVulkanLayer &other) const { + return name == other.name && version == other.version && specVersion == other.specVersion; + } +}; + +struct Q_GUI_EXPORT QVulkanExtension +{ + QByteArray name; + uint32_t version; + bool operator==(const QVulkanExtension &other) const { + return name == other.name && version == other.version; + } +}; + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug, const QVulkanLayer &); +Q_GUI_EXPORT QDebug operator<<(QDebug, const QVulkanExtension &); +#endif + +template +class QVulkanInfoVector : public QVector +{ +public: + bool contains(const QByteArray &name) const { + return std::any_of(this->cbegin(), this->cend(), [&](const T &entry) { + return entry.name == name; }); + } + bool contains(const QByteArray &name, int minVersion) const { + return std::any_of(this->cbegin(), this->cend(), [&](const T &entry) { + return entry.name == name && entry.version >= minVersion; }); + } +}; + +class Q_GUI_EXPORT QVulkanInstance +{ +public: + QVulkanInstance(); + ~QVulkanInstance(); + + enum Flag { + NoDebugOutputRedirect = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + QVulkanInfoVector supportedLayers(); + QVulkanInfoVector supportedExtensions(); + + void setVkInstance(VkInstance existingVkInstance); + + void setFlags(Flags flags); + void setLayers(const QByteArrayList &layers); + void setExtensions(const QByteArrayList &extensions); + void setApiVersion(const QVersionNumber &vulkanVersion); + + bool create(); + void destroy(); + bool isValid() const; + VkResult errorCode() const; + + VkInstance vkInstance() const; + + Flags flags() const; + QByteArrayList layers() const; + QByteArrayList extensions() const; + QVersionNumber apiVersion() const; + + PFN_vkVoidFunction getInstanceProcAddr(const char *name); + + QPlatformVulkanInstance *handle() const; + + QVulkanFunctions *functions() const; + QVulkanDeviceFunctions *deviceFunctions(VkDevice device); + void resetDeviceFunctions(VkDevice device); + + static VkSurfaceKHR surfaceForWindow(QWindow *window); + + bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window); + + void presentQueued(QWindow *window); + +private: + QScopedPointer d_ptr; + Q_DISABLE_COPY(QVulkanInstance) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QVulkanInstance::Flags) + +QT_END_NAMESPACE + +#endif // QT_CONFIG(vulkan) + +#endif // QVULKANINSTANCE_H diff --git a/src/gui/vulkan/vk.xml b/src/gui/vulkan/vk.xml new file mode 100644 index 0000000000..779875b819 --- /dev/null +++ b/src/gui/vulkan/vk.xml @@ -0,0 +1,5269 @@ + + + +Copyright (c) 2015-2017 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + +------------------------------------------------------------------------ + +This file, vk.xml, is the Vulkan API Registry. It is a critically important +and normative part of the Vulkan Specification, including a canonical +machine-readable definition of the API, parameter and member validation +language incorporated into the Specification and reference pages, and other +material which is registered by Khronos, such as tags used by extension and +layer authors. The only authoritative version of vk.xml is the one +maintained in the master branch of the Khronos Vulkan GitHub project. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #include "vk_platform.h" + + #include "vulkan.h" + #include <X11/Xlib.h> + #include <X11/extensions/Xrandr.h> + #include <android/native_window.h> + #include <mir_toolkit/client_types.h> + #include <wayland-client.h> + #include <windows.h> + #include <xcb/xcb.h> + + + + + + + + + + + + + + + + + + + + #define VK_MAKE_VERSION(major, minor, patch) \ + (((major) << 22) | ((minor) << 12) | (patch)) + #define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) + #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) + #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) + + // DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. +//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) + // Vulkan 1.0 version number +#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0) + // Version of this file +#define VK_HEADER_VERSION 39 + + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + + +#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; +#else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#endif +#endif + + + +#define VK_NULL_HANDLE 0 + + + typedef uint32_t VkSampleMask; + typedef uint32_t VkBool32; + typedef uint32_t VkFlags; + typedef uint64_t VkDeviceSize; + + + + + + + + + + + typedef VkFlags VkFramebufferCreateFlags; + typedef VkFlags VkQueryPoolCreateFlags; + typedef VkFlags VkRenderPassCreateFlags; + typedef VkFlags VkSamplerCreateFlags; + typedef VkFlags VkPipelineLayoutCreateFlags; + typedef VkFlags VkPipelineCacheCreateFlags; + typedef VkFlags VkPipelineDepthStencilStateCreateFlags; + typedef VkFlags VkPipelineDynamicStateCreateFlags; + typedef VkFlags VkPipelineColorBlendStateCreateFlags; + typedef VkFlags VkPipelineMultisampleStateCreateFlags; + typedef VkFlags VkPipelineRasterizationStateCreateFlags; + typedef VkFlags VkPipelineViewportStateCreateFlags; + typedef VkFlags VkPipelineTessellationStateCreateFlags; + typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; + typedef VkFlags VkPipelineVertexInputStateCreateFlags; + typedef VkFlags VkPipelineShaderStageCreateFlags; + typedef VkFlags VkDescriptorSetLayoutCreateFlags; + typedef VkFlags VkBufferViewCreateFlags; + typedef VkFlags VkInstanceCreateFlags; + typedef VkFlags VkDeviceCreateFlags; + typedef VkFlags VkDeviceQueueCreateFlags; + typedef VkFlags VkQueueFlags; + typedef VkFlags VkMemoryPropertyFlags; + typedef VkFlags VkMemoryHeapFlags; + typedef VkFlags VkAccessFlags; + typedef VkFlags VkBufferUsageFlags; + typedef VkFlags VkBufferCreateFlags; + typedef VkFlags VkShaderStageFlags; + typedef VkFlags VkImageUsageFlags; + typedef VkFlags VkImageCreateFlags; + typedef VkFlags VkImageViewCreateFlags; + typedef VkFlags VkPipelineCreateFlags; + typedef VkFlags VkColorComponentFlags; + typedef VkFlags VkFenceCreateFlags; + typedef VkFlags VkSemaphoreCreateFlags; + typedef VkFlags VkFormatFeatureFlags; + typedef VkFlags VkQueryControlFlags; + typedef VkFlags VkQueryResultFlags; + typedef VkFlags VkShaderModuleCreateFlags; + typedef VkFlags VkEventCreateFlags; + typedef VkFlags VkCommandPoolCreateFlags; + typedef VkFlags VkCommandPoolResetFlags; + typedef VkFlags VkCommandBufferResetFlags; + typedef VkFlags VkCommandBufferUsageFlags; + typedef VkFlags VkQueryPipelineStatisticFlags; + typedef VkFlags VkMemoryMapFlags; + typedef VkFlags VkImageAspectFlags; + typedef VkFlags VkSparseMemoryBindFlags; + typedef VkFlags VkSparseImageFormatFlags; + typedef VkFlags VkSubpassDescriptionFlags; + typedef VkFlags VkPipelineStageFlags; + typedef VkFlags VkSampleCountFlags; + typedef VkFlags VkAttachmentDescriptionFlags; + typedef VkFlags VkStencilFaceFlags; + typedef VkFlags VkCullModeFlags; + typedef VkFlags VkDescriptorPoolCreateFlags; + typedef VkFlags VkDescriptorPoolResetFlags; + typedef VkFlags VkDependencyFlags; + + typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX; + typedef VkFlags VkObjectEntryUsageFlagsNVX; + + + typedef VkFlags VkCompositeAlphaFlagsKHR; + typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; + typedef VkFlags VkSurfaceTransformFlagsKHR; + typedef VkFlags VkSwapchainCreateFlagsKHR; + typedef VkFlags VkDisplayModeCreateFlagsKHR; + typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; + typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; + typedef VkFlags VkMirSurfaceCreateFlagsKHR; + typedef VkFlags VkViSurfaceCreateFlagsNN; + typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; + typedef VkFlags VkWin32SurfaceCreateFlagsKHR; + typedef VkFlags VkXlibSurfaceCreateFlagsKHR; + typedef VkFlags VkXcbSurfaceCreateFlagsKHR; + + typedef VkFlags VkDebugReportFlagsEXT; + typedef VkFlags VkCommandPoolTrimFlagsKHR; + typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; + typedef VkFlags VkExternalMemoryFeatureFlagsNV; + typedef VkFlags VkSurfaceCounterFlagsEXT; + + + VK_DEFINE_HANDLE(VkInstance) + VK_DEFINE_HANDLE(VkPhysicalDevice) + VK_DEFINE_HANDLE(VkDevice) + VK_DEFINE_HANDLE(VkQueue) + VK_DEFINE_HANDLE(VkCommandBuffer) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) + + + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + typedef void (VKAPI_PTR *PFN_vkFreeFunction)( + void* pUserData, + void* pMemory); + + + typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); + + + typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); + + + + int32_t x + int32_t y + + + int32_t x + int32_t y + int32_t z + + + uint32_t width + uint32_t height + + + uint32_t width + uint32_t height + uint32_t depth + + + float x + float y + float width + float height + float minDepth + float maxDepth + + + VkOffset2D offset + VkExtent2D extent + + + VkOffset3D offset + VkExtent3D extent + + + VkRect2D rect + uint32_t baseArrayLayer + uint32_t layerCount + + + VkComponentSwizzle r + VkComponentSwizzle g + VkComponentSwizzle b + VkComponentSwizzle a + + + uint32_t apiVersion + uint32_t driverVersion + uint32_t vendorID + uint32_t deviceID + VkPhysicalDeviceType deviceType + char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE] + uint8_t pipelineCacheUUID[VK_UUID_SIZE] + VkPhysicalDeviceLimits limits + VkPhysicalDeviceSparseProperties sparseProperties + + + char extensionName[VK_MAX_EXTENSION_NAME_SIZE] + uint32_t specVersion + + + char layerName[VK_MAX_EXTENSION_NAME_SIZE] + uint32_t specVersion + uint32_t implementationVersion + char description[VK_MAX_DESCRIPTION_SIZE] + + + VkStructureType sType + const void* pNext + const char* pApplicationName + uint32_t applicationVersion + const char* pEngineName + uint32_t engineVersion + uint32_t apiVersion + + + void* pUserData + PFN_vkAllocationFunction pfnAllocation + PFN_vkReallocationFunction pfnReallocation + PFN_vkFreeFunction pfnFree + PFN_vkInternalAllocationNotification pfnInternalAllocation + PFN_vkInternalFreeNotification pfnInternalFree + + + VkStructureType sType + const void* pNext + VkDeviceQueueCreateFlags flags + uint32_t queueFamilyIndex + uint32_t queueCount + const float* pQueuePriorities + + + VkStructureType sType + const void* pNext + VkDeviceCreateFlags flags + uint32_t queueCreateInfoCount + const VkDeviceQueueCreateInfo* pQueueCreateInfos + uint32_t enabledLayerCount + const char* const* ppEnabledLayerNames + uint32_t enabledExtensionCount + const char* const* ppEnabledExtensionNames + const VkPhysicalDeviceFeatures* pEnabledFeatures + + + VkStructureType sType + const void* pNext + VkInstanceCreateFlags flags + const VkApplicationInfo* pApplicationInfo + uint32_t enabledLayerCount + const char* const* ppEnabledLayerNames + uint32_t enabledExtensionCount + const char* const* ppEnabledExtensionNames + + + VkQueueFlags queueFlags + uint32_t queueCount + uint32_t timestampValidBits + VkExtent3D minImageTransferGranularity + + + uint32_t memoryTypeCount + VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES] + uint32_t memoryHeapCount + VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS] + + + VkStructureType sType + const void* pNext + VkDeviceSize allocationSize + uint32_t memoryTypeIndex + + + VkDeviceSize size + VkDeviceSize alignment + uint32_t memoryTypeBits + + + VkImageAspectFlags aspectMask + VkExtent3D imageGranularity + VkSparseImageFormatFlags flags + + + VkSparseImageFormatProperties formatProperties + uint32_t imageMipTailFirstLod + VkDeviceSize imageMipTailSize + VkDeviceSize imageMipTailOffset + VkDeviceSize imageMipTailStride + + + VkMemoryPropertyFlags propertyFlags + uint32_t heapIndex + + + VkDeviceSize size + VkMemoryHeapFlags flags + + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + VkDeviceSize offset + VkDeviceSize size + + + VkFormatFeatureFlags linearTilingFeatures + VkFormatFeatureFlags optimalTilingFeatures + VkFormatFeatureFlags bufferFeatures + + + VkExtent3D maxExtent + uint32_t maxMipLevels + uint32_t maxArrayLayers + VkSampleCountFlags sampleCounts + VkDeviceSize maxResourceSize + + + VkBuffer buffer + VkDeviceSize offset + VkDeviceSize range + + + VkSampler sampler + VkImageView imageView + VkImageLayout imageLayout + + + VkStructureType sType + const void* pNext + VkDescriptorSet dstSet + uint32_t dstBinding + uint32_t dstArrayElement + uint32_t descriptorCount + VkDescriptorType descriptorType + const VkDescriptorImageInfo* pImageInfo + const VkDescriptorBufferInfo* pBufferInfo + const VkBufferView* pTexelBufferView + + + VkStructureType sType + const void* pNext + VkDescriptorSet srcSet + uint32_t srcBinding + uint32_t srcArrayElement + VkDescriptorSet dstSet + uint32_t dstBinding + uint32_t dstArrayElement + uint32_t descriptorCount + + + VkStructureType sType + const void* pNext + VkBufferCreateFlags flags + VkDeviceSize size + VkBufferUsageFlags usage + VkSharingMode sharingMode + uint32_t queueFamilyIndexCount + const uint32_t* pQueueFamilyIndices + + + VkStructureType sType + const void* pNext + VkBufferViewCreateFlagsflags + VkBuffer buffer + VkFormat format + VkDeviceSize offset + VkDeviceSize range + + + VkImageAspectFlags aspectMask + uint32_t mipLevel + uint32_t arrayLayer + + + VkImageAspectFlags aspectMask + uint32_t mipLevel + uint32_t baseArrayLayer + uint32_t layerCount + + + VkImageAspectFlags aspectMask + uint32_t baseMipLevel + uint32_t levelCount + uint32_t baseArrayLayer + uint32_t layerCount + + + VkStructureType sType + const void* pNext + VkAccessFlags srcAccessMask + VkAccessFlags dstAccessMask + + + VkStructureType sType + const void* pNext + VkAccessFlags srcAccessMask + VkAccessFlags dstAccessMask + uint32_t srcQueueFamilyIndex + uint32_t dstQueueFamilyIndex + VkBuffer buffer + VkDeviceSize offset + VkDeviceSize size + + + VkStructureType sType + const void* pNext + VkAccessFlags srcAccessMask + VkAccessFlags dstAccessMask + VkImageLayout oldLayout + VkImageLayout newLayout + uint32_t srcQueueFamilyIndex + uint32_t dstQueueFamilyIndex + VkImage image + VkImageSubresourceRange subresourceRange + + + VkStructureType sType + const void* pNext + VkImageCreateFlags flags + VkImageType imageType + VkFormat format + VkExtent3D extent + uint32_t mipLevels + uint32_t arrayLayers + VkSampleCountFlagBits samples + VkImageTiling tiling + VkImageUsageFlags usage + VkSharingMode sharingMode + uint32_t queueFamilyIndexCount + const uint32_t* pQueueFamilyIndices + VkImageLayout initialLayout + + + VkDeviceSize offset + VkDeviceSize size + VkDeviceSize rowPitch + VkDeviceSize arrayPitch + VkDeviceSize depthPitch + + + VkStructureType sType + const void* pNext + VkImageViewCreateFlags flags + VkImage image + VkImageViewType viewType + VkFormat format + VkComponentMapping components + VkImageSubresourceRange subresourceRange + + + VkDeviceSize srcOffset + VkDeviceSize dstOffset + VkDeviceSize size + + + VkDeviceSize resourceOffset + VkDeviceSize size + VkDeviceMemory memory + VkDeviceSize memoryOffset + VkSparseMemoryBindFlagsflags + + + VkImageSubresource subresource + VkOffset3D offset + VkExtent3D extent + VkDeviceMemory memory + VkDeviceSize memoryOffset + VkSparseMemoryBindFlagsflags + + + VkBuffer buffer + uint32_t bindCount + const VkSparseMemoryBind* pBinds + + + VkImage image + uint32_t bindCount + const VkSparseMemoryBind* pBinds + + + VkImage image + uint32_t bindCount + const VkSparseImageMemoryBind* pBinds + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreCount + const VkSemaphore* pWaitSemaphores + uint32_t bufferBindCount + const VkSparseBufferMemoryBindInfo* pBufferBinds + uint32_t imageOpaqueBindCount + const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds + uint32_t imageBindCount + const VkSparseImageMemoryBindInfo* pImageBinds + uint32_t signalSemaphoreCount + const VkSemaphore* pSignalSemaphores + + + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffset + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffset + VkExtent3D extent + + + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffsets[2] + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffsets[2] + + + VkDeviceSize bufferOffset + uint32_t bufferRowLength + uint32_t bufferImageHeight + VkImageSubresourceLayers imageSubresource + VkOffset3D imageOffset + VkExtent3D imageExtent + + + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffset + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffset + VkExtent3D extent + + + VkStructureType sType + const void* pNext + VkShaderModuleCreateFlags flags + size_t codeSize + const uint32_t* pCode + + + uint32_t binding + VkDescriptorType descriptorType + uint32_t descriptorCount + VkShaderStageFlags stageFlags + const VkSampler* pImmutableSamplers + + + VkStructureType sType + const void* pNext + VkDescriptorSetLayoutCreateFlags flags + uint32_t bindingCount + const VkDescriptorSetLayoutBinding* pBindings + + + VkDescriptorType type + uint32_t descriptorCount + + + VkStructureType sType + const void* pNext + VkDescriptorPoolCreateFlags flags + uint32_t maxSets + uint32_t poolSizeCount + const VkDescriptorPoolSize* pPoolSizes + + + VkStructureType sType + const void* pNext + VkDescriptorPool descriptorPool + uint32_t descriptorSetCount + const VkDescriptorSetLayout* pSetLayouts + + + uint32_t constantID + uint32_t offset + size_t size + + + uint32_t mapEntryCount + const VkSpecializationMapEntry* pMapEntries + size_t dataSize + const void* pData + + + VkStructureType sType + const void* pNext + VkPipelineShaderStageCreateFlags flags + VkShaderStageFlagBits stage + VkShaderModule module + const char* pName + const VkSpecializationInfo* pSpecializationInfo + + + VkStructureType sType + const void* pNext + VkPipelineCreateFlags flags + VkPipelineShaderStageCreateInfo stage + VkPipelineLayout layout + VkPipeline basePipelineHandle + int32_t basePipelineIndex + + + uint32_t binding + uint32_t stride + VkVertexInputRate inputRate + + + uint32_t location + uint32_t binding + VkFormat format + uint32_t offset + + + VkStructureType sType + const void* pNext + VkPipelineVertexInputStateCreateFlags flags + uint32_t vertexBindingDescriptionCount + const VkVertexInputBindingDescription* pVertexBindingDescriptions + uint32_t vertexAttributeDescriptionCount + const VkVertexInputAttributeDescription* pVertexAttributeDescriptions + + + VkStructureType sType + const void* pNext + VkPipelineInputAssemblyStateCreateFlags flags + VkPrimitiveTopology topology + VkBool32 primitiveRestartEnable + + + VkStructureType sType + const void* pNext + VkPipelineTessellationStateCreateFlags flags + uint32_t patchControlPoints + + + VkStructureType sType + const void* pNext + VkPipelineViewportStateCreateFlags flags + uint32_t viewportCount + const VkViewport* pViewports + uint32_t scissorCount + const VkRect2D* pScissors + + + VkStructureType sType + const void* pNext + VkPipelineRasterizationStateCreateFlags flags + VkBool32 depthClampEnable + VkBool32 rasterizerDiscardEnable + VkPolygonMode polygonMode + VkCullModeFlags cullMode + VkFrontFace frontFace + VkBool32 depthBiasEnable + float depthBiasConstantFactor + float depthBiasClamp + float depthBiasSlopeFactor + float lineWidth + + + VkStructureType sType + const void* pNext + VkPipelineMultisampleStateCreateFlags flags + VkSampleCountFlagBits rasterizationSamples + VkBool32 sampleShadingEnable + float minSampleShading + const VkSampleMask* pSampleMask + VkBool32 alphaToCoverageEnable + VkBool32 alphaToOneEnable + + + VkBool32 blendEnable + VkBlendFactor srcColorBlendFactor + VkBlendFactor dstColorBlendFactor + VkBlendOp colorBlendOp + VkBlendFactor srcAlphaBlendFactor + VkBlendFactor dstAlphaBlendFactor + VkBlendOp alphaBlendOp + VkColorComponentFlags colorWriteMask + + + VkStructureType sType + const void* pNext + VkPipelineColorBlendStateCreateFlags flags + VkBool32 logicOpEnable + VkLogicOp logicOp + uint32_t attachmentCount + const VkPipelineColorBlendAttachmentState* pAttachments + float blendConstants[4] + + + VkStructureType sType + const void* pNext + VkPipelineDynamicStateCreateFlags flags + uint32_t dynamicStateCount + const VkDynamicState* pDynamicStates + + + VkStencilOp failOp + VkStencilOp passOp + VkStencilOp depthFailOp + VkCompareOp compareOp + uint32_t compareMask + uint32_t writeMask + uint32_t reference + + + VkStructureType sType + const void* pNext + VkPipelineDepthStencilStateCreateFlags flags + VkBool32 depthTestEnable + VkBool32 depthWriteEnable + VkCompareOp depthCompareOp + VkBool32 depthBoundsTestEnable + VkBool32 stencilTestEnable + VkStencilOpState front + VkStencilOpState back + float minDepthBounds + float maxDepthBounds + + + VkStructureType sType + const void* pNext + VkPipelineCreateFlags flags + uint32_t stageCount + const VkPipelineShaderStageCreateInfo* pStages + const VkPipelineVertexInputStateCreateInfo* pVertexInputState + const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState + const VkPipelineTessellationStateCreateInfo* pTessellationState + const VkPipelineViewportStateCreateInfo* pViewportState + const VkPipelineRasterizationStateCreateInfo* pRasterizationState + const VkPipelineMultisampleStateCreateInfo* pMultisampleState + const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState + const VkPipelineColorBlendStateCreateInfo* pColorBlendState + const VkPipelineDynamicStateCreateInfo* pDynamicState + VkPipelineLayout layout + VkRenderPass renderPass + uint32_t subpass + VkPipeline basePipelineHandle + int32_t basePipelineIndex + + + VkStructureType sType + const void* pNext + VkPipelineCacheCreateFlags flags + size_t initialDataSize + const void* pInitialData + + + VkShaderStageFlags stageFlags + uint32_t offset + uint32_t size + + + VkStructureType sType + const void* pNext + VkPipelineLayoutCreateFlags flags + uint32_t setLayoutCount + const VkDescriptorSetLayout* pSetLayouts + uint32_t pushConstantRangeCount + const VkPushConstantRange* pPushConstantRanges + + + VkStructureType sType + const void* pNext + VkSamplerCreateFlags flags + VkFilter magFilter + VkFilter minFilter + VkSamplerMipmapMode mipmapMode + VkSamplerAddressMode addressModeU + VkSamplerAddressMode addressModeV + VkSamplerAddressMode addressModeW + float mipLodBias + VkBool32 anisotropyEnable + float maxAnisotropy + VkBool32 compareEnable + VkCompareOp compareOp + float minLod + float maxLod + VkBorderColor borderColor + VkBool32 unnormalizedCoordinates + + + VkStructureType sType + const void* pNext + VkCommandPoolCreateFlags flags + uint32_t queueFamilyIndex + + + VkStructureType sType + const void* pNext + VkCommandPool commandPool + VkCommandBufferLevel level + uint32_t commandBufferCount + + + VkStructureType sType + const void* pNext + VkRenderPass renderPass + uint32_t subpass + VkFramebuffer framebuffer + VkBool32 occlusionQueryEnable + VkQueryControlFlags queryFlags + VkQueryPipelineStatisticFlags pipelineStatistics + + + VkStructureType sType + const void* pNext + VkCommandBufferUsageFlags flags + const VkCommandBufferInheritanceInfo* pInheritanceInfo + + + VkStructureType sType + const void* pNext + VkRenderPass renderPass + VkFramebuffer framebuffer + VkRect2D renderArea + uint32_t clearValueCount + const VkClearValue* pClearValues + + + float float32[4] + int32_t int32[4] + uint32_t uint32[4] + + + float depth + uint32_t stencil + + + VkClearColorValue color + VkClearDepthStencilValue depthStencil + + + VkImageAspectFlags aspectMask + uint32_t colorAttachment + VkClearValue clearValue + + + VkAttachmentDescriptionFlags flags + VkFormat format + VkSampleCountFlagBits samples + VkAttachmentLoadOp loadOp + VkAttachmentStoreOp storeOp + VkAttachmentLoadOp stencilLoadOp + VkAttachmentStoreOp stencilStoreOp + VkImageLayout initialLayout + VkImageLayout finalLayout + + + uint32_t attachment + VkImageLayout layout + + + VkSubpassDescriptionFlags flags + VkPipelineBindPoint pipelineBindPoint + uint32_t inputAttachmentCount + const VkAttachmentReference* pInputAttachments + uint32_t colorAttachmentCount + const VkAttachmentReference* pColorAttachments + const VkAttachmentReference* pResolveAttachments + const VkAttachmentReference* pDepthStencilAttachment + uint32_t preserveAttachmentCount + const uint32_t* pPreserveAttachments + + + uint32_t srcSubpass + uint32_t dstSubpass + VkPipelineStageFlags srcStageMask + VkPipelineStageFlags dstStageMask + VkAccessFlags srcAccessMask + VkAccessFlags dstAccessMask + VkDependencyFlags dependencyFlags + + + VkStructureType sType + const void* pNext + VkRenderPassCreateFlags flags + uint32_t attachmentCount + const VkAttachmentDescription* pAttachments + uint32_t subpassCount + const VkSubpassDescription* pSubpasses + uint32_t dependencyCount + const VkSubpassDependency* pDependencies + + + VkStructureType sType + const void* pNext + VkEventCreateFlags flags + + + VkStructureType sType + const void* pNext + VkFenceCreateFlags flags + + + VkBool32 robustBufferAccess + VkBool32 fullDrawIndexUint32 + VkBool32 imageCubeArray + VkBool32 independentBlend + VkBool32 geometryShader + VkBool32 tessellationShader + VkBool32 sampleRateShading + VkBool32 dualSrcBlend + VkBool32 logicOp + VkBool32 multiDrawIndirect + VkBool32 drawIndirectFirstInstance + VkBool32 depthClamp + VkBool32 depthBiasClamp + VkBool32 fillModeNonSolid + VkBool32 depthBounds + VkBool32 wideLines + VkBool32 largePoints + VkBool32 alphaToOne + VkBool32 multiViewport + VkBool32 samplerAnisotropy + VkBool32 textureCompressionETC2 + VkBool32 textureCompressionASTC_LDR + VkBool32 textureCompressionBC + VkBool32 occlusionQueryPrecise + VkBool32 pipelineStatisticsQuery + VkBool32 vertexPipelineStoresAndAtomics + VkBool32 fragmentStoresAndAtomics + VkBool32 shaderTessellationAndGeometryPointSize + VkBool32 shaderImageGatherExtended + VkBool32 shaderStorageImageExtendedFormats + VkBool32 shaderStorageImageMultisample + VkBool32 shaderStorageImageReadWithoutFormat + VkBool32 shaderStorageImageWriteWithoutFormat + VkBool32 shaderUniformBufferArrayDynamicIndexing + VkBool32 shaderSampledImageArrayDynamicIndexing + VkBool32 shaderStorageBufferArrayDynamicIndexing + VkBool32 shaderStorageImageArrayDynamicIndexing + VkBool32 shaderClipDistance + VkBool32 shaderCullDistance + VkBool32 shaderFloat64 + VkBool32 shaderInt64 + VkBool32 shaderInt16 + VkBool32 shaderResourceResidency + VkBool32 shaderResourceMinLod + VkBool32 sparseBinding + VkBool32 sparseResidencyBuffer + VkBool32 sparseResidencyImage2D + VkBool32 sparseResidencyImage3D + VkBool32 sparseResidency2Samples + VkBool32 sparseResidency4Samples + VkBool32 sparseResidency8Samples + VkBool32 sparseResidency16Samples + VkBool32 sparseResidencyAliased + VkBool32 variableMultisampleRate + VkBool32 inheritedQueries + + + VkBool32 residencyStandard2DBlockShape + VkBool32 residencyStandard2DMultisampleBlockShape + VkBool32 residencyStandard3DBlockShape + VkBool32 residencyAlignedMipSize + VkBool32 residencyNonResidentStrict + + + + uint32_t maxImageDimension1D + uint32_t maxImageDimension2D + uint32_t maxImageDimension3D + uint32_t maxImageDimensionCube + uint32_t maxImageArrayLayers + uint32_t maxTexelBufferElements + uint32_t maxUniformBufferRange + uint32_t maxStorageBufferRange + uint32_t maxPushConstantsSize + + uint32_t maxMemoryAllocationCount + uint32_t maxSamplerAllocationCount + VkDeviceSize bufferImageGranularity + VkDeviceSize sparseAddressSpaceSize + + uint32_t maxBoundDescriptorSets + uint32_t maxPerStageDescriptorSamplers + uint32_t maxPerStageDescriptorUniformBuffers + uint32_t maxPerStageDescriptorStorageBuffers + uint32_t maxPerStageDescriptorSampledImages + uint32_t maxPerStageDescriptorStorageImages + uint32_t maxPerStageDescriptorInputAttachments + uint32_t maxPerStageResources + uint32_t maxDescriptorSetSamplers + uint32_t maxDescriptorSetUniformBuffers + uint32_t maxDescriptorSetUniformBuffersDynamic + uint32_t maxDescriptorSetStorageBuffers + uint32_t maxDescriptorSetStorageBuffersDynamic + uint32_t maxDescriptorSetSampledImages + uint32_t maxDescriptorSetStorageImages + uint32_t maxDescriptorSetInputAttachments + + uint32_t maxVertexInputAttributes + uint32_t maxVertexInputBindings + uint32_t maxVertexInputAttributeOffset + uint32_t maxVertexInputBindingStride + uint32_t maxVertexOutputComponents + + uint32_t maxTessellationGenerationLevel + uint32_t maxTessellationPatchSize + uint32_t maxTessellationControlPerVertexInputComponents + uint32_t maxTessellationControlPerVertexOutputComponents + uint32_t maxTessellationControlPerPatchOutputComponents + uint32_t maxTessellationControlTotalOutputComponents + + uint32_t maxTessellationEvaluationInputComponents + uint32_t maxTessellationEvaluationOutputComponents + + uint32_t maxGeometryShaderInvocations + uint32_t maxGeometryInputComponents + uint32_t maxGeometryOutputComponents + uint32_t maxGeometryOutputVertices + uint32_t maxGeometryTotalOutputComponents + + uint32_t maxFragmentInputComponents + uint32_t maxFragmentOutputAttachments + uint32_t maxFragmentDualSrcAttachments + uint32_t maxFragmentCombinedOutputResources + + uint32_t maxComputeSharedMemorySize + uint32_t maxComputeWorkGroupCount[3] + uint32_t maxComputeWorkGroupInvocations + uint32_t maxComputeWorkGroupSize[3] + uint32_t subPixelPrecisionBits + uint32_t subTexelPrecisionBits + uint32_t mipmapPrecisionBits + uint32_t maxDrawIndexedIndexValue + uint32_t maxDrawIndirectCount + float maxSamplerLodBias + float maxSamplerAnisotropy + uint32_t maxViewports + uint32_t maxViewportDimensions[2] + float viewportBoundsRange[2] + uint32_t viewportSubPixelBits + size_t minMemoryMapAlignment + VkDeviceSize minTexelBufferOffsetAlignment + VkDeviceSize minUniformBufferOffsetAlignment + VkDeviceSize minStorageBufferOffsetAlignment + int32_t minTexelOffset + uint32_t maxTexelOffset + int32_t minTexelGatherOffset + uint32_t maxTexelGatherOffset + float minInterpolationOffset + float maxInterpolationOffset + uint32_t subPixelInterpolationOffsetBits + uint32_t maxFramebufferWidth + uint32_t maxFramebufferHeight + uint32_t maxFramebufferLayers + VkSampleCountFlags framebufferColorSampleCounts + VkSampleCountFlags framebufferDepthSampleCounts + VkSampleCountFlags framebufferStencilSampleCounts + VkSampleCountFlags framebufferNoAttachmentsSampleCounts + uint32_t maxColorAttachments + VkSampleCountFlags sampledImageColorSampleCounts + VkSampleCountFlags sampledImageIntegerSampleCounts + VkSampleCountFlags sampledImageDepthSampleCounts + VkSampleCountFlags sampledImageStencilSampleCounts + VkSampleCountFlags storageImageSampleCounts + uint32_t maxSampleMaskWords + VkBool32 timestampComputeAndGraphics + float timestampPeriod + uint32_t maxClipDistances + uint32_t maxCullDistances + uint32_t maxCombinedClipAndCullDistances + uint32_t discreteQueuePriorities + float pointSizeRange[2] + float lineWidthRange[2] + float pointSizeGranularity + float lineWidthGranularity + VkBool32 strictLines + VkBool32 standardSampleLocations + VkDeviceSize optimalBufferCopyOffsetAlignment + VkDeviceSize optimalBufferCopyRowPitchAlignment + VkDeviceSize nonCoherentAtomSize + + + VkStructureType sType + const void* pNext + VkSemaphoreCreateFlags flags + + + VkStructureType sType + const void* pNext + VkQueryPoolCreateFlags flags + VkQueryType queryType + uint32_t queryCount + VkQueryPipelineStatisticFlags pipelineStatistics + + + VkStructureType sType + const void* pNext + VkFramebufferCreateFlags flags + VkRenderPass renderPass + uint32_t attachmentCount + const VkImageView* pAttachments + uint32_t width + uint32_t height + uint32_t layers + + + uint32_t vertexCount + uint32_t instanceCount + uint32_t firstVertex + uint32_t firstInstance + + + uint32_t indexCount + uint32_t instanceCount + uint32_t firstIndex + int32_t vertexOffset + uint32_t firstInstance + + + uint32_t x + uint32_t y + uint32_t z + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreCount + const VkSemaphore* pWaitSemaphores + const VkPipelineStageFlags* pWaitDstStageMask + uint32_t commandBufferCount + const VkCommandBuffer* pCommandBuffers + uint32_t signalSemaphoreCount + const VkSemaphore* pSignalSemaphores + + + + VkDisplayKHR display + const char* displayName + VkExtent2D physicalDimensions + VkExtent2D physicalResolution + VkSurfaceTransformFlagsKHR supportedTransforms + VkBool32 planeReorderPossible + VkBool32 persistentContent + + + VkDisplayKHR currentDisplay + uint32_t currentStackIndex + + + VkExtent2D visibleRegion + uint32_t refreshRate + + + VkDisplayModeKHR displayMode + VkDisplayModeParametersKHR parameters + + + VkStructureType sType + const void* pNext + VkDisplayModeCreateFlagsKHR flags + VkDisplayModeParametersKHR parameters + + + VkDisplayPlaneAlphaFlagsKHR supportedAlpha + VkOffset2D minSrcPosition + VkOffset2D maxSrcPosition + VkExtent2D minSrcExtent + VkExtent2D maxSrcExtent + VkOffset2D minDstPosition + VkOffset2D maxDstPosition + VkExtent2D minDstExtent + VkExtent2D maxDstExtent + + + VkStructureType sType + const void* pNext + VkDisplaySurfaceCreateFlagsKHR flags + VkDisplayModeKHR displayMode + uint32_t planeIndex + uint32_t planeStackIndex + VkSurfaceTransformFlagBitsKHR transform + float globalAlpha + VkDisplayPlaneAlphaFlagBitsKHR alphaMode + VkExtent2D imageExtent + + + VkStructureType sType + const void* pNext + VkRect2D srcRect + VkRect2D dstRect + VkBool32 persistent + + + uint32_t minImageCount + uint32_t maxImageCount + VkExtent2D currentExtent + VkExtent2D minImageExtent + VkExtent2D maxImageExtent + uint32_t maxImageArrayLayers + VkSurfaceTransformFlagsKHR supportedTransforms + VkSurfaceTransformFlagBitsKHR currentTransform + VkCompositeAlphaFlagsKHR supportedCompositeAlpha + VkImageUsageFlags supportedUsageFlags + + + VkStructureType sType + const void* pNext + VkAndroidSurfaceCreateFlagsKHR flags + ANativeWindow* window + + + VkStructureType sType + const void* pNext + VkMirSurfaceCreateFlagsKHR flags + MirConnection* connection + MirSurface* mirSurface + + + VkStructureType sType + const void* pNext + VkViSurfaceCreateFlagsNN flags + void* window + + + VkStructureType sType + const void* pNext + VkWaylandSurfaceCreateFlagsKHR flags + struct wl_display* display + struct wl_surface* surface + + + VkStructureType sType + const void* pNext + VkWin32SurfaceCreateFlagsKHR flags + HINSTANCE hinstance + HWND hwnd + + + VkStructureType sType + const void* pNext + VkXlibSurfaceCreateFlagsKHR flags + Display* dpy + Window window + + + VkStructureType sType + const void* pNext + VkXcbSurfaceCreateFlagsKHR flags + xcb_connection_t* connection + xcb_window_t window + + + VkFormat format + VkColorSpaceKHR colorSpace + + + VkStructureType sType + const void* pNext + VkSwapchainCreateFlagsKHR flags + VkSurfaceKHR surface + uint32_t minImageCount + VkFormat imageFormat + VkColorSpaceKHR imageColorSpace + VkExtent2D imageExtent + uint32_t imageArrayLayers + VkImageUsageFlags imageUsage + VkSharingMode imageSharingMode + uint32_t queueFamilyIndexCount + const uint32_t* pQueueFamilyIndices + VkSurfaceTransformFlagBitsKHR preTransform + VkCompositeAlphaFlagBitsKHR compositeAlpha + VkPresentModeKHR presentMode + VkBool32 clipped + VkSwapchainKHR oldSwapchain + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreCount + const VkSemaphore* pWaitSemaphores + uint32_t swapchainCount + const VkSwapchainKHR* pSwapchains + const uint32_t* pImageIndices + VkResult* pResults + + + VkStructureType sType + const void* pNext + VkDebugReportFlagsEXT flags + PFN_vkDebugReportCallbackEXT pfnCallback + void* pUserData + + + VkStructureType sType + const void* pNext + uint32_t disabledValidationCheckCount + VkValidationCheckEXT* pDisabledValidationChecks + + + VkStructureType sType + const void* pNext + VkRasterizationOrderAMD rasterizationOrder + + + VkStructureType sType + const void* pNext + VkDebugReportObjectTypeEXT objectType + uint64_t object + const char* pObjectName + + + VkStructureType sType + const void* pNext + VkDebugReportObjectTypeEXT objectType + uint64_t object + uint64_t tagName + size_t tagSize + const void* pTag + + + VkStructureType sType + const void* pNext + const char* pMarkerName + float color[4] + + + VkStructureType sType + const void* pNext + VkBool32 dedicatedAllocation + + + VkStructureType sType + const void* pNext + VkBool32 dedicatedAllocation + + + VkStructureType sType + const void* pNext + VkImage image + VkBuffer buffer + + + VkImageFormatProperties imageFormatProperties + VkExternalMemoryFeatureFlagsNV externalMemoryFeatures + VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes + VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagsNV handleTypes + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagsNV handleTypes + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagsNV handleType + HANDLE handle + + + VkStructureType sType + const void* pNext + const SECURITY_ATTRIBUTES* pAttributes + DWORD dwAccess + + + VkStructureType sType + const void* pNext + uint32_t acquireCount + const VkDeviceMemory* pAcquireSyncs + const uint64_t* pAcquireKeys + const uint32_t* pAcquireTimeoutMilliseconds + uint32_t releaseCount + const VkDeviceMemory* pReleaseSyncs + const uint64_t* pReleaseKeys + + + + VkStructureType sType + const void* pNext + VkBool32 computeBindingPointSupport + + + VkStructureType sType + const void* pNext + uint32_t maxIndirectCommandsLayoutTokenCount + uint32_t maxObjectEntryCounts + uint32_t minSequenceCountBufferOffsetAlignment + uint32_t minSequenceIndexBufferOffsetAlignment + uint32_t minCommandsTokenBufferOffsetAlignment + + + VkIndirectCommandsTokenTypeNVX tokenType + VkBuffer buffer + VkDeviceSize offset + + + VkIndirectCommandsTokenTypeNVX tokenType + uint32_t bindingUnit + uint32_t dynamicCount + uint32_t divisor + + + VkStructureType sType + const void* pNext + VkPipelineBindPoint pipelineBindPoint + VkIndirectCommandsLayoutUsageFlagsNVX flags + uint32_t tokenCount + const VkIndirectCommandsLayoutTokenNVX* pTokens + + + VkStructureType sType + const void* pNext + VkObjectTableNVX objectTable + VkIndirectCommandsLayoutNVX indirectCommandsLayout + uint32_t indirectCommandsTokenCount + const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens + uint32_t maxSequencesCount + VkCommandBuffer targetCommandBuffer + VkBuffer sequencesCountBuffer + VkDeviceSize sequencesCountOffset + VkBuffer sequencesIndexBuffer + VkDeviceSize sequencesIndexOffset + + + VkStructureType sType + const void* pNext + VkObjectTableNVX objectTable + VkIndirectCommandsLayoutNVX indirectCommandsLayout + uint32_t maxSequencesCount + + + VkStructureType sType + const void* pNext + uint32_t objectCount + const VkObjectEntryTypeNVX* pObjectEntryTypes + const uint32_t* pObjectEntryCounts + const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags + + uint32_t maxUniformBuffersPerDescriptor + uint32_t maxStorageBuffersPerDescriptor + uint32_t maxStorageImagesPerDescriptor + uint32_t maxSampledImagesPerDescriptor + uint32_t maxPipelineLayouts + + + VkObjectEntryTypeNVX type + VkObjectEntryUsageFlagsNVX flags + + + VkObjectEntryTypeNVX type + VkObjectEntryUsageFlagsNVX flags + VkPipeline pipeline + + + VkObjectEntryTypeNVX type + VkObjectEntryUsageFlagsNVX flags + VkPipelineLayout pipelineLayout + VkDescriptorSet descriptorSet + + + VkObjectEntryTypeNVX type + VkObjectEntryUsageFlagsNVX flags + VkBuffer buffer + + + VkObjectEntryTypeNVX type + VkObjectEntryUsageFlagsNVX flags + VkBuffer buffer + VkIndexType indexType + + + VkObjectEntryTypeNVX type + VkObjectEntryUsageFlagsNVX flags + VkPipelineLayout pipelineLayout + VkShaderStageFlags stageFlags + + + VkStructureType sType + void* pNext + VkPhysicalDeviceFeatures features + + + VkStructureType sType + void* pNext + VkPhysicalDeviceProperties properties + + + VkStructureType sType + void* pNext + VkFormatProperties formatProperties + + + VkStructureType sType + void* pNext + VkImageFormatProperties imageFormatProperties + + + VkStructureType sType + const void* pNext + VkFormat format + VkImageType type + VkImageTiling tiling + VkImageUsageFlags usage + VkImageCreateFlags flags + + + VkStructureType sType + void* pNext + VkQueueFamilyProperties queueFamilyProperties + + + VkStructureType sType + void* pNext + VkPhysicalDeviceMemoryProperties memoryProperties + + + VkStructureType sType + void* pNext + VkSparseImageFormatProperties properties + + + VkStructureType sType + const void* pNext + VkFormat format + VkImageType type + VkSampleCountFlagBits samples + VkImageUsageFlags usage + VkImageTiling tiling + + + VkStructureType sType + void* pNext + uint32_t minImageCount + uint32_t maxImageCount + VkExtent2D currentExtent + VkExtent2D minImageExtent + VkExtent2D maxImageExtent + uint32_t maxImageArrayLayers + VkSurfaceTransformFlagsKHR supportedTransforms + VkSurfaceTransformFlagBitsKHR currentTransform + VkCompositeAlphaFlagsKHR supportedCompositeAlpha + VkImageUsageFlags supportedUsageFlags + VkSurfaceCounterFlagsEXT supportedSurfaceCounters + + + VkStructureType sType + const void* pNext + VkDisplayPowerStateEXT powerState + + + VkStructureType sType + const void* pNext + VkDeviceEventTypeEXT deviceEvent + + + VkStructureType sType + const void* pNext + VkDisplayEventTypeEXT displayEvent + + + VkStructureType sType + const void* pNext + VkSurfaceCounterFlagsEXT surfaceCounters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VkResult vkCreateInstance + const VkInstanceCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkInstance* pInstance + + + void vkDestroyInstance + VkInstance instance + const VkAllocationCallbacks* pAllocator + + + VkResult vkEnumeratePhysicalDevices + VkInstance instance + uint32_t* pPhysicalDeviceCount + VkPhysicalDevice* pPhysicalDevices + + + PFN_vkVoidFunction vkGetDeviceProcAddr + VkDevice device + const char* pName + + + PFN_vkVoidFunction vkGetInstanceProcAddr + VkInstance instance + const char* pName + + + void vkGetPhysicalDeviceProperties + VkPhysicalDevice physicalDevice + VkPhysicalDeviceProperties* pProperties + + + void vkGetPhysicalDeviceQueueFamilyProperties + VkPhysicalDevice physicalDevice + uint32_t* pQueueFamilyPropertyCount + VkQueueFamilyProperties* pQueueFamilyProperties + + + void vkGetPhysicalDeviceMemoryProperties + VkPhysicalDevice physicalDevice + VkPhysicalDeviceMemoryProperties* pMemoryProperties + + + void vkGetPhysicalDeviceFeatures + VkPhysicalDevice physicalDevice + VkPhysicalDeviceFeatures* pFeatures + + + void vkGetPhysicalDeviceFormatProperties + VkPhysicalDevice physicalDevice + VkFormat format + VkFormatProperties* pFormatProperties + + + VkResult vkGetPhysicalDeviceImageFormatProperties + VkPhysicalDevice physicalDevice + VkFormat format + VkImageType type + VkImageTiling tiling + VkImageUsageFlags usage + VkImageCreateFlags flags + VkImageFormatProperties* pImageFormatProperties + + + VkResult vkCreateDevice + VkPhysicalDevice physicalDevice + const VkDeviceCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDevice* pDevice + + + void vkDestroyDevice + VkDevice device + const VkAllocationCallbacks* pAllocator + + + VkResult vkEnumerateInstanceLayerProperties + uint32_t* pPropertyCount + VkLayerProperties* pProperties + + + VkResult vkEnumerateInstanceExtensionProperties + const char* pLayerName + uint32_t* pPropertyCount + VkExtensionProperties* pProperties + + + VkResult vkEnumerateDeviceLayerProperties + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkLayerProperties* pProperties + + + VkResult vkEnumerateDeviceExtensionProperties + VkPhysicalDevice physicalDevice + const char* pLayerName + uint32_t* pPropertyCount + VkExtensionProperties* pProperties + + + void vkGetDeviceQueue + VkDevice device + uint32_t queueFamilyIndex + uint32_t queueIndex + VkQueue* pQueue + + + VkResult vkQueueSubmit + VkQueue queue + uint32_t submitCount + const VkSubmitInfo* pSubmits + VkFence fence + + + VkResult vkQueueWaitIdle + VkQueue queue + + + VkResult vkDeviceWaitIdle + VkDevice device + + all sname:VkQueue objects created from pname:device + + + + VkResult vkAllocateMemory + VkDevice device + const VkMemoryAllocateInfo* pAllocateInfo + const VkAllocationCallbacks* pAllocator + VkDeviceMemory* pMemory + + + void vkFreeMemory + VkDevice device + VkDeviceMemory memory + const VkAllocationCallbacks* pAllocator + + + VkResult vkMapMemory + VkDevice device + VkDeviceMemory memory + VkDeviceSize offset + VkDeviceSize size + VkMemoryMapFlags flags + void** ppData + + + void vkUnmapMemory + VkDevice device + VkDeviceMemory memory + + + VkResult vkFlushMappedMemoryRanges + VkDevice device + uint32_t memoryRangeCount + const VkMappedMemoryRange* pMemoryRanges + + + VkResult vkInvalidateMappedMemoryRanges + VkDevice device + uint32_t memoryRangeCount + const VkMappedMemoryRange* pMemoryRanges + + + void vkGetDeviceMemoryCommitment + VkDevice device + VkDeviceMemory memory + VkDeviceSize* pCommittedMemoryInBytes + + + void vkGetBufferMemoryRequirements + VkDevice device + VkBuffer buffer + VkMemoryRequirements* pMemoryRequirements + + + VkResult vkBindBufferMemory + VkDevice device + VkBuffer buffer + VkDeviceMemory memory + VkDeviceSize memoryOffset + + + void vkGetImageMemoryRequirements + VkDevice device + VkImage image + VkMemoryRequirements* pMemoryRequirements + + + VkResult vkBindImageMemory + VkDevice device + VkImage image + VkDeviceMemory memory + VkDeviceSize memoryOffset + + + void vkGetImageSparseMemoryRequirements + VkDevice device + VkImage image + uint32_t* pSparseMemoryRequirementCount + VkSparseImageMemoryRequirements* pSparseMemoryRequirements + + + void vkGetPhysicalDeviceSparseImageFormatProperties + VkPhysicalDevice physicalDevice + VkFormat format + VkImageType type + VkSampleCountFlagBits samples + VkImageUsageFlags usage + VkImageTiling tiling + uint32_t* pPropertyCount + VkSparseImageFormatProperties* pProperties + + + VkResult vkQueueBindSparse + VkQueue queue + uint32_t bindInfoCount + const VkBindSparseInfo* pBindInfo + VkFence fence + + + VkResult vkCreateFence + VkDevice device + const VkFenceCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkFence* pFence + + + void vkDestroyFence + VkDevice device + VkFence fence + const VkAllocationCallbacks* pAllocator + + + VkResult vkResetFences + VkDevice device + uint32_t fenceCount + const VkFence* pFences + + + VkResult vkGetFenceStatus + VkDevice device + VkFence fence + + + VkResult vkWaitForFences + VkDevice device + uint32_t fenceCount + const VkFence* pFences + VkBool32 waitAll + uint64_t timeout + + + VkResult vkCreateSemaphore + VkDevice device + const VkSemaphoreCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSemaphore* pSemaphore + + + void vkDestroySemaphore + VkDevice device + VkSemaphore semaphore + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateEvent + VkDevice device + const VkEventCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkEvent* pEvent + + + void vkDestroyEvent + VkDevice device + VkEvent event + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetEventStatus + VkDevice device + VkEvent event + + + VkResult vkSetEvent + VkDevice device + VkEvent event + + + VkResult vkResetEvent + VkDevice device + VkEvent event + + + VkResult vkCreateQueryPool + VkDevice device + const VkQueryPoolCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkQueryPool* pQueryPool + + + void vkDestroyQueryPool + VkDevice device + VkQueryPool queryPool + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetQueryPoolResults + VkDevice device + VkQueryPool queryPool + uint32_t firstQuery + uint32_t queryCount + size_t dataSize + void* pData + VkDeviceSize stride + VkQueryResultFlags flags + + + VkResult vkCreateBuffer + VkDevice device + const VkBufferCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkBuffer* pBuffer + + + void vkDestroyBuffer + VkDevice device + VkBuffer buffer + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateBufferView + VkDevice device + const VkBufferViewCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkBufferView* pView + + + void vkDestroyBufferView + VkDevice device + VkBufferView bufferView + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateImage + VkDevice device + const VkImageCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkImage* pImage + + + void vkDestroyImage + VkDevice device + VkImage image + const VkAllocationCallbacks* pAllocator + + + void vkGetImageSubresourceLayout + VkDevice device + VkImage image + const VkImageSubresource* pSubresource + VkSubresourceLayout* pLayout + + + VkResult vkCreateImageView + VkDevice device + const VkImageViewCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkImageView* pView + + + void vkDestroyImageView + VkDevice device + VkImageView imageView + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateShaderModule + VkDevice device + const VkShaderModuleCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkShaderModule* pShaderModule + + + void vkDestroyShaderModule + VkDevice device + VkShaderModule shaderModule + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreatePipelineCache + VkDevice device + const VkPipelineCacheCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkPipelineCache* pPipelineCache + + + void vkDestroyPipelineCache + VkDevice device + VkPipelineCache pipelineCache + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetPipelineCacheData + VkDevice device + VkPipelineCache pipelineCache + size_t* pDataSize + void* pData + + + VkResult vkMergePipelineCaches + VkDevice device + VkPipelineCache dstCache + uint32_t srcCacheCount + const VkPipelineCache* pSrcCaches + + + VkResult vkCreateGraphicsPipelines + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkGraphicsPipelineCreateInfo* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + VkResult vkCreateComputePipelines + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkComputePipelineCreateInfo* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + void vkDestroyPipeline + VkDevice device + VkPipeline pipeline + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreatePipelineLayout + VkDevice device + const VkPipelineLayoutCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkPipelineLayout* pPipelineLayout + + + void vkDestroyPipelineLayout + VkDevice device + VkPipelineLayout pipelineLayout + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateSampler + VkDevice device + const VkSamplerCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSampler* pSampler + + + void vkDestroySampler + VkDevice device + VkSampler sampler + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateDescriptorSetLayout + VkDevice device + const VkDescriptorSetLayoutCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDescriptorSetLayout* pSetLayout + + + void vkDestroyDescriptorSetLayout + VkDevice device + VkDescriptorSetLayout descriptorSetLayout + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateDescriptorPool + VkDevice device + const VkDescriptorPoolCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDescriptorPool* pDescriptorPool + + + void vkDestroyDescriptorPool + VkDevice device + VkDescriptorPool descriptorPool + const VkAllocationCallbacks* pAllocator + + + VkResult vkResetDescriptorPool + VkDevice device + VkDescriptorPool descriptorPool + VkDescriptorPoolResetFlags flags + + any sname:VkDescriptorSet objects allocated from pname:descriptorPool + + + + VkResult vkAllocateDescriptorSets + VkDevice device + const VkDescriptorSetAllocateInfo* pAllocateInfo + VkDescriptorSet* pDescriptorSets + + + VkResult vkFreeDescriptorSets + VkDevice device + VkDescriptorPool descriptorPool + uint32_t descriptorSetCount + const VkDescriptorSet* pDescriptorSets + + + void vkUpdateDescriptorSets + VkDevice device + uint32_t descriptorWriteCount + const VkWriteDescriptorSet* pDescriptorWrites + uint32_t descriptorCopyCount + const VkCopyDescriptorSet* pDescriptorCopies + + + VkResult vkCreateFramebuffer + VkDevice device + const VkFramebufferCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkFramebuffer* pFramebuffer + + + void vkDestroyFramebuffer + VkDevice device + VkFramebuffer framebuffer + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateRenderPass + VkDevice device + const VkRenderPassCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkRenderPass* pRenderPass + + + void vkDestroyRenderPass + VkDevice device + VkRenderPass renderPass + const VkAllocationCallbacks* pAllocator + + + void vkGetRenderAreaGranularity + VkDevice device + VkRenderPass renderPass + VkExtent2D* pGranularity + + + VkResult vkCreateCommandPool + VkDevice device + const VkCommandPoolCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkCommandPool* pCommandPool + + + void vkDestroyCommandPool + VkDevice device + VkCommandPool commandPool + const VkAllocationCallbacks* pAllocator + + + VkResult vkResetCommandPool + VkDevice device + VkCommandPool commandPool + VkCommandPoolResetFlags flags + + + VkResult vkAllocateCommandBuffers + VkDevice device + const VkCommandBufferAllocateInfo* pAllocateInfo + VkCommandBuffer* pCommandBuffers + + + void vkFreeCommandBuffers + VkDevice device + VkCommandPool commandPool + uint32_t commandBufferCount + const VkCommandBuffer* pCommandBuffers + + + VkResult vkBeginCommandBuffer + VkCommandBuffer commandBuffer + const VkCommandBufferBeginInfo* pBeginInfo + + the sname:VkCommandPool that pname:commandBuffer was allocated from + + + + VkResult vkEndCommandBuffer + VkCommandBuffer commandBuffer + + the sname:VkCommandPool that pname:commandBuffer was allocated from + + + + VkResult vkResetCommandBuffer + VkCommandBuffer commandBuffer + VkCommandBufferResetFlags flags + + + void vkCmdBindPipeline + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipeline pipeline + + + void vkCmdSetViewport + VkCommandBuffer commandBuffer + uint32_t firstViewport + uint32_t viewportCount + const VkViewport* pViewports + + + void vkCmdSetScissor + VkCommandBuffer commandBuffer + uint32_t firstScissor + uint32_t scissorCount + const VkRect2D* pScissors + + + void vkCmdSetLineWidth + VkCommandBuffer commandBuffer + float lineWidth + + + void vkCmdSetDepthBias + VkCommandBuffer commandBuffer + float depthBiasConstantFactor + float depthBiasClamp + float depthBiasSlopeFactor + + + void vkCmdSetBlendConstants + VkCommandBuffer commandBuffer + const float blendConstants[4] + + + void vkCmdSetDepthBounds + VkCommandBuffer commandBuffer + float minDepthBounds + float maxDepthBounds + + + void vkCmdSetStencilCompareMask + VkCommandBuffer commandBuffer + VkStencilFaceFlags faceMask + uint32_t compareMask + + + void vkCmdSetStencilWriteMask + VkCommandBuffer commandBuffer + VkStencilFaceFlags faceMask + uint32_t writeMask + + + void vkCmdSetStencilReference + VkCommandBuffer commandBuffer + VkStencilFaceFlags faceMask + uint32_t reference + + + void vkCmdBindDescriptorSets + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipelineLayout layout + uint32_t firstSet + uint32_t descriptorSetCount + const VkDescriptorSet* pDescriptorSets + uint32_t dynamicOffsetCount + const uint32_t* pDynamicOffsets + + + void vkCmdBindIndexBuffer + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkIndexType indexType + + + void vkCmdBindVertexBuffers + VkCommandBuffer commandBuffer + uint32_t firstBinding + uint32_t bindingCount + const VkBuffer* pBuffers + const VkDeviceSize* pOffsets + + + void vkCmdDraw + VkCommandBuffer commandBuffer + uint32_t vertexCount + uint32_t instanceCount + uint32_t firstVertex + uint32_t firstInstance + + + void vkCmdDrawIndexed + VkCommandBuffer commandBuffer + uint32_t indexCount + uint32_t instanceCount + uint32_t firstIndex + int32_t vertexOffset + uint32_t firstInstance + + + void vkCmdDrawIndirect + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + uint32_t drawCount + uint32_t stride + + + void vkCmdDrawIndexedIndirect + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + uint32_t drawCount + uint32_t stride + + + void vkCmdDispatch + VkCommandBuffer commandBuffer + uint32_t x + uint32_t y + uint32_t z + + + void vkCmdDispatchIndirect + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + + + void vkCmdCopyBuffer + VkCommandBuffer commandBuffer + VkBuffer srcBuffer + VkBuffer dstBuffer + uint32_t regionCount + const VkBufferCopy* pRegions + + + void vkCmdCopyImage + VkCommandBuffer commandBuffer + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageCopy* pRegions + + + void vkCmdBlitImage + VkCommandBuffer commandBuffer + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageBlit* pRegions + VkFilter filter + + + void vkCmdCopyBufferToImage + VkCommandBuffer commandBuffer + VkBuffer srcBuffer + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkBufferImageCopy* pRegions + + + void vkCmdCopyImageToBuffer + VkCommandBuffer commandBuffer + VkImage srcImage + VkImageLayout srcImageLayout + VkBuffer dstBuffer + uint32_t regionCount + const VkBufferImageCopy* pRegions + + + void vkCmdUpdateBuffer + VkCommandBuffer commandBuffer + VkBuffer dstBuffer + VkDeviceSize dstOffset + VkDeviceSize dataSize + const void* pData + + + void vkCmdFillBuffer + VkCommandBuffer commandBuffer + VkBuffer dstBuffer + VkDeviceSize dstOffset + VkDeviceSize size + uint32_t data + + + void vkCmdClearColorImage + VkCommandBuffer commandBuffer + VkImage image + VkImageLayout imageLayout + const VkClearColorValue* pColor + uint32_t rangeCount + const VkImageSubresourceRange* pRanges + + + void vkCmdClearDepthStencilImage + VkCommandBuffer commandBuffer + VkImage image + VkImageLayout imageLayout + const VkClearDepthStencilValue* pDepthStencil + uint32_t rangeCount + const VkImageSubresourceRange* pRanges + + + void vkCmdClearAttachments + VkCommandBuffer commandBuffer + uint32_t attachmentCount + const VkClearAttachment* pAttachments + uint32_t rectCount + const VkClearRect* pRects + + + void vkCmdResolveImage + VkCommandBuffer commandBuffer + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageResolve* pRegions + + + void vkCmdSetEvent + VkCommandBuffer commandBuffer + VkEvent event + VkPipelineStageFlags stageMask + + + void vkCmdResetEvent + VkCommandBuffer commandBuffer + VkEvent event + VkPipelineStageFlags stageMask + + + void vkCmdWaitEvents + VkCommandBuffer commandBuffer + uint32_t eventCount + const VkEvent* pEvents + VkPipelineStageFlags srcStageMask + VkPipelineStageFlags dstStageMask + uint32_t memoryBarrierCount + const VkMemoryBarrier* pMemoryBarriers + uint32_t bufferMemoryBarrierCount + const VkBufferMemoryBarrier* pBufferMemoryBarriers + uint32_t imageMemoryBarrierCount + const VkImageMemoryBarrier* pImageMemoryBarriers + + + void vkCmdPipelineBarrier + VkCommandBuffer commandBuffer + VkPipelineStageFlags srcStageMask + VkPipelineStageFlags dstStageMask + VkDependencyFlags dependencyFlags + uint32_t memoryBarrierCount + const VkMemoryBarrier* pMemoryBarriers + uint32_t bufferMemoryBarrierCount + const VkBufferMemoryBarrier* pBufferMemoryBarriers + uint32_t imageMemoryBarrierCount + const VkImageMemoryBarrier* pImageMemoryBarriers + + + void vkCmdBeginQuery + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t query + VkQueryControlFlags flags + + + void vkCmdEndQuery + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t query + + + void vkCmdResetQueryPool + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t firstQuery + uint32_t queryCount + + + void vkCmdWriteTimestamp + VkCommandBuffer commandBuffer + VkPipelineStageFlagBits pipelineStage + VkQueryPool queryPool + uint32_t query + + + void vkCmdCopyQueryPoolResults + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t firstQuery + uint32_t queryCount + VkBuffer dstBuffer + VkDeviceSize dstOffset + VkDeviceSize stride + VkQueryResultFlags flags + + + void vkCmdPushConstants + VkCommandBuffer commandBuffer + VkPipelineLayout layout + VkShaderStageFlags stageFlags + uint32_t offset + uint32_t size + const void* pValues + + + void vkCmdBeginRenderPass + VkCommandBuffer commandBuffer + const VkRenderPassBeginInfo* pRenderPassBegin + VkSubpassContents contents + + + void vkCmdNextSubpass + VkCommandBuffer commandBuffer + VkSubpassContents contents + + + void vkCmdEndRenderPass + VkCommandBuffer commandBuffer + + + void vkCmdExecuteCommands + VkCommandBuffer commandBuffer + uint32_t commandBufferCount + const VkCommandBuffer* pCommandBuffers + + + VkResult vkCreateAndroidSurfaceKHR + VkInstance instance + const VkAndroidSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkGetPhysicalDeviceDisplayPropertiesKHR + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkDisplayPropertiesKHR* pProperties + + + VkResult vkGetPhysicalDeviceDisplayPlanePropertiesKHR + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkDisplayPlanePropertiesKHR* pProperties + + + VkResult vkGetDisplayPlaneSupportedDisplaysKHR + VkPhysicalDevice physicalDevice + uint32_t planeIndex + uint32_t* pDisplayCount + VkDisplayKHR* pDisplays + + + VkResult vkGetDisplayModePropertiesKHR + VkPhysicalDevice physicalDevice + VkDisplayKHR display + uint32_t* pPropertyCount + VkDisplayModePropertiesKHR* pProperties + + + VkResult vkCreateDisplayModeKHR + VkPhysicalDevice physicalDevice + VkDisplayKHR display + const VkDisplayModeCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDisplayModeKHR* pMode + + + VkResult vkGetDisplayPlaneCapabilitiesKHR + VkPhysicalDevice physicalDevice + VkDisplayModeKHR mode + uint32_t planeIndex + VkDisplayPlaneCapabilitiesKHR* pCapabilities + + + VkResult vkCreateDisplayPlaneSurfaceKHR + VkInstance instance + const VkDisplaySurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkCreateSharedSwapchainsKHR + VkDevice device + uint32_t swapchainCount + const VkSwapchainCreateInfoKHR* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkSwapchainKHR* pSwapchains + + + VkResult vkCreateMirSurfaceKHR + VkInstance instance + const VkMirSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceMirPresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + MirConnection* connection + + + void vkDestroySurfaceKHR + VkInstance instance + VkSurfaceKHR surface + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetPhysicalDeviceSurfaceSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + VkSurfaceKHR surface + VkBool32* pSupported + + + VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities + + + VkResult vkGetPhysicalDeviceSurfaceFormatsKHR + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + uint32_t* pSurfaceFormatCount + VkSurfaceFormatKHR* pSurfaceFormats + + + VkResult vkGetPhysicalDeviceSurfacePresentModesKHR + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + uint32_t* pPresentModeCount + VkPresentModeKHR* pPresentModes + + + VkResult vkCreateSwapchainKHR + VkDevice device + const VkSwapchainCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSwapchainKHR* pSwapchain + + + void vkDestroySwapchainKHR + VkDevice device + VkSwapchainKHR swapchain + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetSwapchainImagesKHR + VkDevice device + VkSwapchainKHR swapchain + uint32_t* pSwapchainImageCount + VkImage* pSwapchainImages + + + VkResult vkAcquireNextImageKHR + VkDevice device + VkSwapchainKHR swapchain + uint64_t timeout + VkSemaphore semaphore + VkFence fence + uint32_t* pImageIndex + + + VkResult vkQueuePresentKHR + VkQueue queue + const VkPresentInfoKHR* pPresentInfo + + + VkResult vkCreateViSurfaceNN + VkInstance instance + const VkViSurfaceCreateInfoNN* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkCreateWaylandSurfaceKHR + VkInstance instance + const VkWaylandSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + struct wl_display* display + + + VkResult vkCreateWin32SurfaceKHR + VkInstance instance + const VkWin32SurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceWin32PresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + + + VkResult vkCreateXlibSurfaceKHR + VkInstance instance + const VkXlibSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceXlibPresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + Display* dpy + VisualID visualID + + + VkResult vkCreateXcbSurfaceKHR + VkInstance instance + const VkXcbSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceXcbPresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + xcb_connection_t* connection + xcb_visualid_t visual_id + + + VkResult vkCreateDebugReportCallbackEXT + VkInstance instance + const VkDebugReportCallbackCreateInfoEXT* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDebugReportCallbackEXT* pCallback + + + void vkDestroyDebugReportCallbackEXT + VkInstance instance + VkDebugReportCallbackEXT callback + const VkAllocationCallbacks* pAllocator + + + void vkDebugReportMessageEXT + VkInstance instance + VkDebugReportFlagsEXT flags + VkDebugReportObjectTypeEXT objectType + uint64_t object + size_t location + int32_t messageCode + const char* pLayerPrefix + const char* pMessage + + + VkResult vkDebugMarkerSetObjectNameEXT + VkDevice device + VkDebugMarkerObjectNameInfoEXT* pNameInfo + + + VkResult vkDebugMarkerSetObjectTagEXT + VkDevice device + VkDebugMarkerObjectTagInfoEXT* pTagInfo + + + void vkCmdDebugMarkerBeginEXT + VkCommandBuffer commandBuffer + VkDebugMarkerMarkerInfoEXT* pMarkerInfo + + + void vkCmdDebugMarkerEndEXT + VkCommandBuffer commandBuffer + + + void vkCmdDebugMarkerInsertEXT + VkCommandBuffer commandBuffer + VkDebugMarkerMarkerInfoEXT* pMarkerInfo + + + VkResult vkGetPhysicalDeviceExternalImageFormatPropertiesNV + VkPhysicalDevice physicalDevice + VkFormat format + VkImageType type + VkImageTiling tiling + VkImageUsageFlags usage + VkImageCreateFlags flags + VkExternalMemoryHandleTypeFlagsNV externalHandleType + VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties + + + VkResult vkGetMemoryWin32HandleNV + VkDevice device + VkDeviceMemory memory + VkExternalMemoryHandleTypeFlagsNV handleType + HANDLE* pHandle + + + void vkCmdDrawIndirectCountAMD + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkBuffer countBuffer + VkDeviceSize countBufferOffset + uint32_t maxDrawCount + uint32_t stride + + + void vkCmdDrawIndexedIndirectCountAMD + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkBuffer countBuffer + VkDeviceSize countBufferOffset + uint32_t maxDrawCount + uint32_t stride + + + void vkCmdProcessCommandsNVX + VkCommandBuffer commandBuffer + const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo + + + void vkCmdReserveSpaceForCommandsNVX + VkCommandBuffer commandBuffer + const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo + + + VkResult vkCreateIndirectCommandsLayoutNVX + VkDevice device + const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout + + + void vkDestroyIndirectCommandsLayoutNVX + VkDevice device + VkIndirectCommandsLayoutNVX indirectCommandsLayout + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateObjectTableNVX + VkDevice device + const VkObjectTableCreateInfoNVX* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkObjectTableNVX* pObjectTable + + + void vkDestroyObjectTableNVX + VkDevice device + VkObjectTableNVX objectTable + const VkAllocationCallbacks* pAllocator + + + VkResult vkRegisterObjectsNVX + VkDevice device + VkObjectTableNVX objectTable + uint32_t objectCount + const VkObjectTableEntryNVX* const* ppObjectTableEntries + const uint32_t* pObjectIndices + + + VkResult vkUnregisterObjectsNVX + VkDevice device + VkObjectTableNVX objectTable + uint32_t objectCount + const VkObjectEntryTypeNVX* pObjectEntryTypes + const uint32_t* pObjectIndices + + + void vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX + VkPhysicalDevice physicalDevice + VkDeviceGeneratedCommandsFeaturesNVX* pFeatures + VkDeviceGeneratedCommandsLimitsNVX* pLimits + + + void vkGetPhysicalDeviceFeatures2KHR + VkPhysicalDevice physicalDevice + VkPhysicalDeviceFeatures2KHR* pFeatures + + + void vkGetPhysicalDeviceProperties2KHR + VkPhysicalDevice physicalDevice + VkPhysicalDeviceProperties2KHR* pProperties + + + void vkGetPhysicalDeviceFormatProperties2KHR + VkPhysicalDevice physicalDevice + VkFormat format + VkFormatProperties2KHR* pFormatProperties + + + VkResult vkGetPhysicalDeviceImageFormatProperties2KHR + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo + VkImageFormatProperties2KHR* pImageFormatProperties + + + void vkGetPhysicalDeviceQueueFamilyProperties2KHR + VkPhysicalDevice physicalDevice + uint32_t* pQueueFamilyPropertyCount + VkQueueFamilyProperties2KHR* pQueueFamilyProperties + + + void vkGetPhysicalDeviceMemoryProperties2KHR + VkPhysicalDevice physicalDevice + VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties + + + void vkGetPhysicalDeviceSparseImageFormatProperties2KHR + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo + uint32_t* pPropertyCount + VkSparseImageFormatProperties2KHR* pProperties + + + void vkTrimCommandPoolKHR + VkDevice device + VkCommandPool commandPool + VkCommandPoolTrimFlagsKHR flags + + + VkResult vkReleaseDisplayEXT + VkPhysicalDevice physicalDevice + VkDisplayKHR display + + + VkResult vkAcquireXlibDisplayEXT + VkPhysicalDevice physicalDevice + Display* dpy + VkDisplayKHR display + + + VkResult vkGetRandROutputDisplayEXT + VkPhysicalDevice physicalDevice + Display* dpy + RROutput rrOutput + VkDisplayKHR* pDisplay + + + VkResult vkDisplayPowerControlEXT + VkDevice device + VkDisplayKHR display + const VkDisplayPowerInfoEXT* pDisplayPowerInfo + + + VkResult vkRegisterDeviceEventEXT + VkDevice device + const VkDeviceEventInfoEXT* pDeviceEventInfo + const VkAllocationCallbacks* pAllocator + VkFence* pFence + + + VkResult vkRegisterDisplayEventEXT + VkDevice device + VkDisplayKHR display + const VkDisplayEventInfoEXT* pDisplayEventInfo + const VkAllocationCallbacks* pAllocator + VkFence* pFence + + + VkResult vkGetSwapchainCounterEXT + VkDevice device + VkSwapchainKHR swapchain + VkSurfaceCounterFlagBitsEXT counter + uint64_t* pCounterValue + + + VkResult vkGetPhysicalDeviceSurfaceCapabilities2EXT + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + VkSurfaceCapabilities2EXT* pSurfaceCapabilities + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gui/vulkan/vulkan.pri b/src/gui/vulkan/vulkan.pri new file mode 100644 index 0000000000..25635a84c4 --- /dev/null +++ b/src/gui/vulkan/vulkan.pri @@ -0,0 +1,47 @@ +qtConfig(vulkan) { + HEADERS += \ + vulkan/qvulkaninstance.h \ + vulkan/qplatformvulkaninstance.h + + SOURCES += \ + vulkan/qvulkaninstance.cpp \ + vulkan/qplatformvulkaninstance.cpp \ + vulkan/qvulkanfunctions.cpp + + # Applications must inherit the Vulkan header include path. + QMAKE_USE += vulkan/nolink +} + +# Generate qvulkanfunctions.h, qvulkanfunctions_p.h, qvulkanfunctions_p.cpp +QMAKE_QVKGEN_INPUT = vulkan/vk.xml +QMAKE_QVKGEN_LICENSE_HEADER = $$QT_SOURCE_TREE/header.LGPL +qtPrepareTool(QMAKE_QVKGEN, qvkgen) + +qvkgen_h.commands = $$QMAKE_QVKGEN ${QMAKE_FILE_IN} $$shell_quote($$QMAKE_QVKGEN_LICENSE_HEADER) ${QMAKE_FILE_OUT_PATH}/${QMAKE_FILE_OUT_BASE} +qvkgen_h.output = vulkan/qvulkanfunctions.h +qvkgen_h.input = QMAKE_QVKGEN_INPUT +qtConfig(vulkan): \ + qvkgen_h.variable_out = HEADERS +else: \ + qvkgen_h.CONFIG += target_predeps no_link +QMAKE_EXTRA_COMPILERS += qvkgen_h + +qvkgen_ph.commands = $$escape_expand(\\n) +qvkgen_ph.output = vulkan/qvulkanfunctions_p.h +qvkgen_ph.input = QMAKE_QVKGEN_INPUT +qvkgen_ph.depends += vulkan/qvulkanfunctions.h +qtConfig(vulkan): \ + qvkgen_ph.variable_out = HEADERS +else: \ + qvkgen_ph.CONFIG += target_predeps no_link +QMAKE_EXTRA_COMPILERS += qvkgen_ph + +qvkgen_pimpl.commands = $$escape_expand(\\n) +qvkgen_pimpl.output = vulkan/qvulkanfunctions_p.cpp +qvkgen_pimpl.input = QMAKE_QVKGEN_INPUT +qvkgen_pimpl.depends += vulkan/qvulkanfunctions_p.h +qtConfig(vulkan): \ + qvkgen_pimpl.variable_out = SOURCES +else: \ + qvkgen_pimpl.CONFIG += target_predeps no_link +QMAKE_EXTRA_COMPILERS += qvkgen_pimpl diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 7a97a12bae..9bfa849685 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -42,3 +42,6 @@ darwin { macos: \ SUBDIRS += cglconvenience } + +qtConfig(vulkan): \ + SUBDIRS += vkconvenience diff --git a/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp new file mode 100644 index 0000000000..1a2a07260a --- /dev/null +++ b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance.cpp @@ -0,0 +1,357 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qbasicvulkanplatforminstance_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcVk, "qt.vulkan") + +/*! + \class QBasicPlatformVulkanInstance + \brief A generic platform Vulkan instance implementation. + \since 5.10 + \internal + \ingroup qpa + + Implements QPlatformVulkanInstance, serving as a base for platform-specific + implementations. The library loading and any WSI-specifics are excluded. + + Subclasses are expected to call init() from their constructor and + initInstance() from their createOrAdoptInstance() implementation. + */ + +QBasicPlatformVulkanInstance::QBasicPlatformVulkanInstance() + : m_vkInst(VK_NULL_HANDLE), + m_vkGetInstanceProcAddr(nullptr), + m_ownsVkInst(false), + m_errorCode(VK_SUCCESS), + m_debugCallback(0) +{ +} + +QBasicPlatformVulkanInstance::~QBasicPlatformVulkanInstance() +{ + if (!m_vkInst) + return; + + if (m_debugCallback && m_vkDestroyDebugReportCallbackEXT) + m_vkDestroyDebugReportCallbackEXT(m_vkInst, m_debugCallback, nullptr); + + if (m_ownsVkInst) + m_vkDestroyInstance(m_vkInst, nullptr); +} + +void QBasicPlatformVulkanInstance::init(QLibrary *lib) +{ + if (m_vkGetInstanceProcAddr) + return; + + qCDebug(lcVk, "Vulkan init (%s)", qPrintable(lib->fileName())); + + // While not strictly required with every implementation, try to follow the spec + // and do not rely on core functions being exported. + // + // 1. dlsym vkGetInstanceProcAddr + // 2. with a special null instance resolve vkCreateInstance and vkEnumerateInstance* + // 3. all other core functions are resolved with the created instance + + m_vkGetInstanceProcAddr = reinterpret_cast(lib->resolve("vkGetInstanceProcAddr")); + if (!m_vkGetInstanceProcAddr) { + qWarning("Failed to find vkGetInstanceProcAddr"); + return; + } + + m_vkCreateInstance = reinterpret_cast(m_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance")); + if (!m_vkCreateInstance) { + qWarning("Failed to find vkCreateInstance"); + return; + } + m_vkEnumerateInstanceLayerProperties = reinterpret_cast( + m_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties")); + if (!m_vkEnumerateInstanceLayerProperties) { + qWarning("Failed to find vkEnumerateInstanceLayerProperties"); + return; + } + m_vkEnumerateInstanceExtensionProperties = reinterpret_cast( + m_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties")); + if (!m_vkEnumerateInstanceExtensionProperties) { + qWarning("Failed to find vkEnumerateInstanceExtensionProperties"); + return; + } + + uint32_t layerCount = 0; + m_vkEnumerateInstanceLayerProperties(&layerCount, nullptr); + if (layerCount) { + QVector layerProps(layerCount); + m_vkEnumerateInstanceLayerProperties(&layerCount, layerProps.data()); + m_supportedLayers.reserve(layerCount); + for (const VkLayerProperties &p : qAsConst(layerProps)) { + QVulkanLayer layer; + layer.name = p.layerName; + layer.version = p.implementationVersion; + layer.specVersion = QVersionNumber(VK_VERSION_MAJOR(p.specVersion), + VK_VERSION_MINOR(p.specVersion), + VK_VERSION_PATCH(p.specVersion)); + layer.description = p.description; + m_supportedLayers.append(layer); + } + } + qCDebug(lcVk) << "Supported Vulkan instance layers:" << m_supportedLayers; + + uint32_t extCount = 0; + m_vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); + if (extCount) { + QVector extProps(extCount); + m_vkEnumerateInstanceExtensionProperties(nullptr, &extCount, extProps.data()); + m_supportedExtensions.reserve(extCount); + for (const VkExtensionProperties &p : qAsConst(extProps)) { + QVulkanExtension ext; + ext.name = p.extensionName; + ext.version = p.specVersion; + m_supportedExtensions.append(ext); + } + } + qDebug(lcVk) << "Supported Vulkan instance extensions:" << m_supportedExtensions; +} + +QVulkanInfoVector QBasicPlatformVulkanInstance::supportedLayers() const +{ + return m_supportedLayers; +} + +QVulkanInfoVector QBasicPlatformVulkanInstance::supportedExtensions() const +{ + return m_supportedExtensions; +} + +void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const QByteArrayList &extraExts) +{ + if (!m_vkGetInstanceProcAddr) { + qWarning("initInstance: No Vulkan library available"); + return; + } + + m_vkInst = instance->vkInstance(); // when non-null we are adopting an existing instance + + QVulkanInstance::Flags flags = instance->flags(); + m_enabledLayers = instance->layers(); + m_enabledExtensions = instance->extensions(); + + if (!m_vkInst) { + VkApplicationInfo appInfo; + memset(&appInfo, 0, sizeof(appInfo)); + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + QByteArray appName = QCoreApplication::applicationName().toUtf8(); + appInfo.pApplicationName = appName.constData(); + const QVersionNumber apiVersion = instance->apiVersion(); + if (!apiVersion.isNull()) { + appInfo.apiVersion = VK_MAKE_VERSION(apiVersion.majorVersion(), + apiVersion.minorVersion(), + apiVersion.microVersion()); + } + + if (!flags.testFlag(QVulkanInstance::NoDebugOutputRedirect)) + m_enabledExtensions.append("VK_EXT_debug_report"); + + m_enabledExtensions.append("VK_KHR_surface"); + + for (const QByteArray &ext : extraExts) + m_enabledExtensions.append(ext); + + // No clever stuff with QSet and friends: the order for layers matters + // and the user-provided order must be kept. + for (int i = 0; i < m_enabledLayers.count(); ++i) { + const QByteArray &layerName(m_enabledLayers[i]); + if (!m_supportedLayers.contains(layerName)) + m_enabledLayers.removeAt(i--); + } + qDebug(lcVk) << "Enabling Vulkan instance layers:" << m_enabledLayers; + for (int i = 0; i < m_enabledExtensions.count(); ++i) { + const QByteArray &extName(m_enabledExtensions[i]); + if (!m_supportedExtensions.contains(extName)) + m_enabledExtensions.removeAt(i--); + } + qDebug(lcVk) << "Enabling Vulkan instance extensions:" << m_enabledExtensions; + + VkInstanceCreateInfo instInfo; + memset(&instInfo, 0, sizeof(instInfo)); + instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instInfo.pApplicationInfo = &appInfo; + + QVector layerNameVec; + for (const QByteArray &ba : qAsConst(m_enabledLayers)) + layerNameVec.append(ba.constData()); + if (!layerNameVec.isEmpty()) { + instInfo.enabledLayerCount = layerNameVec.count(); + instInfo.ppEnabledLayerNames = layerNameVec.constData(); + } + + QVector extNameVec; + for (const QByteArray &ba : qAsConst(m_enabledExtensions)) + extNameVec.append(ba.constData()); + if (!extNameVec.isEmpty()) { + instInfo.enabledExtensionCount = extNameVec.count(); + instInfo.ppEnabledExtensionNames = extNameVec.constData(); + } + + m_errorCode = m_vkCreateInstance(&instInfo, nullptr, &m_vkInst); + if (m_errorCode != VK_SUCCESS || !m_vkInst) { + qWarning("Failed to create Vulkan instance: %d", m_errorCode); + return; + } + + m_vkDestroyInstance = reinterpret_cast(m_vkGetInstanceProcAddr(m_vkInst, "vkDestroyInstance")); + if (!m_vkDestroyInstance) { + qWarning("Failed to find vkDestroyInstance"); + m_vkInst = VK_NULL_HANDLE; + return; + } + + m_ownsVkInst = true; + } + + m_getPhysDevSurfaceSupport = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceSurfaceSupportKHR")); + if (!m_getPhysDevSurfaceSupport) + qWarning("Failed to find vkGetPhysicalDeviceSurfaceSupportKHR"); + + if (!flags.testFlag(QVulkanInstance::NoDebugOutputRedirect)) + setupDebugOutput(); +} + +bool QBasicPlatformVulkanInstance::isValid() const +{ + return m_vkInst != VK_NULL_HANDLE; +} + +VkResult QBasicPlatformVulkanInstance::errorCode() const +{ + return m_errorCode; +} + +VkInstance QBasicPlatformVulkanInstance::vkInstance() const +{ + return m_vkInst; +} + +QByteArrayList QBasicPlatformVulkanInstance::enabledLayers() const +{ + return m_enabledLayers; +} + +QByteArrayList QBasicPlatformVulkanInstance::enabledExtensions() const +{ + return m_enabledExtensions; +} + +PFN_vkVoidFunction QBasicPlatformVulkanInstance::getInstanceProcAddr(const char *name) +{ + if (!name) + return nullptr; + + const bool needsNullInstance = !strcmp(name, "vkEnumerateInstanceLayerProperties") + || !strcmp(name, "vkEnumerateInstanceExtensionProperties"); + + return m_vkGetInstanceProcAddr(needsNullInstance ? 0 : m_vkInst, name); +} + +bool QBasicPlatformVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + QWindow *window) +{ + if (!m_getPhysDevSurfaceSupport) + return true; + + VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window); + VkBool32 supported = false; + m_getPhysDevSurfaceSupport(physicalDevice, queueFamilyIndex, surface, &supported); + + return supported; +} + +static VKAPI_ATTR VkBool32 VKAPI_CALL defaultDebugCallbackFunc(VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char *pLayerPrefix, + const char *pMessage, + void *pUserData) +{ + Q_UNUSED(flags); + Q_UNUSED(objectType); + Q_UNUSED(object); + Q_UNUSED(location); + Q_UNUSED(pUserData); + + // not categorized, just route to plain old qDebug + qDebug("vkDebug: %s: %d: %s", pLayerPrefix, messageCode, pMessage); + + return VK_FALSE; +} + +void QBasicPlatformVulkanInstance::setupDebugOutput() +{ + if (!m_enabledExtensions.contains("VK_EXT_debug_report")) + return; + + PFN_vkCreateDebugReportCallbackEXT createDebugReportCallback = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkCreateDebugReportCallbackEXT")); + m_vkDestroyDebugReportCallbackEXT = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkDestroyDebugReportCallbackEXT")); + + VkDebugReportCallbackCreateInfoEXT dbgCallbackInfo; + memset(&dbgCallbackInfo, 0, sizeof(dbgCallbackInfo)); + dbgCallbackInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; + dbgCallbackInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT + | VK_DEBUG_REPORT_WARNING_BIT_EXT + | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + dbgCallbackInfo.pfnCallback = defaultDebugCallbackFunc; + + VkResult err = createDebugReportCallback(m_vkInst, &dbgCallbackInfo, nullptr, &m_debugCallback); + if (err != VK_SUCCESS) + qWarning("Failed to create debug report callback: %d", err); +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance_p.h b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance_p.h new file mode 100644 index 0000000000..748b138f01 --- /dev/null +++ b/src/platformsupport/vkconvenience/qbasicvulkanplatforminstance_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 QBASICVULKANPLATFORMINSTANCE_P_H +#define QBASICVULKANPLATFORMINSTANCE_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 + +QT_BEGIN_NAMESPACE + +class QLibrary; + +class QBasicPlatformVulkanInstance : public QPlatformVulkanInstance +{ +public: + QBasicPlatformVulkanInstance(); + ~QBasicPlatformVulkanInstance(); + + QVulkanInfoVector supportedLayers() const override; + QVulkanInfoVector supportedExtensions() const override; + bool isValid() const override; + VkResult errorCode() const override; + VkInstance vkInstance() const override; + QByteArrayList enabledLayers() const override; + QByteArrayList enabledExtensions() const override; + PFN_vkVoidFunction getInstanceProcAddr(const char *name) override; + bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override; + +protected: + void init(QLibrary *lib); + void initInstance(QVulkanInstance *instance, const QByteArrayList &extraExts); + + VkInstance m_vkInst; + PFN_vkGetInstanceProcAddr m_vkGetInstanceProcAddr; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR m_getPhysDevSurfaceSupport; + +private: + void setupDebugOutput(); + + bool m_ownsVkInst; + VkResult m_errorCode; + QVulkanInfoVector m_supportedLayers; + QVulkanInfoVector m_supportedExtensions; + QByteArrayList m_enabledLayers; + QByteArrayList m_enabledExtensions; + + PFN_vkCreateInstance m_vkCreateInstance; + PFN_vkEnumerateInstanceLayerProperties m_vkEnumerateInstanceLayerProperties; + PFN_vkEnumerateInstanceExtensionProperties m_vkEnumerateInstanceExtensionProperties; + + PFN_vkDestroyInstance m_vkDestroyInstance; + + VkDebugReportCallbackEXT m_debugCallback; + PFN_vkDestroyDebugReportCallbackEXT m_vkDestroyDebugReportCallbackEXT; +}; + +QT_END_NAMESPACE + +#endif // QBASICVULKANPLATFORMINSTANCE_P_H diff --git a/src/platformsupport/vkconvenience/vkconvenience.pro b/src/platformsupport/vkconvenience/vkconvenience.pro new file mode 100644 index 0000000000..7a4cdb041d --- /dev/null +++ b/src/platformsupport/vkconvenience/vkconvenience.pro @@ -0,0 +1,16 @@ +TARGET = QtVulkanSupport +MODULE = vulkan_support + +QT = core-private gui-private +CONFIG += static internal_module + +DEFINES += QT_NO_CAST_FROM_ASCII +PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h + +SOURCES += \ + qbasicvulkanplatforminstance.cpp + +HEADERS += \ + qbasicvulkanplatforminstance_p.h + +load(qt_module) diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 03592bfa7d..73db9e93a3 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -11,6 +11,8 @@ QT += \ eventdispatcher_support-private accessibility_support-private \ fontdatabase_support-private egl_support-private +qtConfig(vulkan): QT += vulkan_support-private + OTHER_FILES += $$PWD/android.json INCLUDEPATH += \ @@ -78,6 +80,13 @@ HEADERS += $$PWD/qandroidplatformintegration.h \ qtConfig(android-style-assets): SOURCES += $$PWD/extract.cpp else: SOURCES += $$PWD/extract-dummy.cpp +qtConfig(vulkan) { + SOURCES += $$PWD/qandroidplatformvulkaninstance.cpp \ + $$PWD/qandroidplatformvulkanwindow.cpp + HEADERS += $$PWD/qandroidplatformvulkaninstance.h \ + $$PWD/qandroidplatformvulkanwindow.h +} + PLUGIN_TYPE = platforms load(qt_plugin) diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 13f9dc5a68..0668c43d18 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -69,6 +69,11 @@ #include +#if QT_CONFIG(vulkan) +#include "qandroidplatformvulkanwindow.h" +#include "qandroidplatformvulkaninstance.h" +#endif + QT_BEGIN_NAMESPACE int QAndroidPlatformIntegration::m_defaultGeometryWidth = 320; @@ -121,6 +126,23 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA return 0; } +void *QAndroidPlatformNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) +{ +#if QT_CONFIG(vulkan) + if (resource == "vkSurface") { + if (window->surfaceType() == QSurface::VulkanSurface) { + QAndroidPlatformVulkanWindow *w = static_cast(window->handle()); + // return a pointer to the VkSurfaceKHR, not the value + return w ? w->vkSurface() : nullptr; + } + } +#else + Q_UNUSED(resource); + Q_UNUSED(window); +#endif + return nullptr; +} + QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶mList) : m_touchDevice(nullptr) #ifndef QT_NO_ACCESSIBILITY @@ -286,6 +308,11 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind if (!QtAndroid::activity()) return nullptr; +#if QT_CONFIG(vulkan) + if (window->surfaceType() == QSurface::VulkanSurface) + return new QAndroidPlatformVulkanWindow(window); +#endif + return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); } @@ -426,4 +453,13 @@ void QAndroidPlatformIntegration::setScreenSize(int width, int height) QMetaObject::invokeMethod(m_primaryScreen, "setSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height))); } +#if QT_CONFIG(vulkan) + +QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + return new QAndroidPlatformVulkanInstance(instance); +} + +#endif // QT_CONFIG(vulkan) + QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index be10c3d161..0d2a0d2ad6 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -40,6 +40,8 @@ #ifndef QANDROIDPLATFORMINTERATION_H #define QANDROIDPLATFORMINTERATION_H +#include + #include #include #include @@ -64,6 +66,7 @@ class QAndroidPlatformNativeInterface: public QPlatformNativeInterface { public: void *nativeResourceForIntegration(const QByteArray &resource) override; + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override; std::shared_ptr m_androidStyle; }; @@ -124,6 +127,10 @@ public: void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; } static void setDefaultApplicationState(Qt::ApplicationState applicationState) { m_defaultApplicationState = applicationState; } +#if QT_CONFIG(vulkan) + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; +#endif + private: EGLDisplay m_eglDisplay; QTouchDevice *m_touchDevice; diff --git a/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp b/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp new file mode 100644 index 0000000000..a411d0f007 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qandroidplatformvulkaninstance.h" + +QT_BEGIN_NAMESPACE + +QAndroidPlatformVulkanInstance::QAndroidPlatformVulkanInstance(QVulkanInstance *instance) + : m_instance(instance) +{ + m_lib.setFileName(QStringLiteral("vulkan")); + + if (!m_lib.load()) { + qWarning("Failed to load %s", qPrintable(m_lib.fileName())); + return; + } + + init(&m_lib); +} + +void QAndroidPlatformVulkanInstance::createOrAdoptInstance() +{ + initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_KHR_android_surface")); +} + +QAndroidPlatformVulkanInstance::~QAndroidPlatformVulkanInstance() +{ +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformvulkaninstance.h b/src/plugins/platforms/android/qandroidplatformvulkaninstance.h new file mode 100644 index 0000000000..67edcceed9 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformvulkaninstance.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 QANDROIDPLATFORMVULKANINSTANCE_H +#define QANDROIDPLATFORMVULKANINSTANCE_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QAndroidPlatformVulkanInstance : public QBasicPlatformVulkanInstance +{ +public: + QAndroidPlatformVulkanInstance(QVulkanInstance *instance); + ~QAndroidPlatformVulkanInstance(); + + void createOrAdoptInstance() override; + +private: + QVulkanInstance *m_instance; + QLibrary m_lib; +}; + +QT_END_NAMESPACE + +#endif // QANDROIDPLATFORMVULKANINSTANCE_H diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp new file mode 100644 index 0000000000..cc41a871f3 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qandroidplatformvulkanwindow.h" +#include "qandroidplatformscreen.h" +#include "androidjnimain.h" +#include "qandroideventdispatcher.h" +#include "androiddeadlockprotector.h" + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window) + : QAndroidPlatformWindow(window), + m_nativeSurfaceId(-1), + m_nativeWindow(nullptr), + m_vkSurface(0), + m_createVkSurface(nullptr), + m_destroyVkSurface(nullptr) +{ +} + +QAndroidPlatformVulkanWindow::~QAndroidPlatformVulkanWindow() +{ + m_surfaceWaitCondition.wakeOne(); + lockSurface(); + if (m_nativeSurfaceId != -1) + QtAndroid::destroySurface(m_nativeSurfaceId); + clearSurface(); + unlockSurface(); +} + +void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect) +{ + if (rect == geometry()) + return; + + m_oldGeometry = geometry(); + + QAndroidPlatformWindow::setGeometry(rect); + if (m_nativeSurfaceId != -1) + QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect); + + QRect availableGeometry = screen()->availableGeometry(); + if (m_oldGeometry.width() == 0 + && m_oldGeometry.height() == 0 + && rect.width() > 0 + && rect.height() > 0 + && availableGeometry.width() > 0 + && availableGeometry.height() > 0) { + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size())); + } + + if (rect.topLeft() != m_oldGeometry.topLeft()) + repaint(QRegion(rect)); +} + +void QAndroidPlatformVulkanWindow::applicationStateChanged(Qt::ApplicationState state) +{ + QAndroidPlatformWindow::applicationStateChanged(state); + if (state <= Qt::ApplicationHidden) { + lockSurface(); + if (m_nativeSurfaceId != -1) { + QtAndroid::destroySurface(m_nativeSurfaceId); + m_nativeSurfaceId = -1; + } + clearSurface(); + unlockSurface(); + } +} + +QSurfaceFormat QAndroidPlatformVulkanWindow::format() const +{ + return window()->requestedFormat(); +} + +void QAndroidPlatformVulkanWindow::clearSurface() +{ + if (m_vkSurface && m_destroyVkSurface) { + m_destroyVkSurface(window()->vulkanInstance()->vkInstance(), m_vkSurface, nullptr); + m_vkSurface = 0; + } + + if (m_nativeWindow) { + ANativeWindow_release(m_nativeWindow); + m_nativeWindow = nullptr; + } +} + +void QAndroidPlatformVulkanWindow::sendExpose() +{ + QRect availableGeometry = screen()->availableGeometry(); + if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0) + QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size()))); +} + +void QAndroidPlatformVulkanWindow::surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) +{ + Q_UNUSED(jniEnv); + Q_UNUSED(w); + Q_UNUSED(h); + + lockSurface(); + m_androidSurfaceObject = surface; + if (surface) + m_surfaceWaitCondition.wakeOne(); + unlockSurface(); + + if (surface) + sendExpose(); +} + +VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface() +{ + if (QAndroidEventDispatcherStopper::stopped()) + return &m_vkSurface; + + bool needsExpose = false; + if (!m_vkSurface) { + clearSurface(); + + QMutexLocker lock(&m_surfaceMutex); + if (m_nativeSurfaceId == -1) { + AndroidDeadlockProtector protector; + if (!protector.acquire()) + return &m_vkSurface; + const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); + m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32); + m_surfaceWaitCondition.wait(&m_surfaceMutex); + } + + if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid()) + return &m_vkSurface; + + QJNIEnvironmentPrivate env; + m_nativeWindow = ANativeWindow_fromSurface(env, m_androidSurfaceObject.object()); + + VkAndroidSurfaceCreateInfoKHR surfaceInfo; + memset(&surfaceInfo, 0, sizeof(surfaceInfo)); + surfaceInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + surfaceInfo.window = m_nativeWindow; + QVulkanInstance *inst = window()->vulkanInstance(); + if (!inst) { + qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?"); + return &m_vkSurface; + } + if (!m_createVkSurface) { + m_createVkSurface = reinterpret_cast( + inst->getInstanceProcAddr("vkCreateAndroidSurfaceKHR")); + } + if (!m_destroyVkSurface) { + m_destroyVkSurface = reinterpret_cast( + inst->getInstanceProcAddr("vkDestroySurfaceKHR")); + } + VkResult err = m_createVkSurface(inst->vkInstance(), &surfaceInfo, nullptr, &m_vkSurface); + if (err != VK_SUCCESS) + qWarning("Failed to create Android VkSurface: %d", err); + + needsExpose = true; + } + + if (needsExpose) + sendExpose(); + + return &m_vkSurface; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h new file mode 100644 index 0000000000..19eca98720 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 QANDROIDPLATFORMVULKANWINDOW_H +#define QANDROIDPLATFORMVULKANWINDOW_H + +#if defined(VULKAN_H_) && !defined(VK_USE_PLATFORM_ANDROID_KHR) +#error "vulkan.h included without Android WSI" +#endif + +#define VK_USE_PLATFORM_ANDROID_KHR + +#include +#include + +#include "androidsurfaceclient.h" +#include "qandroidplatformwindow.h" + +#include "qandroidplatformvulkaninstance.h" + +QT_BEGIN_NAMESPACE + +class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient +{ +public: + explicit QAndroidPlatformVulkanWindow(QWindow *window); + ~QAndroidPlatformVulkanWindow(); + + void setGeometry(const QRect &rect) override; + QSurfaceFormat format() const override; + void applicationStateChanged(Qt::ApplicationState) override; + + VkSurfaceKHR *vkSurface(); + +protected: + void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override; + +private: + void sendExpose(); + void clearSurface(); + + int m_nativeSurfaceId; + ANativeWindow *m_nativeWindow; + QJNIObjectPrivate m_androidSurfaceObject; + QWaitCondition m_surfaceWaitCondition; + QSurfaceFormat m_format; + QRect m_oldGeometry; + VkSurfaceKHR m_vkSurface; + PFN_vkCreateAndroidSurfaceKHR m_createVkSurface; + PFN_vkDestroySurfaceKHR m_destroyVkSurface; +}; + +QT_END_NAMESPACE + +#endif // QANDROIDPLATFORMVULKANWINDOW_H diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro index 224f122fc4..87405ae19f 100644 --- a/src/plugins/platforms/direct2d/direct2d.pro +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -5,6 +5,8 @@ QT += \ eventdispatcher_support-private accessibility_support-private \ fontdatabase_support-private theme_support-private +qtConfig(vulkan): QT += vulkan_support-private + LIBS += -ldwmapi -ld2d1 -ld3d11 -ldwrite -lVersion -lgdi32 include(../windows/windows.pri) diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 316f93e3ac..6614c76a53 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -606,4 +606,11 @@ void QWindowsIntegration::beep() const MessageBeep(MB_OK); // For QApplication } +#if QT_CONFIG(vulkan) +QPlatformVulkanInstance *QWindowsIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + return new QWindowsVulkanInstance(instance); +} +#endif + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 607203829f..fbdb341dab 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -113,6 +113,10 @@ public: QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const override; #endif +#if QT_CONFIG(vulkan) + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; +#endif + protected: virtual QWindowsWindow *createPlatformWindowHelper(QWindow *window, const QWindowsWindowData &) const; diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index d750eef19d..8bc2e1b441 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -64,7 +64,8 @@ enum ResourceType { HandleType, GlHandleType, GetDCType, - ReleaseDCType + ReleaseDCType, + VkSurface }; static int resourceType(const QByteArray &key) @@ -77,7 +78,8 @@ static int resourceType(const QByteArray &key) "handle", "glhandle", "getdc", - "releasedc" + "releasedc", + "vkSurface" }; const char ** const end = names + sizeof(names) / sizeof(names[0]); const char **result = std::find(names, end, key); @@ -112,6 +114,12 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc case QWindow::OpenGLSurface: case QWindow::OpenVGSurface: break; +#if QT_CONFIG(vulkan) + case QWindow::VulkanSurface: + if (type == VkSurface) + return bw->surface(nullptr, nullptr); // returns the address of the VkSurfaceKHR, not the value, as expected + break; +#endif } qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); return 0; diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp new file mode 100644 index 0000000000..d81ee8ba29 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qwindowsvulkaninstance.h" + +QT_BEGIN_NAMESPACE + +QWindowsVulkanInstance::QWindowsVulkanInstance(QVulkanInstance *instance) + : m_instance(instance), + m_getPhysDevPresSupport(nullptr), + m_createSurface(nullptr), + m_destroySurface(nullptr) +{ + if (qEnvironmentVariableIsSet("QT_VULKAN_LIB")) + m_lib.setFileName(QString::fromUtf8(qgetenv("QT_VULKAN_LIB"))); + else + m_lib.setFileName(QStringLiteral("vulkan-1")); + + if (!m_lib.load()) { + qWarning("Failed to load %s: %s", qPrintable(m_lib.fileName()), qPrintable(m_lib.errorString())); + return; + } + + init(&m_lib); +} + +void QWindowsVulkanInstance::createOrAdoptInstance() +{ + initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_KHR_win32_surface")); + + if (!m_vkInst) + return; + + m_getPhysDevPresSupport = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceWin32PresentationSupportKHR")); + if (!m_getPhysDevPresSupport) + qWarning("Failed to find vkGetPhysicalDeviceWin32PresentationSupportKHR"); +} + +QWindowsVulkanInstance::~QWindowsVulkanInstance() +{ +} + +bool QWindowsVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + QWindow *window) +{ + if (!m_getPhysDevPresSupport || !m_getPhysDevSurfaceSupport) + return true; + + bool ok = m_getPhysDevPresSupport(physicalDevice, queueFamilyIndex); + + VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window); + VkBool32 supported = false; + m_getPhysDevSurfaceSupport(physicalDevice, queueFamilyIndex, surface, &supported); + ok &= bool(supported); + + return ok; +} + +VkSurfaceKHR QWindowsVulkanInstance::createSurface(HWND win) +{ + VkSurfaceKHR surface = 0; + + if (!m_createSurface) { + m_createSurface = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkCreateWin32SurfaceKHR")); + } + if (!m_createSurface) { + qWarning("Failed to find vkCreateWin32SurfaceKHR"); + return surface; + } + if (!m_destroySurface) { + m_destroySurface = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkDestroySurfaceKHR")); + } + if (!m_destroySurface) { + qWarning("Failed to find vkDestroySurfaceKHR"); + return surface; + } + + VkWin32SurfaceCreateInfoKHR surfaceInfo; + memset(&surfaceInfo, 0, sizeof(surfaceInfo)); + surfaceInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + surfaceInfo.hinstance = GetModuleHandle(nullptr); + surfaceInfo.hwnd = win; + VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface); + if (err != VK_SUCCESS) + qWarning("Failed to create Vulkan surface: %d", err); + + return surface; +} + +void QWindowsVulkanInstance::destroySurface(VkSurfaceKHR surface) +{ + if (m_destroySurface && surface) + m_destroySurface(m_vkInst, surface, nullptr); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.h b/src/plugins/platforms/windows/qwindowsvulkaninstance.h new file mode 100644 index 0000000000..ca60ab7627 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 QWINDOWSVULKANINSTANCE_H +#define QWINDOWSVULKANINSTANCE_H + +#if defined(VULKAN_H_) && !defined(VK_USE_PLATFORM_WIN32_KHR) +#error "vulkan.h included without Win32 WSI" +#endif + +#define VK_USE_PLATFORM_WIN32_KHR + +#include +#include + +QT_BEGIN_NAMESPACE + +class QWindowsVulkanInstance : public QBasicPlatformVulkanInstance +{ +public: + QWindowsVulkanInstance(QVulkanInstance *instance); + ~QWindowsVulkanInstance(); + + void createOrAdoptInstance() override; + bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override; + + VkSurfaceKHR createSurface(HWND win); + void destroySurface(VkSurfaceKHR surface); + +private: + QVulkanInstance *m_instance; + QLibrary m_lib; + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR m_getPhysDevPresSupport; + PFN_vkCreateWin32SurfaceKHR m_createSurface; + PFN_vkDestroySurfaceKHR m_destroySurface; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSVULKANINSTANCE_H diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 8950ec3bfc..25f7e11c60 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -67,6 +67,10 @@ #include +#if QT_CONFIG(vulkan) +#include "qwindowsvulkaninstance.h" +#endif + QT_BEGIN_NAMESPACE enum { @@ -308,13 +312,15 @@ static QWindow::Visibility windowVisibility_sys(HWND hwnd) return QWindow::Windowed; } -static inline bool windowIsOpenGL(const QWindow *w) +static inline bool windowIsAccelerated(const QWindow *w) { switch (w->surfaceType()) { case QSurface::OpenGLSurface: return true; case QSurface::RasterGLSurface: return qt_window_private(const_cast(w))->compositing; + case QSurface::VulkanSurface: + return true; default: return false; } @@ -375,11 +381,11 @@ bool QWindowsWindow::setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool has return needsLayered; } -static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bool openGL, qreal level) +static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bool accelerated, qreal level) { if (QWindowsWindow::setWindowLayered(hwnd, flags, hasAlpha, level)) { const BYTE alpha = BYTE(qRound(255.0 * level)); - if (hasAlpha && !openGL && (flags & Qt::FramelessWindowHint)) { + if (hasAlpha && !accelerated && (flags & Qt::FramelessWindowHint)) { // Non-GL windows with alpha: Use blend function to update. BLENDFUNCTION blend = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA}; UpdateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA); @@ -393,13 +399,13 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bo static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::WindowFlags flags, qreal opacity) { - const bool isGL = windowIsOpenGL(w); + const bool isAccelerated = windowIsAccelerated(w); const bool hasAlpha = w->format().hasAlpha(); - if (isGL && hasAlpha) + if (isAccelerated && hasAlpha) applyBlurBehindWindow(hwnd); - setWindowOpacity(hwnd, flags, hasAlpha, isGL, opacity); + setWindowOpacity(hwnd, flags, hasAlpha, isAccelerated, opacity); } /*! @@ -1053,6 +1059,9 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_data(data), m_cursor(new CursorHandle), m_format(aWindow->requestedFormat()) +#if QT_CONFIG(vulkan) + , m_vkSurface(0) +#endif { // Clear the creation context as the window can be found in QWindowsContext's map. QWindowsContext::instance()->setWindowCreationContext(QSharedPointer()); @@ -1068,6 +1077,10 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) setFlag(OpenGL_ES2); } #endif // QT_NO_OPENGL +#if QT_CONFIG(vulkan) + if (aWindow->surfaceType() == QSurface::VulkanSurface) + setFlag(VulkanSurface); +#endif updateDropSite(window()->isTopLevel()); registerTouchWindow(); @@ -1121,6 +1134,14 @@ void QWindowsWindow::destroyWindow() if (hasMouseCapture()) setMouseGrabEnabled(false); setDropSiteEnabled(false); +#if QT_CONFIG(vulkan) + if (m_vkSurface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + static_cast(inst->handle())->destroySurface(m_vkSurface); + m_vkSurface = 0; + } +#endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) @@ -1470,8 +1491,10 @@ void QWindowsWindow::handleHidden() void QWindowsWindow::handleCompositionSettingsChanged() { const QWindow *w = window(); - if (w->surfaceType() == QWindow::OpenGLSurface && w->format().hasAlpha()) + if ((w->surfaceType() == QWindow::OpenGLSurface || w->surfaceType() == QWindow::VulkanSurface) + && w->format().hasAlpha()) { applyBlurBehindWindow(handle()); + } } static QRect normalFrameGeometry(HWND hwnd) @@ -1693,8 +1716,11 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, BeginPaint(hwnd, &ps); // Observed painting problems with Aero style disabled (QTBUG-7865). - if (Q_UNLIKELY(testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered) && !dwmIsCompositionEnabled())) + if (Q_UNLIKELY(!dwmIsCompositionEnabled()) + && ((testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered)) || testFlag(VulkanSurface))) + { SelectClipRgn(ps.hdc, NULL); + } // If the a window is obscured by another window (such as a child window) // we still need to send isExposed=true, for compatibility. @@ -2030,7 +2056,7 @@ void QWindowsWindow::setOpacity(qreal level) m_opacity = level; if (m_data.hwnd) setWindowOpacity(m_data.hwnd, m_data.flags, - window()->format().hasAlpha(), testFlag(OpenGLSurface), + window()->format().hasAlpha(), testFlag(OpenGLSurface) || testFlag(VulkanSurface), level); } } @@ -2448,11 +2474,27 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) void *QWindowsWindow::surface(void *nativeConfig, int *err) { -#ifdef QT_NO_OPENGL +#if QT_CONFIG(vulkan) + Q_UNUSED(nativeConfig); + Q_UNUSED(err); + if (window()->surfaceType() == QSurface::VulkanSurface) { + if (!m_vkSurface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + m_vkSurface = static_cast(inst->handle())->createSurface(handle()); + else + qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?"); + } + // Different semantics for VkSurfaces: the return value is the address, + // not the value, given that this is a 64-bit handle even on x86. + return &m_vkSurface; + } +#elif defined(QT_NO_OPENGL) Q_UNUSED(err) Q_UNUSED(nativeConfig) return 0; -#else +#endif +#ifndef QT_NO_OPENGL if (!m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) m_surface = staticOpenGLContext->createWindowSurface(m_data.hwnd, nativeConfig, err); @@ -2464,6 +2506,14 @@ void *QWindowsWindow::surface(void *nativeConfig, int *err) void QWindowsWindow::invalidateSurface() { +#if QT_CONFIG(vulkan) + if (m_vkSurface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + static_cast(inst->handle())->destroySurface(m_vkSurface); + m_vkSurface = 0; + } +#endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index b55529588c..46236c10b5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -46,6 +46,10 @@ #include #include +#if QT_CONFIG(vulkan) +#include "qwindowsvulkaninstance.h" +#endif + QT_BEGIN_NAMESPACE class QWindowsOleDropTarget; @@ -209,6 +213,7 @@ public: Compositing = 0x200000, HasBorderInFullScreen = 0x400000, WithinDpiChanged = 0x800000, + VulkanSurface = 0x1000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); @@ -351,6 +356,11 @@ private: HICON m_iconSmall = 0; HICON m_iconBig = 0; void *m_surface = nullptr; + +#if QT_CONFIG(vulkan) + // note: intentionally not using void * in order to avoid breaking x86 + VkSurfaceKHR m_vkSurface = 0; +#endif }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 1a80526aab..7694824d20 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -68,6 +68,11 @@ qtConfig(dynamicgl) { HEADERS += $$PWD/qwindowseglcontext.h } +qtConfig(vulkan) { + SOURCES += $$PWD/qwindowsvulkaninstance.cpp + HEADERS += $$PWD/qwindowsvulkaninstance.h +} + !contains( DEFINES, QT_NO_CLIPBOARD ) { SOURCES += $$PWD/qwindowsclipboard.cpp HEADERS += $$PWD/qwindowsclipboard.h diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 23168c10dc..4d788d91f8 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -5,6 +5,8 @@ QT += \ eventdispatcher_support-private accessibility_support-private \ fontdatabase_support-private theme_support-private +qtConfig(vulkan): QT += vulkan_support-private + LIBS += -lgdi32 -ldwmapi include(windows.pri) diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 40858b39e0..7f1cff1299 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -83,6 +83,11 @@ #include +#if QT_CONFIG(vulkan) +#include "qxcbvulkaninstance.h" +#include "qxcbvulkanwindow.h" +#endif + QT_BEGIN_NAMESPACE // Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,. @@ -199,11 +204,19 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const { QXcbScreen *screen = static_cast(window->screen()->handle()); QXcbGlIntegration *glIntegration = screen->connection()->glIntegration(); - if (window->type() != Qt::Desktop && window->supportsOpenGL()) { - if (glIntegration) { - QXcbWindow *xcbWindow = glIntegration->createWindow(window); + if (window->type() != Qt::Desktop) { + if (window->supportsOpenGL()) { + if (glIntegration) { + QXcbWindow *xcbWindow = glIntegration->createWindow(window); + xcbWindow->create(); + return xcbWindow; + } +#if QT_CONFIG(vulkan) + } else if (window->surfaceType() == QSurface::VulkanSurface) { + QXcbWindow *xcbWindow = new QXcbVulkanWindow(window); xcbWindow->create(); return xcbWindow; +#endif } } @@ -498,4 +511,11 @@ void QXcbIntegration::beep() const xcb_bell(connection, 0); } +#if QT_CONFIG(vulkan) +QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + return new QXcbVulkanInstance(instance); +} +#endif + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index baa5c9d835..6e12739138 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -113,6 +113,10 @@ public: void beep() const override; +#if QT_CONFIG(vulkan) + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; +#endif + static QXcbIntegration *instance() { return m_instance; } private: diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index cc05671580..eff38fc868 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -67,6 +67,10 @@ #include "qxcbnativeinterfacehandler.h" +#if QT_CONFIG(vulkan) +#include "qxcbvulkanwindow.h" +#endif + QT_BEGIN_NAMESPACE // return QXcbNativeInterface::ResourceType for the key. @@ -82,7 +86,8 @@ static int resourceType(const QByteArray &key) QByteArrayLiteral("rootwindow"), QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingenabled"), QByteArrayLiteral("atspibus"), - QByteArrayLiteral("compositingenabled") + QByteArrayLiteral("compositingenabled"), + QByteArrayLiteral("vksurface") }; const QByteArray *end = names + sizeof(names) / sizeof(names[0]); const QByteArray *result = std::find(names, end, key); @@ -257,6 +262,14 @@ void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceStr case Screen: result = screenForWindow(window); break; +#if QT_CONFIG(vulkan) + case VkSurface: + if (window->surfaceType() == QSurface::VulkanSurface && window->handle()) { + // return a pointer to the VkSurfaceKHR value, not the value itself + result = static_cast(window->handle())->surface(); + } + break; +#endif default: break; } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index 4186d77f4d..b9f1ebcdc6 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -73,7 +73,8 @@ public: ScreenSubpixelType, ScreenAntialiasingEnabled, AtspiBus, - CompositingEnabled + CompositingEnabled, + VkSurface }; QXcbNativeInterface(); diff --git a/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp b/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp new file mode 100644 index 0000000000..4d540defa9 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qxcbvulkaninstance.h" +#include "qxcbwindow.h" +#include "qxcbscreen.h" + +QT_BEGIN_NAMESPACE + +QXcbVulkanInstance::QXcbVulkanInstance(QVulkanInstance *instance) + : m_instance(instance), + m_getPhysDevPresSupport(nullptr), + m_createSurface(nullptr), + m_destroySurface(nullptr) +{ + if (qEnvironmentVariableIsSet("QT_VULKAN_LIB")) + m_lib.setFileName(QString::fromUtf8(qgetenv("QT_VULKAN_LIB"))); + else + m_lib.setFileName(QStringLiteral("vulkan")); + + if (!m_lib.load()) { + qWarning("Failed to load %s: %s", qPrintable(m_lib.fileName()), qPrintable(m_lib.errorString())); + return; + } + + init(&m_lib); +} + +QXcbVulkanInstance::~QXcbVulkanInstance() +{ +} + +void QXcbVulkanInstance::createOrAdoptInstance() +{ + initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_KHR_xcb_surface")); + + if (!m_vkInst) + return; + + m_getPhysDevPresSupport = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceXcbPresentationSupportKHR")); + if (!m_getPhysDevPresSupport) + qWarning("Failed to find vkGetPhysicalDeviceXcbPresentationSupportKHR"); +} + +bool QXcbVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + QWindow *window) +{ + if (!m_getPhysDevPresSupport || !m_getPhysDevSurfaceSupport) + return true; + + QXcbWindow *w = static_cast(window->handle()); + if (!w) { + qWarning("Attempted to call supportsPresent() without a valid platform window"); + return false; + } + xcb_connection_t *connection = w->xcbScreen()->xcb_connection(); + bool ok = m_getPhysDevPresSupport(physicalDevice, queueFamilyIndex, connection, w->visualId()); + + VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window); + VkBool32 supported = false; + m_getPhysDevSurfaceSupport(physicalDevice, queueFamilyIndex, surface, &supported); + ok &= bool(supported); + + return ok; +} + +VkSurfaceKHR QXcbVulkanInstance::createSurface(QXcbWindow *window) +{ + VkSurfaceKHR surface = 0; + + if (!m_createSurface) { + m_createSurface = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkCreateXcbSurfaceKHR")); + } + if (!m_createSurface) { + qWarning("Failed to find vkCreateXcbSurfaceKHR"); + return surface; + } + if (!m_destroySurface) { + m_destroySurface = reinterpret_cast( + m_vkGetInstanceProcAddr(m_vkInst, "vkDestroySurfaceKHR")); + } + if (!m_destroySurface) { + qWarning("Failed to find vkDestroySurfaceKHR"); + return surface; + } + + VkXcbSurfaceCreateInfoKHR surfaceInfo; + memset(&surfaceInfo, 0, sizeof(surfaceInfo)); + surfaceInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + surfaceInfo.connection = window->xcbScreen()->xcb_connection(); + surfaceInfo.window = window->xcb_window(); + VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface); + if (err != VK_SUCCESS) + qWarning("Failed to create Vulkan surface: %d", err); + + return surface; +} + +void QXcbVulkanInstance::destroySurface(VkSurfaceKHR surface) +{ + if (m_destroySurface && surface) + m_destroySurface(m_vkInst, surface, nullptr); +} + +void QXcbVulkanInstance::presentQueued(QWindow *window) +{ + QXcbWindow *w = static_cast(window->handle()); + if (!w) { + qWarning("Attempted to call presentQueued() without a valid platform window"); + return; + } + + if (w->needsSync()) + w->postSyncWindowRequest(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbvulkaninstance.h b/src/plugins/platforms/xcb/qxcbvulkaninstance.h new file mode 100644 index 0000000000..dbe057d944 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbvulkaninstance.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 QXCBVULKANINSTANCE_H +#define QXCBVULKANINSTANCE_H + +#if defined(VULKAN_H_) && !defined(VK_USE_PLATFORM_XCB_KHR) +#error "vulkan.h included without xcb WSI" +#endif + +#define VK_USE_PLATFORM_XCB_KHR + +#include +#include + +QT_BEGIN_NAMESPACE + +class QXcbWindow; + +class QXcbVulkanInstance : public QBasicPlatformVulkanInstance +{ +public: + QXcbVulkanInstance(QVulkanInstance *instance); + ~QXcbVulkanInstance(); + + void createOrAdoptInstance() override; + bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override; + void presentQueued(QWindow *window) override; + + VkSurfaceKHR createSurface(QXcbWindow *window); + void destroySurface(VkSurfaceKHR surface); + +private: + QVulkanInstance *m_instance; + QLibrary m_lib; + PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR m_getPhysDevPresSupport; + PFN_vkCreateXcbSurfaceKHR m_createSurface; + PFN_vkDestroySurfaceKHR m_destroySurface; +}; + +QT_END_NAMESPACE + +#endif // QXCBVULKANINSTANCE_H diff --git a/src/plugins/platforms/xcb/qxcbvulkanwindow.cpp b/src/plugins/platforms/xcb/qxcbvulkanwindow.cpp new file mode 100644 index 0000000000..f9136c8b72 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbvulkanwindow.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qxcbvulkanwindow.h" + +QT_BEGIN_NAMESPACE + +QXcbVulkanWindow::QXcbVulkanWindow(QWindow *window) + : QXcbWindow(window), + m_surface(0) +{ +} + +QXcbVulkanWindow::~QXcbVulkanWindow() +{ + if (m_surface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + static_cast(inst->handle())->destroySurface(m_surface); + } +} + +void QXcbVulkanWindow::resolveFormat(const QSurfaceFormat &format) +{ + m_format = format; + m_format.setRedBufferSize(8); + m_format.setGreenBufferSize(8); + m_format.setBlueBufferSize(8); +} + +VkSurfaceKHR *QXcbVulkanWindow::surface() +{ + if (m_surface) + return &m_surface; + + QVulkanInstance *inst = window()->vulkanInstance(); + if (!inst) { + qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?"); + return nullptr; + } + QXcbVulkanInstance *xcbinst = static_cast(inst->handle()); + m_surface = xcbinst->createSurface(this); + + return &m_surface; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbvulkanwindow.h b/src/plugins/platforms/xcb/qxcbvulkanwindow.h new file mode 100644 index 0000000000..43c96820c5 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbvulkanwindow.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 QXCBVULKANWINDOW_H +#define QXCBVULKANWINDOW_H + +#include "qxcbwindow.h" +#include "qxcbvulkaninstance.h" + +QT_BEGIN_NAMESPACE + +class QXcbVulkanWindow : public QXcbWindow +{ +public: + QXcbVulkanWindow(QWindow *window); + ~QXcbVulkanWindow(); + + VkSurfaceKHR *surface(); + +protected: + void resolveFormat(const QSurfaceFormat &format) override; + +private: + VkSurfaceKHR m_surface; +}; + +QT_END_NAMESPACE + +#endif // QXCBVULKANWINDOW_H diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 6db0c76dea..c7f2993220 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -10,6 +10,8 @@ QT += \ qtHaveModule(linuxaccessibility_support-private): \ QT += linuxaccessibility_support-private +qtConfig(vulkan): QT += vulkan_support-private + SOURCES = \ qxcbclipboard.cpp \ qxcbconnection.cpp \ @@ -70,6 +72,16 @@ qtConfig(xcb-sm) { include(gl_integrations/gl_integrations.pri) +qtConfig(vulkan) { + SOURCES += \ + qxcbvulkaninstance.cpp \ + qxcbvulkanwindow.cpp + + HEADERS += \ + qxcbvulkaninstance.h \ + qxcbvulkanwindow.h +} + !qtConfig(system-xcb) { DEFINES += XCB_USE_RENDER QMAKE_USE += xcb-static xcb diff --git a/src/src.pro b/src/src.pro index 403bf58a0a..cf65e4baf4 100644 --- a/src/src.pro +++ b/src/src.pro @@ -49,6 +49,11 @@ src_tools_qdbuscpp2xml.target = sub-qdbuscpp2xml force_bootstrap: src_tools_qdbuscpp2xml.depends = src_tools_bootstrap_dbus else: src_tools_qdbuscpp2xml.depends = src_dbus +src_tools_qvkgen.subdir = tools/qvkgen +src_tools_qvkgen.target = sub-qvkgen +force_bootstrap: src_tools_qvkgen.depends = src_tools_bootstrap +else: src_tools_qvkgen.depends = src_corelib + src_winmain.subdir = $$PWD/winmain src_winmain.target = sub-winmain src_winmain.depends = sub-corelib # just for the module .pri file @@ -185,6 +190,9 @@ qtConfig(gui) { SUBDIRS += src_3rdparty_freetype src_platformsupport.depends += src_3rdparty_freetype } + SUBDIRS += src_tools_qvkgen + src_gui.depends += src_tools_qvkgen + TOOLS += src_tools_qvkgen SUBDIRS += src_gui src_platformsupport src_platformheaders qtConfig(opengl): SUBDIRS += src_openglextensions src_plugins.depends += src_gui src_platformsupport src_platformheaders diff --git a/src/tools/qvkgen/qvkgen.cpp b/src/tools/qvkgen/qvkgen.cpp new file mode 100644 index 0000000000..cf97a84062 --- /dev/null +++ b/src/tools/qvkgen/qvkgen.cpp @@ -0,0 +1,530 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +class VkSpecParser +{ +public: + bool parse(); + + struct TypedName { + QString name; + QString type; + QString typeSuffix; + }; + + struct Command { + TypedName cmd; + QVector args; + bool deviceLevel; + }; + + QVector commands() const { return m_commands; } + + void setFileName(const QString &fn) { m_fn = fn; } + +private: + void skip(); + void parseCommands(); + Command parseCommand(); + TypedName parseParamOrProto(const QString &tag); + QString parseName(); + + QFile m_file; + QXmlStreamReader m_reader; + QVector m_commands; + QString m_fn; +}; + +bool VkSpecParser::parse() +{ + m_file.setFileName(m_fn); + if (!m_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning("Failed to open %s", qPrintable(m_file.fileName())); + return false; + } + + m_reader.setDevice(&m_file); + while (!m_reader.atEnd()) { + m_reader.readNext(); + if (m_reader.isStartElement()) { + if (m_reader.name() == QStringLiteral("commands")) + parseCommands(); + } + } + + return true; +} + +void VkSpecParser::skip() +{ + QString tag = m_reader.name().toString(); + while (!m_reader.atEnd()) { + m_reader.readNext(); + if (m_reader.isEndElement() && m_reader.name() == tag) + break; + } +} + +void VkSpecParser::parseCommands() +{ + m_commands.clear(); + + while (!m_reader.atEnd()) { + m_reader.readNext(); + if (m_reader.isEndElement() && m_reader.name() == QStringLiteral("commands")) + return; + if (m_reader.isStartElement() && m_reader.name() == "command") + m_commands.append(parseCommand()); + } +} + +VkSpecParser::Command VkSpecParser::parseCommand() +{ + Command c; + + while (!m_reader.atEnd()) { + m_reader.readNext(); + if (m_reader.isEndElement() && m_reader.name() == QStringLiteral("command")) + break; + if (m_reader.isStartElement()) { + const QString protoStr = QStringLiteral("proto"); + const QString paramStr = QStringLiteral("param"); + if (m_reader.name() == protoStr) { + c.cmd = parseParamOrProto(protoStr); + } else if (m_reader.name() == paramStr) { + c.args.append(parseParamOrProto(paramStr)); + } else { + skip(); + } + } + } + + c.deviceLevel = false; + if (!c.args.isEmpty()) { + QStringList dispatchableDeviceAndChildTypes { + QStringLiteral("VkDevice"), + QStringLiteral("VkQueue"), + QStringLiteral("VkCommandBuffer") + }; + if (dispatchableDeviceAndChildTypes.contains(c.args[0].type) + && c.cmd.name != QStringLiteral("vkGetDeviceProcAddr")) + { + c.deviceLevel = true; + } + } + + return c; +} + +VkSpecParser::TypedName VkSpecParser::parseParamOrProto(const QString &tag) +{ + TypedName t; + + while (!m_reader.atEnd()) { + m_reader.readNext(); + if (m_reader.isEndElement() && m_reader.name() == tag) + break; + if (m_reader.isStartElement()) { + if (m_reader.name() == QStringLiteral("name")) { + t.name = parseName(); + } else if (m_reader.name() != QStringLiteral("type")) { + skip(); + } + } else { + QStringRef text = m_reader.text().trimmed(); + if (!text.isEmpty()) { + if (text.startsWith(QLatin1Char('['))) { + t.typeSuffix += text; + } else { + if (!t.type.isEmpty()) + t.type += QLatin1Char(' '); + t.type += text; + } + } + } + } + + return t; +} + +QString VkSpecParser::parseName() +{ + QString name; + while (!m_reader.atEnd()) { + m_reader.readNext(); + if (m_reader.isEndElement() && m_reader.name() == QStringLiteral("name")) + break; + name += m_reader.text(); + } + return name.trimmed(); +} + +QString funcSig(const VkSpecParser::Command &c, const char *className = nullptr) +{ + QString s; + s.sprintf("%s %s%s%s", qPrintable(c.cmd.type), + (className ? className : ""), (className ? "::" : ""), + qPrintable(c.cmd.name)); + if (!c.args.isEmpty()) { + s += QLatin1Char('('); + bool first = true; + for (const VkSpecParser::TypedName &a : c.args) { + QString argStr; + argStr.sprintf("%s%s%s%s", qPrintable(a.type), (a.type.endsWith(QLatin1Char('*')) ? "" : " "), + qPrintable(a.name), qPrintable(a.typeSuffix)); + if (!first) + s += QStringLiteral(", "); + else + first = false; + s += argStr; + } + s += QLatin1Char(')'); + } + return s; +} + +QString funcCall(const VkSpecParser::Command &c, int idx) +{ + QString s; + // template: + // [return] reinterpret_cast(d_ptr->m_funcs[0])(instance, pPhysicalDeviceCount, pPhysicalDevices); + s.sprintf("%sreinterpret_cast(d_ptr->m_funcs[%d])", + (c.cmd.type == QStringLiteral("void") ? "" : "return "), + qPrintable(c.cmd.name), + idx); + if (!c.args.isEmpty()) { + s += QLatin1Char('('); + bool first = true; + for (const VkSpecParser::TypedName &a : c.args) { + if (!first) + s += QStringLiteral(", "); + else + first = false; + s += a.name; + } + s += QLatin1Char(')'); + } + return s; +} + +class Preamble +{ +public: + QByteArray get(const QString &fn); + +private: + QByteArray m_str; +} preamble; + +QByteArray Preamble::get(const QString &fn) +{ + if (!m_str.isEmpty()) + return m_str; + + QFile f(fn); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning("Failed to open %s", qPrintable(fn)); + return m_str; + } + + m_str = f.readAll(); + m_str.replace("FOO", "QtGui"); + m_str += "\n// This file is automatically generated by qvkgen. Do not edit.\n"; + + return m_str; +} + +bool genVulkanFunctionsH(const QVector &commands, const QString &licHeaderFn, const QString &outputBase) +{ + QFile f(outputBase + QStringLiteral(".h")); + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("Failed to write %s", qPrintable(f.fileName())); + return false; + } + + static const char *s = +"%s\n" +"#ifndef QVULKANFUNCTIONS_H\n" +"#define QVULKANFUNCTIONS_H\n" +"\n" +"#include \n" +"\n" +"#if QT_CONFIG(vulkan)\n" +"\n" +"#ifndef VK_NO_PROTOTYPES\n" +"#define VK_NO_PROTOTYPES\n" +"#endif\n" +"#include \n" +"\n" +"#include \n" +"\n" +"QT_BEGIN_NAMESPACE\n" +"\n" +"class QVulkanInstance;\n" +"class QVulkanFunctionsPrivate;\n" +"class QVulkanDeviceFunctionsPrivate;\n" +"\n" +"class Q_GUI_EXPORT QVulkanFunctions\n" +"{\n" +"public:\n" +" ~QVulkanFunctions();\n" +"\n" +"%s\n" +"private:\n" +" Q_DISABLE_COPY(QVulkanFunctions)\n" +" QVulkanFunctions(QVulkanInstance *inst);\n" +"\n" +" QScopedPointer d_ptr;\n" +" friend class QVulkanInstance;\n" +"};\n" +"\n" +"class Q_GUI_EXPORT QVulkanDeviceFunctions\n" +"{\n" +"public:\n" +" ~QVulkanDeviceFunctions();\n" +"\n" +"%s\n" +"private:\n" +" Q_DISABLE_COPY(QVulkanDeviceFunctions)\n" +" QVulkanDeviceFunctions(QVulkanInstance *inst, VkDevice device);\n" +"\n" +" QScopedPointer d_ptr;\n" +" friend class QVulkanInstance;\n" +"};\n" +"\n" +"QT_END_NAMESPACE\n" +"\n" +"#endif // QT_CONFIG(vulkan)\n" +"\n" +"#endif // QVULKANFUNCTIONS_H\n"; + + QString instCmdStr; + QString devCmdStr; + for (const VkSpecParser::Command &c : commands) { + QString *dst = c.deviceLevel ? &devCmdStr : &instCmdStr; + *dst += QStringLiteral(" "); + *dst += funcSig(c); + *dst += QStringLiteral(";\n"); + } + + QString str; + str.sprintf(s, preamble.get(licHeaderFn).constData(), instCmdStr.toUtf8().constData(), devCmdStr.toUtf8().constData()); + + f.write(str.toUtf8()); + + return true; +} + +bool genVulkanFunctionsPH(const QVector &commands, const QString &licHeaderFn, const QString &outputBase) +{ + QFile f(outputBase + QStringLiteral("_p.h")); + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("Failed to write %s", qPrintable(f.fileName())); + return false; + } + + static const char *s = +"%s\n" +"#ifndef QVULKANFUNCTIONS_P_H\n" +"#define QVULKANFUNCTIONS_P_H\n" +"\n" +"//\n" +"// W A R N I N G\n" +"// -------------\n" +"//\n" +"// This file is not part of the Qt API. It exists purely as an\n" +"// implementation detail. This header file may change from version to\n" +"// version without notice, or even be removed.\n" +"//\n" +"// We mean it.\n" +"//\n" +"\n" +"#include \"qvulkanfunctions.h\"\n" +"\n" +"QT_BEGIN_NAMESPACE\n" +"\n" +"class QVulkanInstance;\n" +"\n" +"class QVulkanFunctionsPrivate\n" +"{\n" +"public:\n" +" QVulkanFunctionsPrivate(QVulkanInstance *inst);\n" +"\n" +" PFN_vkVoidFunction m_funcs[%d];\n" +"};\n" +"\n" +"class QVulkanDeviceFunctionsPrivate\n" +"{\n" +"public:\n" +" QVulkanDeviceFunctionsPrivate(QVulkanInstance *inst, VkDevice device);\n" +"\n" +" PFN_vkVoidFunction m_funcs[%d];\n" +"};\n" +"\n" +"QT_END_NAMESPACE\n" +"\n" +"#endif // QVULKANFUNCTIONS_P_H\n"; + + const int devLevelCount = std::count_if(commands.cbegin(), commands.cend(), + [](const VkSpecParser::Command &c) { return c.deviceLevel; }); + const int instLevelCount = commands.count() - devLevelCount; + + QString str; + str.sprintf(s, preamble.get(licHeaderFn).constData(), instLevelCount, devLevelCount); + + f.write(str.toUtf8()); + + return true; +} + +bool genVulkanFunctionsPC(const QVector &commands, const QString &licHeaderFn, const QString &outputBase) +{ + QFile f(outputBase + QStringLiteral("_p.cpp")); + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("Failed to write %s", qPrintable(f.fileName())); + return false; + } + + static const char *s = +"%s\n" +"#include \"qvulkanfunctions_p.h\"\n" +"#include \"qvulkaninstance.h\"\n" +"\n" +"QT_BEGIN_NAMESPACE\n" +"\n%s" +"QVulkanFunctionsPrivate::QVulkanFunctionsPrivate(QVulkanInstance *inst)\n" +"{\n" +" static const char *funcNames[] = {\n" +"%s\n" +" };\n" +" for (int i = 0; i < %d; ++i) {\n" +" m_funcs[i] = inst->getInstanceProcAddr(funcNames[i]);\n" +" if (!m_funcs[i])\n" +" qWarning(\"QVulkanFunctions: Failed to resolve %%s\", funcNames[i]);\n" +" }\n" +"}\n" +"\n%s" +"QVulkanDeviceFunctionsPrivate::QVulkanDeviceFunctionsPrivate(QVulkanInstance *inst, VkDevice device)\n" +"{\n" +" QVulkanFunctions *f = inst->functions();\n" +" Q_ASSERT(f);\n\n" +" static const char *funcNames[] = {\n" +"%s\n" +" };\n" +" for (int i = 0; i < %d; ++i) {\n" +" m_funcs[i] = f->vkGetDeviceProcAddr(device, funcNames[i]);\n" +" if (!m_funcs[i])\n" +" qWarning(\"QVulkanDeviceFunctions: Failed to resolve %%s\", funcNames[i]);\n" +" }\n" +"}\n" +"\n" +"QT_END_NAMESPACE\n"; + + QString devCmdWrapperStr; + QString instCmdWrapperStr; + int devIdx = 0; + int instIdx = 0; + QString devCmdNamesStr; + QString instCmdNamesStr; + + for (int i = 0; i < commands.count(); ++i) { + QString *dst = commands[i].deviceLevel ? &devCmdWrapperStr : &instCmdWrapperStr; + int *idx = commands[i].deviceLevel ? &devIdx : &instIdx; + *dst += funcSig(commands[i], commands[i].deviceLevel ? "QVulkanDeviceFunctions" : "QVulkanFunctions"); + *dst += QString(QStringLiteral("\n{\n Q_ASSERT(d_ptr->m_funcs[%1]);\n ")).arg(*idx); + *dst += funcCall(commands[i], *idx); + *dst += QStringLiteral(";\n}\n\n"); + ++*idx; + + dst = commands[i].deviceLevel ? &devCmdNamesStr : &instCmdNamesStr; + *dst += QStringLiteral(" \""); + *dst += commands[i].cmd.name; + *dst += QStringLiteral("\",\n"); + } + + if (devCmdNamesStr.count() > 2) + devCmdNamesStr = devCmdNamesStr.left(devCmdNamesStr.count() - 2); + if (instCmdNamesStr.count() > 2) + instCmdNamesStr = instCmdNamesStr.left(instCmdNamesStr.count() - 2); + + QString str; + str.sprintf(s, preamble.get(licHeaderFn).constData(), + instCmdWrapperStr.toUtf8().constData(), instCmdNamesStr.toUtf8().constData(), instIdx, + devCmdWrapperStr.toUtf8().constData(), devCmdNamesStr.toUtf8().constData(), commands.count() - instIdx); + + f.write(str.toUtf8()); + + return true; +} + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + VkSpecParser parser; + + if (argc < 4) { + qWarning("Usage: qvkgen input_vk_xml input_license_header output_base\n" + " For example: qvkgen vulkan/vk.xml vulkan/qvulkanfunctions.header vulkan/qvulkanfunctions"); + return 1; + } + + parser.setFileName(QString::fromUtf8(argv[1])); + + if (!parser.parse()) + return 1; + + QVector commands = parser.commands(); + QStringList ignoredFuncs { + QStringLiteral("vkCreateInstance"), + QStringLiteral("vkDestroyInstance"), + QStringLiteral("vkGetInstanceProcAddr") + }; + + // Filter out extensions and unwanted functions. + // The check for the former is rather simplistic for now: skip if the last letter is uppercase... + for (int i = 0; i < commands.count(); ++i) { + QString name = commands[i].cmd.name; + QChar c = name[name.count() - 1]; + if (c.isUpper() || ignoredFuncs.contains(name)) + commands.remove(i--); + } + + QString licenseHeaderFileName = QString::fromUtf8(argv[2]); + QString outputBase = QString::fromUtf8(argv[3]); + genVulkanFunctionsH(commands, licenseHeaderFileName, outputBase); + genVulkanFunctionsPH(commands, licenseHeaderFileName, outputBase); + genVulkanFunctionsPC(commands, licenseHeaderFileName, outputBase); + + return 0; +} diff --git a/src/tools/qvkgen/qvkgen.pro b/src/tools/qvkgen/qvkgen.pro new file mode 100644 index 0000000000..9f2c2f6594 --- /dev/null +++ b/src/tools/qvkgen/qvkgen.pro @@ -0,0 +1,5 @@ +option(host_build) + +SOURCES += qvkgen.cpp + +load(qt_tool) diff --git a/sync.profile b/sync.profile index add6766c49..4fcca568a9 100644 --- a/sync.profile +++ b/sync.profile @@ -26,6 +26,7 @@ "QtFbSupport" => "$basedir/src/platformsupport/fbconvenience", "QtGlxSupport" => "$basedir/src/platformsupport/glxconvenience", "QtKmsSupport" => "$basedir/src/platformsupport/kmsconvenience", + "QtVulkanSupport" => "$basedir/src/platformsupport/vkconvenience", "QtPlatformHeaders" => "$basedir/src/platformheaders", "QtANGLE/KHR" => "!$basedir/src/3rdparty/angle/include/KHR", "QtANGLE/GLES2" => "!$basedir/src/3rdparty/angle/include/GLES2", @@ -52,6 +53,7 @@ "qnamespace.h" => "Qt", "qnumeric.h" => "QtNumeric", "qvariant.h" => "QVariantHash,QVariantList,QVariantMap", + "qvulkanfunctions.h" => "QVulkanFunctions,QVulkanDeviceFunctions", "qgl.h" => "QGL", "qsql.h" => "QSql", "qssl.h" => "QSsl", @@ -80,4 +82,7 @@ my @zlib_headers = ( "zconf.h", "zlib.h" ); @ignore_headers = ( @internal_zlib_headers ); @ignore_for_include_check = ( "qsystemdetection.h", "qcompilerdetection.h", "qprocessordetection.h", @zlib_headers, @angle_headers); @ignore_for_qt_begin_namespace_check = ( "qt_windows.h", @zlib_headers, @angle_headers); -%inject_headers = ( "$basedir/src/corelib/global" => [ "qconfig.h", "qconfig_p.h" ] ); +%inject_headers = ( + "$basedir/src/corelib/global" => [ "qconfig.h", "qconfig_p.h" ], + "$basedir/src/gui/vulkan" => [ "qvulkanfunctions.h" ] +); diff --git a/tests/auto/gui/gui.pro b/tests/auto/gui/gui.pro index 2fd3024afe..d7cda11513 100644 --- a/tests/auto/gui/gui.pro +++ b/tests/auto/gui/gui.pro @@ -9,8 +9,11 @@ SUBDIRS = \ painting \ qopenglconfig \ qopengl \ + qvulkan \ text \ util \ itemmodels \ !qtConfig(opengl): SUBDIRS -= qopengl qopenglconfig + +!qtConfig(vulkan): SUBDIRS -= qvulkan diff --git a/tests/auto/gui/qvulkan/qvulkan.pro b/tests/auto/gui/qvulkan/qvulkan.pro new file mode 100644 index 0000000000..0db990a2d6 --- /dev/null +++ b/tests/auto/gui/qvulkan/qvulkan.pro @@ -0,0 +1,9 @@ +############################################################ +# Project file for autotest for gui/vulkan functionality +############################################################ + +CONFIG += testcase +TARGET = tst_qvulkan +QT += gui-private core-private testlib + +SOURCES += tst_qvulkan.cpp diff --git a/tests/auto/gui/qvulkan/tst_qvulkan.cpp b/tests/auto/gui/qvulkan/tst_qvulkan.cpp new file mode 100644 index 0000000000..2803b84e8c --- /dev/null +++ b/tests/auto/gui/qvulkan/tst_qvulkan.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include + +#include + +class tst_QVulkan : public QObject +{ + Q_OBJECT + +private slots: + void vulkanInstance(); + void vulkanCheckSupported(); + void vulkanWindow(); + void vulkanVersionRequest(); +}; + +void tst_QVulkan::vulkanInstance() +{ + QVulkanInstance inst; + if (!inst.create()) + QSKIP("Vulkan init failed; skip"); + + QVERIFY(inst.isValid()); + QVERIFY(inst.vkInstance() != VK_NULL_HANDLE); + QVERIFY(inst.functions()); + QVERIFY(!inst.flags().testFlag(QVulkanInstance::NoDebugOutputRedirect)); + + inst.destroy(); + + QVERIFY(!inst.isValid()); + QVERIFY(inst.handle() == nullptr); + + inst.setFlags(QVulkanInstance::NoDebugOutputRedirect); + // pass a bogus layer and extension + inst.setExtensions(QByteArrayList() << "abcdefg" << "notanextension"); + inst.setLayers(QByteArrayList() << "notalayer"); + QVERIFY(inst.create()); + + QVERIFY(inst.isValid()); + QVERIFY(inst.vkInstance() != VK_NULL_HANDLE); + QVERIFY(inst.handle() != nullptr); + QVERIFY(inst.functions()); + QVERIFY(inst.flags().testFlag(QVulkanInstance::NoDebugOutputRedirect)); + QVERIFY(!inst.extensions().contains("abcdefg")); + QVERIFY(!inst.extensions().contains("notanextension")); + QVERIFY(!inst.extensions().contains("notalayer")); + // at least the surface extensions should be there however + QVERIFY(inst.extensions().contains("VK_KHR_surface")); + + QVERIFY(inst.getInstanceProcAddr("vkGetDeviceQueue")); +} + +void tst_QVulkan::vulkanCheckSupported() +{ + // Test the early calls to supportedLayers/extensions that need the library + // and some basics, but do not initialize the instance. + QVulkanInstance inst; + QVERIFY(!inst.isValid()); + + QVulkanInfoVector vl = inst.supportedLayers(); + qDebug() << vl; + QVERIFY(!inst.isValid()); + + QVulkanInfoVector ve = inst.supportedExtensions(); + qDebug() << ve; + QVERIFY(!inst.isValid()); + + if (inst.create()) { // skip the rest when Vulkan is not supported at all + QVERIFY(!ve.isEmpty()); + QVERIFY(ve == inst.supportedExtensions()); + } +} + +void tst_QVulkan::vulkanWindow() +{ + QVulkanInstance inst; + if (!inst.create()) + QSKIP("Vulkan init failed; skip"); + + QWindow w; + w.setSurfaceType(QSurface::VulkanSurface); + w.setVulkanInstance(&inst); + w.resize(1024, 768); + w.show(); + QTest::qWaitForWindowExposed(&w); + + QCOMPARE(w.vulkanInstance(), &inst); + + VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(&w); + QVERIFY(surface != VK_NULL_HANDLE); + + // exercise supportsPresent (and QVulkanFunctions) a bit + QVulkanFunctions *f = inst.functions(); + VkPhysicalDevice physDev; + uint32_t count = 1; + VkResult err = f->vkEnumeratePhysicalDevices(inst.vkInstance(), &count, &physDev); + if (err != VK_SUCCESS) + QSKIP("No physical devices; skip"); + + VkPhysicalDeviceProperties physDevProps; + f->vkGetPhysicalDeviceProperties(physDev, &physDevProps); + qDebug("Device name: %s Driver version: %d.%d.%d", physDevProps.deviceName, + VK_VERSION_MAJOR(physDevProps.driverVersion), VK_VERSION_MINOR(physDevProps.driverVersion), + VK_VERSION_PATCH(physDevProps.driverVersion)); + + bool supports = inst.supportsPresent(physDev, 0, &w); + qDebug("queue family 0 supports presenting to window = %d", supports); +} + +void tst_QVulkan::vulkanVersionRequest() +{ + QVulkanInstance inst; + if (!inst.create()) + QSKIP("Vulkan init failed; skip"); + + // Now that we know Vulkan is functional, check the requested apiVersion is + // passed to vkCreateInstance as expected. + + inst.destroy(); + + inst.setApiVersion(QVersionNumber(10, 0, 0)); + QVERIFY(!inst.create()); + QCOMPARE(inst.errorCode(), VK_ERROR_INCOMPATIBLE_DRIVER); +} + +QTEST_MAIN(tst_QVulkan) + +#include "tst_qvulkan.moc" diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index a9d27fa488..ab00a5ef60 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -67,3 +67,5 @@ win32: SUBDIRS -= network_remote_stresstest network_stresstest lessThan(QT_MAJOR_VERSION, 5): SUBDIRS -= bearerex lance qnetworkaccessmanager/qget qmimedatabase qnetworkreply \ qpainfo qscreen socketengine xembed-raster xembed-widgets windowtransparency \ embeddedintoforeignwindow foreignwindows + +qtConfig(vulkan): SUBDIRS += qvulkaninstance diff --git a/tests/manual/qvulkaninstance/main.cpp b/tests/manual/qvulkaninstance/main.cpp new file mode 100644 index 0000000000..9b5f0ad072 --- /dev/null +++ b/tests/manual/qvulkaninstance/main.cpp @@ -0,0 +1,713 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +static const int SWAPCHAIN_BUFFER_COUNT = 2; +static const int FRAME_LAG = 2; + +class VWindow : public QWindow +{ +public: + VWindow() { setSurfaceType(VulkanSurface); } + ~VWindow() { releaseResources(); } + +private: + void exposeEvent(QExposeEvent *) override; + void resizeEvent(QResizeEvent *) override; + bool event(QEvent *) override; + + void init(); + void releaseResources(); + void recreateSwapChain(); + void createDefaultRenderPass(); + void releaseSwapChain(); + void render(); + void buildDrawCalls(); + + bool m_inited = false; + VkSurfaceKHR m_vkSurface; + VkPhysicalDevice m_vkPhysDev; + VkPhysicalDeviceProperties m_physDevProps; + VkDevice m_vkDev = 0; + QVulkanDeviceFunctions *m_devFuncs; + VkQueue m_vkGfxQueue; + VkQueue m_vkPresQueue; + VkCommandPool m_vkCmdPool = 0; + + PFN_vkCreateSwapchainKHR m_vkCreateSwapchainKHR = nullptr; + PFN_vkDestroySwapchainKHR m_vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR m_vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR m_vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR m_vkQueuePresentKHR; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR m_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR m_vkGetPhysicalDeviceSurfaceFormatsKHR; + + QSize m_swapChainImageSize; + VkFormat m_colorFormat; + VkSwapchainKHR m_swapChain = 0; + uint32_t m_swapChainBufferCount = 0; + + struct ImageResources { + VkImage image = 0; + VkImageView imageView = 0; + VkCommandBuffer cmdBuf = 0; + VkFence cmdFence = 0; + bool cmdFenceWaitable = false; + VkFramebuffer fb = 0; + } m_imageRes[SWAPCHAIN_BUFFER_COUNT]; + + uint32_t m_currentImage; + + struct FrameResources { + VkFence fence = 0; + bool fenceWaitable = false; + VkSemaphore imageSem = 0; + VkSemaphore drawSem = 0; + } m_frameRes[FRAME_LAG]; + + uint32_t m_currentFrame; + + VkRenderPass m_defaultRenderPass = 0; +}; + +void VWindow::exposeEvent(QExposeEvent *) +{ + if (isExposed() && !m_inited) { + qDebug("initializing"); + m_inited = true; + init(); + recreateSwapChain(); + render(); + } + + // Release everything when unexposed - the meaning of which is platform specific. + // Can be essential on mobile, to release resources while in background. +#if 1 + if (!isExposed() && m_inited) { + m_inited = false; + releaseSwapChain(); + releaseResources(); + } +#endif +} + +void VWindow::resizeEvent(QResizeEvent *) +{ + // Nothing to do here - recreating the swapchain is handled in render(), + // in fact calling recreateSwapChain() from here leads to problems. +} + +bool VWindow::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::UpdateRequest: + render(); + break; + + // Now the fun part: the swapchain must be destroyed before the surface as per + // spec. This is not ideal for us because the surface is managed by the + // QPlatformWindow which may be gone already when the unexpose comes, making the + // validation layer scream. The solution is to listen to the PlatformSurface events. + case QEvent::PlatformSurface: + if (static_cast(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) + releaseSwapChain(); + break; + + default: + break; + } + + return QWindow::event(e); +} + +void VWindow::init() +{ + m_vkSurface = QVulkanInstance::surfaceForWindow(this); + if (!m_vkSurface) + qFatal("Failed to get surface for window"); + + QVulkanInstance *inst = vulkanInstance(); + QVulkanFunctions *f = inst->functions(); + uint32_t devCount = 0; + f->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, nullptr); + qDebug("%d physical devices", devCount); + if (!devCount) + qFatal("No physical devices"); + + // Just pick the first physical device for now. + devCount = 1; + VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, &m_vkPhysDev); + if (err != VK_SUCCESS) + qFatal("Failed to enumerate physical devices: %d", err); + + f->vkGetPhysicalDeviceProperties(m_vkPhysDev, &m_physDevProps); + qDebug("Device name: %s Driver version: %d.%d.%d", m_physDevProps.deviceName, + VK_VERSION_MAJOR(m_physDevProps.driverVersion), VK_VERSION_MINOR(m_physDevProps.driverVersion), + VK_VERSION_PATCH(m_physDevProps.driverVersion)); + + uint32_t queueCount = 0; + f->vkGetPhysicalDeviceQueueFamilyProperties(m_vkPhysDev, &queueCount, nullptr); + QVector queueFamilyProps(queueCount); + f->vkGetPhysicalDeviceQueueFamilyProperties(m_vkPhysDev, &queueCount, queueFamilyProps.data()); + int gfxQueueFamilyIdx = -1; + int presQueueFamilyIdx = -1; + // First look for a queue that supports both. + for (int i = 0; i < queueFamilyProps.count(); ++i) { + qDebug("queue family %d: flags=0x%x count=%d", i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount); + if (gfxQueueFamilyIdx == -1 + && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + && inst->supportsPresent(m_vkPhysDev, i, this)) + gfxQueueFamilyIdx = i; + } + if (gfxQueueFamilyIdx != -1) { + presQueueFamilyIdx = gfxQueueFamilyIdx; + } else { + // Separate queues then. + qDebug("No queue with graphics+present; trying separate queues"); + for (int i = 0; i < queueFamilyProps.count(); ++i) { + if (gfxQueueFamilyIdx == -1 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) + gfxQueueFamilyIdx = i; + if (presQueueFamilyIdx == -1 && inst->supportsPresent(m_vkPhysDev, i, this)) + presQueueFamilyIdx = i; + } + } + if (gfxQueueFamilyIdx == -1) + qFatal("No graphics queue family found"); + if (presQueueFamilyIdx == -1) + qFatal("No present queue family found"); + + VkDeviceQueueCreateInfo queueInfo[2]; + const float prio[] = { 0 }; + memset(queueInfo, 0, sizeof(queueInfo)); + queueInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo[0].queueFamilyIndex = gfxQueueFamilyIdx; + queueInfo[0].queueCount = 1; + queueInfo[0].pQueuePriorities = prio; + if (gfxQueueFamilyIdx != presQueueFamilyIdx) { + queueInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo[1].queueFamilyIndex = presQueueFamilyIdx; + queueInfo[1].queueCount = 1; + queueInfo[1].pQueuePriorities = prio; + } + + QVector devLayers; + if (inst->layers().contains("VK_LAYER_LUNARG_standard_validation")) + devLayers.append("VK_LAYER_LUNARG_standard_validation"); + + QVector devExts; + devExts.append("VK_KHR_swapchain"); + + VkDeviceCreateInfo devInfo; + memset(&devInfo, 0, sizeof(devInfo)); + devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + devInfo.queueCreateInfoCount = gfxQueueFamilyIdx == presQueueFamilyIdx ? 1 : 2; + devInfo.pQueueCreateInfos = queueInfo; + devInfo.enabledLayerCount = devLayers.count(); + devInfo.ppEnabledLayerNames = devLayers.constData(); + devInfo.enabledExtensionCount = devExts.count(); + devInfo.ppEnabledExtensionNames = devExts.constData(); + + err = f->vkCreateDevice(m_vkPhysDev, &devInfo, nullptr, &m_vkDev); + if (err != VK_SUCCESS) + qFatal("Failed to create device: %d", err); + + m_devFuncs = inst->deviceFunctions(m_vkDev); + + m_devFuncs->vkGetDeviceQueue(m_vkDev, gfxQueueFamilyIdx, 0, &m_vkGfxQueue); + if (gfxQueueFamilyIdx == presQueueFamilyIdx) + m_vkPresQueue = m_vkGfxQueue; + else + m_devFuncs->vkGetDeviceQueue(m_vkDev, presQueueFamilyIdx, 0, &m_vkPresQueue); + + VkCommandPoolCreateInfo poolInfo; + memset(&poolInfo, 0, sizeof(poolInfo)); + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = gfxQueueFamilyIdx; + err = m_devFuncs->vkCreateCommandPool(m_vkDev, &poolInfo, nullptr, &m_vkCmdPool); + if (err != VK_SUCCESS) + qFatal("Failed to create command pool: %d", err); + + m_colorFormat = VK_FORMAT_B8G8R8A8_UNORM; // may get changed later when setting up the swapchain +} + +void VWindow::releaseResources() +{ + if (!m_vkDev) + return; + + m_devFuncs->vkDeviceWaitIdle(m_vkDev); + + if (m_vkCmdPool) { + m_devFuncs->vkDestroyCommandPool(m_vkDev, m_vkCmdPool, nullptr); + m_vkCmdPool = 0; + } + + if (m_vkDev) { + m_devFuncs->vkDestroyDevice(m_vkDev, nullptr); + + // Play nice and notify QVulkanInstance that the QVulkanDeviceFunctions + // for m_vkDev needs to be invalidated. + vulkanInstance()->resetDeviceFunctions(m_vkDev); + + m_vkDev = 0; + } + + m_vkSurface = 0; +} + +void VWindow::recreateSwapChain() +{ + m_swapChainImageSize = size(); + + if (m_swapChainImageSize.isEmpty()) + return; + + QVulkanInstance *inst = vulkanInstance(); + QVulkanFunctions *f = inst->functions(); + m_devFuncs->vkDeviceWaitIdle(m_vkDev); + + if (!m_vkCreateSwapchainKHR) { + m_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast( + inst->getInstanceProcAddr("vkGetPhysicalDeviceSurfaceCapabilitiesKHR")); + m_vkGetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast( + inst->getInstanceProcAddr("vkGetPhysicalDeviceSurfaceFormatsKHR")); + // note: device-specific functions + m_vkCreateSwapchainKHR = reinterpret_cast(f->vkGetDeviceProcAddr(m_vkDev, "vkCreateSwapchainKHR")); + m_vkDestroySwapchainKHR = reinterpret_cast(f->vkGetDeviceProcAddr(m_vkDev, "vkDestroySwapchainKHR")); + m_vkGetSwapchainImagesKHR = reinterpret_cast(f->vkGetDeviceProcAddr(m_vkDev, "vkGetSwapchainImagesKHR")); + m_vkAcquireNextImageKHR = reinterpret_cast(f->vkGetDeviceProcAddr(m_vkDev, "vkAcquireNextImageKHR")); + m_vkQueuePresentKHR = reinterpret_cast(f->vkGetDeviceProcAddr(m_vkDev, "vkQueuePresentKHR")); + } + + VkColorSpaceKHR colorSpace = VkColorSpaceKHR(0); + uint32_t formatCount = 0; + m_vkGetPhysicalDeviceSurfaceFormatsKHR(m_vkPhysDev, m_vkSurface, &formatCount, nullptr); + if (formatCount) { + QVector formats(formatCount); + m_vkGetPhysicalDeviceSurfaceFormatsKHR(m_vkPhysDev, m_vkSurface, &formatCount, formats.data()); + if (formats[0].format != VK_FORMAT_UNDEFINED) { + m_colorFormat = formats[0].format; + colorSpace = formats[0].colorSpace; + } + } + + VkSurfaceCapabilitiesKHR surfaceCaps; + m_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_vkPhysDev, m_vkSurface, &surfaceCaps); + uint32_t reqBufferCount = SWAPCHAIN_BUFFER_COUNT; + if (surfaceCaps.maxImageCount) + reqBufferCount = qBound(surfaceCaps.minImageCount, reqBufferCount, surfaceCaps.maxImageCount); + + VkExtent2D bufferSize = surfaceCaps.currentExtent; + if (bufferSize.width == uint32_t(-1)) + bufferSize.width = m_swapChainImageSize.width(); + if (bufferSize.height == uint32_t(-1)) + bufferSize.height = m_swapChainImageSize.height(); + + VkSurfaceTransformFlagBitsKHR preTransform = + (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) + ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR + : surfaceCaps.currentTransform; + + VkCompositeAlphaFlagBitsKHR compositeAlpha = + (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) + ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR + : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + + VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; + + VkSwapchainKHR oldSwapChain = m_swapChain; + VkSwapchainCreateInfoKHR swapChainInfo; + memset(&swapChainInfo, 0, sizeof(swapChainInfo)); + swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapChainInfo.surface = m_vkSurface; + swapChainInfo.minImageCount = reqBufferCount; + swapChainInfo.imageFormat = m_colorFormat; + swapChainInfo.imageColorSpace = colorSpace; + swapChainInfo.imageExtent = bufferSize; + swapChainInfo.imageArrayLayers = 1; + swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapChainInfo.preTransform = preTransform; + swapChainInfo.compositeAlpha = compositeAlpha; + swapChainInfo.presentMode = presentMode; + swapChainInfo.clipped = true; + swapChainInfo.oldSwapchain = oldSwapChain; + + qDebug("creating new swap chain of %d buffers, size %dx%d", reqBufferCount, bufferSize.width, bufferSize.height); + + VkSwapchainKHR newSwapChain; + VkResult err = m_vkCreateSwapchainKHR(m_vkDev, &swapChainInfo, nullptr, &newSwapChain); + if (err != VK_SUCCESS) + qFatal("Failed to create swap chain: %d", err); + + if (oldSwapChain) + releaseSwapChain(); + + m_swapChain = newSwapChain; + + m_swapChainBufferCount = 0; + err = m_vkGetSwapchainImagesKHR(m_vkDev, m_swapChain, &m_swapChainBufferCount, nullptr); + if (err != VK_SUCCESS || m_swapChainBufferCount < 2) + qFatal("Failed to get swapchain images: %d (count=%d)", err, m_swapChainBufferCount); + + qDebug("actual swap chain buffer count: %d", m_swapChainBufferCount); + Q_ASSERT(m_swapChainBufferCount <= SWAPCHAIN_BUFFER_COUNT); + + VkImage swapChainImages[SWAPCHAIN_BUFFER_COUNT]; + err = m_vkGetSwapchainImagesKHR(m_vkDev, m_swapChain, &m_swapChainBufferCount, swapChainImages); + if (err != VK_SUCCESS) + qFatal("Failed to get swapchain images: %d", err); + + // Now that we know m_colorFormat, create the default renderpass, the framebuffers will need it. + createDefaultRenderPass(); + + VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT }; + + for (uint32_t i = 0; i < m_swapChainBufferCount; ++i) { + ImageResources &image(m_imageRes[i]); + image.image = swapChainImages[i]; + + VkImageViewCreateInfo imgViewInfo; + memset(&imgViewInfo, 0, sizeof(imgViewInfo)); + imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imgViewInfo.image = swapChainImages[i]; + imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imgViewInfo.format = m_colorFormat; + imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1; + err = m_devFuncs->vkCreateImageView(m_vkDev, &imgViewInfo, nullptr, &image.imageView); + if (err != VK_SUCCESS) + qFatal("Failed to create swapchain image view %d: %d", i, err); + + err = m_devFuncs->vkCreateFence(m_vkDev, &fenceInfo, nullptr, &image.cmdFence); + if (err != VK_SUCCESS) + qFatal("Failed to create command buffer fence: %d", err); + image.cmdFenceWaitable = true; + + VkImageView views[1] = { image.imageView }; + VkFramebufferCreateInfo fbInfo; + memset(&fbInfo, 0, sizeof(fbInfo)); + fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fbInfo.renderPass = m_defaultRenderPass; + fbInfo.attachmentCount = 1; + fbInfo.pAttachments = views; + fbInfo.width = m_swapChainImageSize.width(); + fbInfo.height = m_swapChainImageSize.height(); + fbInfo.layers = 1; + VkResult err = m_devFuncs->vkCreateFramebuffer(m_vkDev, &fbInfo, nullptr, &image.fb); + if (err != VK_SUCCESS) + qFatal("Failed to create framebuffer: %d", err); + } + + m_currentImage = 0; + + VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; + for (uint32_t i = 0; i < FRAME_LAG; ++i) { + FrameResources &frame(m_frameRes[i]); + m_devFuncs->vkCreateFence(m_vkDev, &fenceInfo, nullptr, &frame.fence); + frame.fenceWaitable = true; + m_devFuncs->vkCreateSemaphore(m_vkDev, &semInfo, nullptr, &frame.imageSem); + m_devFuncs->vkCreateSemaphore(m_vkDev, &semInfo, nullptr, &frame.drawSem); + } + + m_currentFrame = 0; +} + +void VWindow::createDefaultRenderPass() +{ + VkAttachmentDescription attDesc[1]; + memset(attDesc, 0, sizeof(attDesc)); + attDesc[0].format = m_colorFormat; + attDesc[0].samples = VK_SAMPLE_COUNT_1_BIT; + attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subPassDesc; + memset(&subPassDesc, 0, sizeof(subPassDesc)); + subPassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subPassDesc.colorAttachmentCount = 1; + subPassDesc.pColorAttachments = &colorRef; + + VkRenderPassCreateInfo rpInfo; + memset(&rpInfo, 0, sizeof(rpInfo)); + rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rpInfo.attachmentCount = 1; + rpInfo.pAttachments = attDesc; + rpInfo.subpassCount = 1; + rpInfo.pSubpasses = &subPassDesc; + VkResult err = m_devFuncs->vkCreateRenderPass(m_vkDev, &rpInfo, nullptr, &m_defaultRenderPass); + if (err != VK_SUCCESS) + qFatal("Failed to create renderpass: %d", err); +} + +void VWindow::releaseSwapChain() +{ + if (!m_vkDev) + return; + + m_devFuncs->vkDeviceWaitIdle(m_vkDev); + + if (m_defaultRenderPass) { + m_devFuncs->vkDestroyRenderPass(m_vkDev, m_defaultRenderPass, nullptr); + m_defaultRenderPass = 0; + } + + for (uint32_t i = 0; i < FRAME_LAG; ++i) { + FrameResources &frame(m_frameRes[i]); + if (frame.fence) { + if (frame.fenceWaitable) + m_devFuncs->vkWaitForFences(m_vkDev, 1, &frame.fence, VK_TRUE, UINT64_MAX); + m_devFuncs->vkDestroyFence(m_vkDev, frame.fence, nullptr); + frame.fence = 0; + frame.fenceWaitable = false; + } + if (frame.imageSem) { + m_devFuncs->vkDestroySemaphore(m_vkDev, frame.imageSem, nullptr); + frame.imageSem = 0; + } + if (frame.drawSem) { + m_devFuncs->vkDestroySemaphore(m_vkDev, frame.drawSem, nullptr); + frame.drawSem = 0; + } + } + + for (uint32_t i = 0; i < m_swapChainBufferCount; ++i) { + ImageResources &image(m_imageRes[i]); + if (image.cmdFence) { + if (image.cmdFenceWaitable) + m_devFuncs->vkWaitForFences(m_vkDev, 1, &image.cmdFence, VK_TRUE, UINT64_MAX); + m_devFuncs->vkDestroyFence(m_vkDev, image.cmdFence, nullptr); + image.cmdFence = 0; + image.cmdFenceWaitable = false; + } + if (image.fb) { + m_devFuncs->vkDestroyFramebuffer(m_vkDev, image.fb, nullptr); + image.fb = 0; + } + if (image.imageView) { + m_devFuncs->vkDestroyImageView(m_vkDev, image.imageView, nullptr); + image.imageView = 0; + } + if (image.cmdBuf) { + m_devFuncs->vkFreeCommandBuffers(m_vkDev, m_vkCmdPool, 1, &image.cmdBuf); + image.cmdBuf = 0; + } + } + + if (m_swapChain) { + m_vkDestroySwapchainKHR(m_vkDev, m_swapChain, nullptr); + m_swapChain = 0; + } +} + +void VWindow::render() +{ + if (!m_swapChain) + return; + + if (size() != m_swapChainImageSize) { + recreateSwapChain(); + if (!m_swapChain) + return; + } + + FrameResources &frame(m_frameRes[m_currentFrame]); + + // Wait if we are too far ahead, i.e. the thread gets throttled based on the presentation rate + // (note that we are using FIFO mode -> vsync) + if (frame.fenceWaitable) { + m_devFuncs->vkWaitForFences(m_vkDev, 1, &frame.fence, VK_TRUE, UINT64_MAX); + m_devFuncs->vkResetFences(m_vkDev, 1, &frame.fence); + } + + // move on to next swapchain image + VkResult err = m_vkAcquireNextImageKHR(m_vkDev, m_swapChain, UINT64_MAX, + frame.imageSem, frame.fence, &m_currentImage); + if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) { + frame.fenceWaitable = true; + } else if (err == VK_ERROR_OUT_OF_DATE_KHR) { + frame.fenceWaitable = false; + recreateSwapChain(); + requestUpdate(); + return; + } else { + qWarning("Failed to acquire next swapchain image: %d", err); + frame.fenceWaitable = false; + requestUpdate(); + return; + } + + // make sure the previous draw for the same image has finished + ImageResources &image(m_imageRes[m_currentImage]); + if (image.cmdFenceWaitable) { + m_devFuncs->vkWaitForFences(m_vkDev, 1, &image.cmdFence, VK_TRUE, UINT64_MAX); + m_devFuncs->vkResetFences(m_vkDev, 1, &image.cmdFence); + } + + // build new draw command buffer + buildDrawCalls(); + + // submit draw calls + VkSubmitInfo submitInfo; + memset(&submitInfo, 0, sizeof(submitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &image.cmdBuf; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &frame.imageSem; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &frame.drawSem; + VkPipelineStageFlags psf = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + submitInfo.pWaitDstStageMask = &psf; + + err = m_devFuncs->vkQueueSubmit(m_vkGfxQueue, 1, &submitInfo, image.cmdFence); + if (err == VK_SUCCESS) { + image.cmdFenceWaitable = true; + } else { + qWarning("Failed to submit to command queue: %d", err); + image.cmdFenceWaitable = false; + } + + // queue present + VkPresentInfoKHR presInfo; + memset(&presInfo, 0, sizeof(presInfo)); + presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presInfo.swapchainCount = 1; + presInfo.pSwapchains = &m_swapChain; + presInfo.pImageIndices = &m_currentImage; + presInfo.waitSemaphoreCount = 1; + presInfo.pWaitSemaphores = &frame.drawSem; + + // we do not currently handle the case when the present queue is separate + Q_ASSERT(m_vkGfxQueue == m_vkPresQueue); + + err = m_vkQueuePresentKHR(m_vkGfxQueue, &presInfo); + if (err != VK_SUCCESS) { + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + recreateSwapChain(); + requestUpdate(); + return; + } else if (err != VK_SUBOPTIMAL_KHR) { + qWarning("Failed to present: %d", err); + } + } + + vulkanInstance()->presentQueued(this); + + m_currentFrame = (m_currentFrame + 1) % FRAME_LAG; + requestUpdate(); +} + +void VWindow::buildDrawCalls() +{ + ImageResources &image(m_imageRes[m_currentImage]); + + if (image.cmdBuf) { + m_devFuncs->vkFreeCommandBuffers(m_vkDev, m_vkCmdPool, 1, &image.cmdBuf); + image.cmdBuf = 0; + } + + VkCommandBufferAllocateInfo cmdBufInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, m_vkCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 }; + VkResult err = m_devFuncs->vkAllocateCommandBuffers(m_vkDev, &cmdBufInfo, &image.cmdBuf); + if (err != VK_SUCCESS) + qFatal("Failed to allocate frame command buffer: %d", err); + + VkCommandBufferBeginInfo cmdBufBeginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, 0, nullptr }; + err = m_devFuncs->vkBeginCommandBuffer(image.cmdBuf, &cmdBufBeginInfo); + if (err != VK_SUCCESS) + qFatal("Failed to begin frame command buffer: %d", err); + + static float g = 0; + g += 0.005f; + if (g > 1.0f) + g = 0.0f; + VkClearColorValue clearColor = { 0.0f, g, 0.0f, 1.0f }; + VkClearValue clearValues[1]; + clearValues[0].color = clearColor; + + VkRenderPassBeginInfo rpBeginInfo; + memset(&rpBeginInfo, 0, sizeof(rpBeginInfo)); + rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rpBeginInfo.renderPass = m_defaultRenderPass; + rpBeginInfo.framebuffer = image.fb; + rpBeginInfo.renderArea.extent.width = m_swapChainImageSize.width(); + rpBeginInfo.renderArea.extent.height = m_swapChainImageSize.height(); + rpBeginInfo.clearValueCount = 1; + rpBeginInfo.pClearValues = clearValues; + m_devFuncs->vkCmdBeginRenderPass(image.cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + m_devFuncs->vkCmdEndRenderPass(image.cmdBuf); + + err = m_devFuncs->vkEndCommandBuffer(image.cmdBuf); + if (err != VK_SUCCESS) + qFatal("Failed to end frame command buffer: %d", err); +} + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true")); + + QVulkanInstance inst; + // Test the early queries for supported layers/exts. + qDebug() << inst.supportedLayers() << inst.supportedExtensions(); + + // Enable validation layer, if supported. + inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation"); + + bool ok = inst.create(); + qDebug("QVulkanInstance::create() returned %d", ok); + if (!ok) + return 1; + + VWindow w; + w.setVulkanInstance(&inst); + w.resize(1024, 768); + w.show(); + + return app.exec(); +} diff --git a/tests/manual/qvulkaninstance/qvulkaninstance.pro b/tests/manual/qvulkaninstance/qvulkaninstance.pro new file mode 100644 index 0000000000..7305da53c1 --- /dev/null +++ b/tests/manual/qvulkaninstance/qvulkaninstance.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +TARGET = qvulkaninstance + +QT += gui-private + +SOURCES += main.cpp