summaryrefslogtreecommitdiffstats
path: root/src/gui/vulkan/qvulkaninstance.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/vulkan/qvulkaninstance.cpp')
-rw-r--r--src/gui/vulkan/qvulkaninstance.cpp894
1 files changed, 894 insertions, 0 deletions
diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp
new file mode 100644
index 0000000000..8236d9625a
--- /dev/null
+++ b/src/gui/vulkan/qvulkaninstance.cpp
@@ -0,0 +1,894 @@
+/****************************************************************************
+**
+** 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 <private/qvulkanfunctions_p.h>
+#include <qpa/qplatformvulkaninstance.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+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() \e before invoking create().
+
+ To enable additional layers and extensions, provide the list via
+ setLayers() and setExtensions() \e 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 and QVulkanDeviceFunctions objects accessible via
+ functions() and deviceFunctions().
+
+ \note QVulkanFunctions and QVulkanDeviceFunctions are generated from the
+ Vulkan API XML specifications when building the Qt libraries. Therefore no
+ documentation is provided for them. They contain the Vulkan 1.0 functions
+ with the same signatures as described in the
+ \l{https://www.khronos.org/registry/vulkan/specs/1.0/html/}{Vulkan API
+ documentation}.
+
+ \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<QPlatformVulkanInstance> platformInst;
+ VkInstance vkInst;
+ QVulkanInstance::Flags flags;
+ QByteArrayList layers;
+ QByteArrayList extensions;
+ QVersionNumber apiVersion;
+ VkResult errorCode;
+ QScopedPointer<QVulkanFunctions> funcs;
+ QHash<VkDevice, QVulkanDeviceFunctions *> 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();
+}
+
+/*!
+ \class QVulkanLayer
+ \brief Represents information about a Vulkan layer.
+ */
+
+/*!
+ \variable QVulkanLayer::name
+ \brief The name of the layer.
+ */
+
+/*!
+ \variable QVulkanLayer::version
+ \brief The version of the layer. This is an integer, increasing with each backward
+ compatible change.
+ */
+
+/*!
+ \variable QVulkanLayer::specVersion
+ \brief The Vulkan version the layer was written against.
+ */
+
+/*!
+ \variable QVulkanLayer::description
+ \brief The description of the layer.
+ */
+
+/*!
+ \fn bool operator==(const QVulkanLayer &lhs, const QVulkanLayer &rhs)
+ \since 5.10
+ \relates QVulkanLayer
+
+ Returns \c true if Vulkan layers \a lhs and \a rhs have
+ the same name, version, and spec version.
+*/
+
+/*!
+ \fn bool operator!=(const QVulkanLayer &lhs, const QVulkanLayer &rhs)
+ \since 5.10
+ \relates QVulkanLayer
+
+ Returns \c true if Vulkan layers \a lhs and \a rhs have
+ different name, version, or spec version.
+*/
+
+/*!
+ \fn uint qHash(const QVulkanLayer &key, uint seed)
+ \since 5.10
+ \relates QVulkanLayer
+
+ Returns the hash value for the \a key, using \a seed to seed the
+ calculation.
+*/
+
+/*!
+ \class QVulkanExtension
+ \brief Represents information about a Vulkan extension.
+ */
+
+/*!
+ \variable QVulkanExtension::name
+ \brief The name of the extension.
+ */
+
+/*!
+ \variable QVulkanExtension::version
+ \brief The version of the extension. This is an integer, increasing with each backward
+ compatible change.
+ */
+
+/*!
+ \fn bool operator==(const QVulkanExtension &lhs, const QVulkanExtension &rhs)
+ \since 5.10
+ \relates QVulkanExtension
+
+ Returns \c true if Vulkan extensions \a lhs and \a rhs are have the
+ same name and version.
+*/
+
+/*!
+ \fn bool operator!=(const QVulkanExtension &lhs, const QVulkanExtension &rhs)
+ \since 5.10
+ \relates QVulkanExtension
+
+ Returns \c true if Vulkan extensions \a lhs and \a rhs are have different
+ name or version.
+*/
+
+/*!
+ \fn uint qHash(const QVulkanExtension &key, uint seed)
+ \since 5.10
+ \relates QVulkanExtension
+
+ Returns the hash value for the \a key, using \a seed to seed the
+ calculation.
+*/
+
+/*!
+ \class QVulkanInfoVector
+ \brief A specialized QVector for QVulkanLayer and QVulkanExtension.
+ */
+
+/*!
+ \fn template<typename T> bool QVulkanInfoVector<T>::contains(const QByteArray &name) const
+
+ \return true if the vector contains a layer or extension with the given \a name.
+ */
+
+/*!
+ \fn template<typename T> bool QVulkanInfoVector<T>::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<QVulkanLayer> QVulkanInstance::supportedLayers()
+{
+ return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedLayers() : QVulkanInfoVector<QVulkanLayer>();
+}
+
+/*!
+ \return the list of supported instance-level extensions.
+
+ \note This function can be called before create().
+ */
+QVulkanInfoVector<QVulkanExtension> QVulkanInstance::supportedExtensions()
+{
+ return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedExtensions() : QVulkanInfoVector<QVulkanExtension>();
+}
+
+/*!
+ 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 prefer using the function wrappers retrievable from
+ functions() and deviceFunctions() instead.
+ */
+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<VkSurfaceKHR *>(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