69f6cab0af
Try to replace all wordings like '.. to 0' with '.. to \nullptr'. Also checked for 'null pointer' and similar. Change-Id: I73341f59ba51e0798e816a8b1a532c7c7374b74a Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
806 lines
27 KiB
C++
806 lines
27 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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:
|
|
|
|
\snippet code/src_gui_vulkan_qvulkaninstance.cpp 0
|
|
|
|
\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:
|
|
|
|
\snippet code/src_gui_vulkan_qvulkaninstance.cpp 1
|
|
|
|
Or, alternatively, to make decisions before attempting to create a Vulkan
|
|
instance:
|
|
|
|
\snippet code/src_gui_vulkan_qvulkaninstance.cpp 2
|
|
|
|
\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:
|
|
|
|
\snippet code/src_gui_vulkan_qvulkaninstance.cpp 3
|
|
|
|
\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 \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 \nullptr 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
|