summaryrefslogtreecommitdiffstats
path: root/src/gui/vulkan
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/vulkan')
-rw-r--r--src/gui/vulkan/licenseheader.h.in (renamed from src/gui/vulkan/generated_header.txt)0
-rw-r--r--src/gui/vulkan/qbasicvulkanplatforminstance.cpp28
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.cpp11
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.h12
-rw-r--r--src/gui/vulkan/qt_attribution.json2
-rw-r--r--src/gui/vulkan/qvulkandefaultinstance.cpp4
-rw-r--r--src/gui/vulkan/qvulkanfunctions.cpp24
-rw-r--r--src/gui/vulkan/qvulkaninstance.cpp67
-rw-r--r--src/gui/vulkan/qvulkaninstance.h17
-rw-r--r--src/gui/vulkan/qvulkaninstance_p.h2
-rw-r--r--src/gui/vulkan/qvulkanwindow.cpp143
-rw-r--r--src/gui/vulkan/qvulkanwindow.h14
-rw-r--r--src/gui/vulkan/qvulkanwindow_p.h4
13 files changed, 234 insertions, 94 deletions
diff --git a/src/gui/vulkan/generated_header.txt b/src/gui/vulkan/licenseheader.h.in
index 3b6a0ea72a..3b6a0ea72a 100644
--- a/src/gui/vulkan/generated_header.txt
+++ b/src/gui/vulkan/licenseheader.h.in
diff --git a/src/gui/vulkan/qbasicvulkanplatforminstance.cpp b/src/gui/vulkan/qbasicvulkanplatforminstance.cpp
index c5a0b5de17..bbe9f9e1cb 100644
--- a/src/gui/vulkan/qbasicvulkanplatforminstance.cpp
+++ b/src/gui/vulkan/qbasicvulkanplatforminstance.cpp
@@ -147,7 +147,7 @@ void QBasicPlatformVulkanInstance::init(QLibrary *lib)
QList<VkLayerProperties> layerProps(layerCount);
m_vkEnumerateInstanceLayerProperties(&layerCount, layerProps.data());
m_supportedLayers.reserve(layerCount);
- for (const VkLayerProperties &p : qAsConst(layerProps)) {
+ for (const VkLayerProperties &p : std::as_const(layerProps)) {
QVulkanLayer layer;
layer.name = p.layerName;
layer.version = p.implementationVersion;
@@ -166,7 +166,7 @@ void QBasicPlatformVulkanInstance::init(QLibrary *lib)
QList<VkExtensionProperties> extProps(extCount);
m_vkEnumerateInstanceExtensionProperties(nullptr, &extCount, extProps.data());
m_supportedExtensions.reserve(extCount);
- for (const VkExtensionProperties &p : qAsConst(extProps)) {
+ for (const VkExtensionProperties &p : std::as_const(extProps)) {
QVulkanExtension ext;
ext.name = p.extensionName;
ext.version = p.specVersion;
@@ -216,11 +216,12 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const
apiVersion.microVersion());
}
+ m_enabledExtensions.append("VK_KHR_surface");
+ if (!flags.testFlag(QVulkanInstance::NoPortabilityDrivers))
+ m_enabledExtensions.append("VK_KHR_portability_enumeration");
if (!flags.testFlag(QVulkanInstance::NoDebugOutputRedirect))
m_enabledExtensions.append("VK_EXT_debug_utils");
- m_enabledExtensions.append("VK_KHR_surface");
-
for (const QByteArray &ext : extraExts)
m_enabledExtensions.append(ext);
@@ -242,13 +243,13 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const
// 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) {
+ for (int i = 0; i < m_enabledLayers.size(); ++i) {
const QByteArray &layerName(m_enabledLayers[i]);
if (!m_supportedLayers.contains(layerName))
m_enabledLayers.removeAt(i--);
}
qDebug(lcPlatVk) << "Enabling Vulkan instance layers:" << m_enabledLayers;
- for (int i = 0; i < m_enabledExtensions.count(); ++i) {
+ for (int i = 0; i < m_enabledExtensions.size(); ++i) {
const QByteArray &extName(m_enabledExtensions[i]);
if (!m_supportedExtensions.contains(extName))
m_enabledExtensions.removeAt(i--);
@@ -258,20 +259,27 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const
VkInstanceCreateInfo instInfo = {};
instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instInfo.pApplicationInfo = &appInfo;
+ if (!flags.testFlag(QVulkanInstance::NoPortabilityDrivers)) {
+ // With old Vulkan SDKs setting a non-zero flags gives a validation error.
+ // Whereas from 1.3.216 on the portability bit is required for MoltenVK to function.
+ // Hence the version check.
+ if (m_supportedApiVersion >= QVersionNumber(1, 3, 216))
+ instInfo.flags |= 0x00000001; // VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR
+ }
QList<const char *> layerNameVec;
- for (const QByteArray &ba : qAsConst(m_enabledLayers))
+ for (const QByteArray &ba : std::as_const(m_enabledLayers))
layerNameVec.append(ba.constData());
if (!layerNameVec.isEmpty()) {
- instInfo.enabledLayerCount = layerNameVec.count();
+ instInfo.enabledLayerCount = layerNameVec.size();
instInfo.ppEnabledLayerNames = layerNameVec.constData();
}
QList<const char *> extNameVec;
- for (const QByteArray &ba : qAsConst(m_enabledExtensions))
+ for (const QByteArray &ba : std::as_const(m_enabledExtensions))
extNameVec.append(ba.constData());
if (!extNameVec.isEmpty()) {
- instInfo.enabledExtensionCount = extNameVec.count();
+ instInfo.enabledExtensionCount = extNameVec.size();
instInfo.ppEnabledExtensionNames = extNameVec.constData();
}
diff --git a/src/gui/vulkan/qplatformvulkaninstance.cpp b/src/gui/vulkan/qplatformvulkaninstance.cpp
index 2955f2f300..2685a5c6f8 100644
--- a/src/gui/vulkan/qplatformvulkaninstance.cpp
+++ b/src/gui/vulkan/qplatformvulkaninstance.cpp
@@ -64,4 +64,15 @@ void QPlatformVulkanInstance::setDebugUtilsFilters(const QList<QVulkanInstance::
Q_UNUSED(filters);
}
+void QPlatformVulkanInstance::beginFrame(QWindow *window)
+{
+ Q_UNUSED(window);
+}
+
+void QPlatformVulkanInstance::endFrame(QWindow *window)
+{
+ Q_UNUSED(window);
+}
+
+
QT_END_NAMESPACE
diff --git a/src/gui/vulkan/qplatformvulkaninstance.h b/src/gui/vulkan/qplatformvulkaninstance.h
index a3dcc37f0b..d34cb77d1b 100644
--- a/src/gui/vulkan/qplatformvulkaninstance.h
+++ b/src/gui/vulkan/qplatformvulkaninstance.h
@@ -15,7 +15,7 @@
#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(vulkan) || defined(Q_QDOC)
#include <qvulkaninstance.h>
@@ -46,6 +46,8 @@ public:
virtual void presentQueued(QWindow *window);
virtual void setDebugFilters(const QList<QVulkanInstance::DebugFilter> &filters);
virtual void setDebugUtilsFilters(const QList<QVulkanInstance::DebugUtilsFilter> &filters);
+ virtual void beginFrame(QWindow *window);
+ virtual void endFrame(QWindow *window);
private:
QScopedPointer<QPlatformVulkanInstancePrivate> d_ptr;
@@ -56,7 +58,7 @@ QT_END_NAMESPACE
#endif // QT_CONFIG(vulkan)
-#if defined(Q_CLANG_QDOC)
+#if defined(Q_QDOC)
/*
The following include file did not exist for clang-qdoc running
in macOS, but the classes are documented in qvulkanfunctions.cpp.
@@ -70,7 +72,7 @@ QT_END_NAMESPACE
#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(vulkan) || defined(Q_QDOC)
#ifndef VK_NO_PROTOTYPES
#define VK_NO_PROTOTYPES
@@ -113,8 +115,8 @@ private:
QT_END_NAMESPACE
-#endif // QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+#endif // QT_CONFIG(vulkan) || defined(Q_QDOC)
#endif // QVULKANFUNCTIONS_H;
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
#endif // QPLATFORMVULKANINSTANCE_H
diff --git a/src/gui/vulkan/qt_attribution.json b/src/gui/vulkan/qt_attribution.json
index f2ebf9b918..b49e59954d 100644
--- a/src/gui/vulkan/qt_attribution.json
+++ b/src/gui/vulkan/qt_attribution.json
@@ -5,7 +5,7 @@
"QDocModule": "qtgui",
"Description": "Vulkan XML API Registry.",
"QtUsage": "Used to dynamically generate the sources for the QVulkan(Device)Functions classes.",
- "Path": "vk.xml",
+ "Files": "vk.xml",
"Homepage": "https://www.khronos.org/",
"Version": "1.3.223",
diff --git a/src/gui/vulkan/qvulkandefaultinstance.cpp b/src/gui/vulkan/qvulkandefaultinstance.cpp
index 14bc697ce5..b4f343cf17 100644
--- a/src/gui/vulkan/qvulkandefaultinstance.cpp
+++ b/src/gui/vulkan/qvulkandefaultinstance.cpp
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvulkandefaultinstance_p.h"
-#include <private/qrhivulkan_p.h>
+#include <rhi/qrhi.h>
#include <QLoggingCategory>
QT_BEGIN_NAMESPACE
@@ -10,7 +10,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcGuiVk, "qt.vulkan")
static QVulkanInstance *s_vulkanInstance;
-static QVulkanDefaultInstance::Flags s_vulkanInstanceFlags;
+Q_CONSTINIT static QVulkanDefaultInstance::Flags s_vulkanInstanceFlags;
QVulkanDefaultInstance::Flags QVulkanDefaultInstance::flags()
{
diff --git a/src/gui/vulkan/qvulkanfunctions.cpp b/src/gui/vulkan/qvulkanfunctions.cpp
index e6bf10068f..6a30799502 100644
--- a/src/gui/vulkan/qvulkanfunctions.cpp
+++ b/src/gui/vulkan/qvulkanfunctions.cpp
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
\wrapper
\brief The QVulkanFunctions class provides cross-platform access to the
- instance level core Vulkan 1.2 API.
+ instance level core Vulkan 1.3 API.
Qt and Qt applications do not link to any Vulkan libraries by default.
Instead, all functions are resolved dynamically at run time. Each
@@ -45,17 +45,17 @@ QT_BEGIN_NAMESPACE
\l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html}{the
man page for vkGetInstanceProcAddr} for more information.
- \note The member function prototypes for Vulkan 1.1 and 1.2 commands are
- ifdefed with the appropriate \c{VK_VERSION_1_x} that is defined by the
- Vulkan headers. Therefore these functions will only be callable by an
+ \note The member function prototypes for Vulkan 1.1, 1.2, and 1.3 commands
+ are \c ifdefed with the appropriate \c{VK_VERSION_1_x} that is defined by
+ the Vulkan headers. As such, these functions will only be callable by an
application when the system's (on which the application is built) Vulkan
- header is new enough and it contains 1.1 and 1.2 Vulkan API definitions.
- When building Qt from source, this has an additional consequence: the
- Vulkan headers on the build environment must also be 1.1 and 1.2 capable in
- order to get a Qt build that supports resolving the 1.1 and 1.2 API
- commands. If either of these conditions is not met, applications will only
- be able to call the Vulkan 1.0 commands through QVulkanFunctions and
- QVulkanDeviceFunctions.
+ header is new enough and it contains 1.1, 1.2, or 1.3 Vulkan API
+ definitions. When building Qt from source, this has an additional
+ consequence: the Vulkan headers on the build environment must also be 1.1,
+ 1.2, and 1.3 compatible to get a Qt build that supports resolving
+ the 1.1, 1.2, and 1.3 API commands. If neither of these conditions is met,
+ applications will only be able to call the Vulkan 1.0 commands through
+ QVulkanFunctions and QVulkanDeviceFunctions.
\sa QVulkanInstance, QVulkanDeviceFunctions, QWindow::setVulkanInstance(), QWindow::setSurfaceType()
*/
@@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE
\wrapper
\brief The QVulkanDeviceFunctions class provides cross-platform access to
- the device level core Vulkan 1.2 API.
+ the device level core Vulkan 1.3 API.
Qt and Qt applications do not link to any Vulkan libraries by default.
Instead, all functions are resolved dynamically at run time. Each
diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp
index 83d1e9b1b5..6d3020d62d 100644
--- a/src/gui/vulkan/qvulkaninstance.cpp
+++ b/src/gui/vulkan/qvulkaninstance.cpp
@@ -12,6 +12,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QVulkanInstance
\since 5.10
+ \ingroup painting-3D
\inmodule QtGui
\brief The QVulkanInstance class represents a native Vulkan instance, enabling
@@ -206,6 +207,7 @@ QT_BEGIN_NAMESPACE
the behavior of create().
\value NoDebugOutputRedirect Disables Vulkan debug output (\c{VK_EXT_debug_utils}) redirection to qDebug.
+ \value [since 6.5] NoPortabilityDrivers Disables enumerating physical devices marked as Vulkan Portability.
*/
bool QVulkanInstancePrivate::ensureVulkan()
@@ -243,7 +245,8 @@ QVulkanInstance::QVulkanInstance()
/*!
Destructor.
- \note current() will return \nullptr once the instance is destroyed.
+ \note \l {QVulkanInstance::}{vkInstance()} will return \nullptr once the
+ instance is destroyed.
*/
QVulkanInstance::~QVulkanInstance()
{
@@ -478,9 +481,14 @@ void QVulkanInstance::setLayers(const QByteArrayList &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.
+ when not supported at run time.
+
+ \note The surface-related extensions required by Qt (for example, \c
+ VK_KHR_win32_surface) will always be added automatically, no need to
+ include them in this list.
+
+ \note \c VK_KHR_portability_enumeration is added automatically unless the
+ NoPortabilityDrivers flag is set. This value was introduced in Qt 6.5.
\note This function can only be called before create() and has no effect if
called afterwards.
@@ -533,11 +541,16 @@ void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion)
\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().
+ When successful, the pointer to this QVulkanInstance is retrievable via
+ \l {QVulkanInstance::}{vkInstance()}.
The Vulkan instance and library is available as long as this
QVulkanInstance exists, or until destroy() is called.
+
+ By default the VkInstance is created with the flag
+ \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateFlagBits.html}{VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR}
+ set. This means that Vulkan Portability physical devices get enumerated as
+ well. If this is not desired, set the NoPortabilityDrivers flag.
*/
bool QVulkanInstance::create()
{
@@ -556,6 +569,7 @@ bool QVulkanInstance::create()
d_ptr->errorCode = VK_SUCCESS;
d_ptr->funcs.reset(new QVulkanFunctions(this));
d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
+ d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
return true;
}
@@ -810,7 +824,12 @@ void QVulkanInstance::presentQueued(QWindow *window)
/*!
\typedef QVulkanInstance::DebugFilter
- Typedef for debug filtering callback functions.
+ Typedef for debug filtering callback functions, with the following signature:
+
+ \code
+ bool myDebugFilter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object,
+ size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage)
+ \endcode
Returning \c true suppresses the printing of the message.
@@ -867,9 +886,16 @@ void QVulkanInstance::removeDebugOutputFilter(DebugFilter filter)
/*!
\typedef QVulkanInstance::DebugUtilsFilter
- Typedef for debug filtering callback functions. The \c callbackData
- argument is a pointer to the VkDebugUtilsMessengerCallbackDataEXT
- structure.
+ Typedef for debug filtering callback functions, with the following signature:
+
+ \code
+ std::function<bool(DebugMessageSeverityFlags severity, DebugMessageTypeFlags type, const void *message)>;
+ \endcode
+
+ The \c message argument is a pointer to the
+ VkDebugUtilsMessengerCallbackDataEXT structure. Refer to the documentation
+ of \c{VK_EXT_debug_utils} for details. The Qt headers do not use the real
+ type in order to avoid introducing a dependency on post-1.0 Vulkan headers.
Returning \c true suppresses the printing of the message.
@@ -906,20 +932,18 @@ void QVulkanInstance::removeDebugOutputFilter(DebugFilter filter)
\note This function can be called before create().
- \sa removeDebugOutputFilter()
+ \sa clearDebugOutputFilters()
\since 6.5
*/
void QVulkanInstance::installDebugOutputFilter(DebugUtilsFilter filter)
{
- if (!d_ptr->debugUtilsFilters.contains(filter)) {
- d_ptr->debugUtilsFilters.append(filter);
- if (d_ptr->platformInst)
- d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
- }
+ d_ptr->debugUtilsFilters.append(filter);
+ if (d_ptr->platformInst)
+ d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
}
/*!
- Removes a \a filter function previously installed by
+ Removes all filter functions installed previously by
installDebugOutputFilter().
\note This function can be called before create().
@@ -927,11 +951,14 @@ void QVulkanInstance::installDebugOutputFilter(DebugUtilsFilter filter)
\sa installDebugOutputFilter()
\since 6.5
*/
-void QVulkanInstance::removeDebugOutputFilter(DebugUtilsFilter filter)
+void QVulkanInstance::clearDebugOutputFilters()
{
- d_ptr->debugUtilsFilters.removeOne(filter);
- if (d_ptr->platformInst)
+ d_ptr->debugFilters.clear();
+ d_ptr->debugUtilsFilters.clear();
+ if (d_ptr->platformInst) {
+ d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
+ }
}
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/gui/vulkan/qvulkaninstance.h b/src/gui/vulkan/qvulkaninstance.h
index 6fd5116aab..221f605fa2 100644
--- a/src/gui/vulkan/qvulkaninstance.h
+++ b/src/gui/vulkan/qvulkaninstance.h
@@ -11,12 +11,12 @@
#pragma qt_sync_skip_header_check
#endif
-#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(vulkan) || defined(Q_QDOC)
#ifndef VK_NO_PROTOTYPES
#define VK_NO_PROTOTYPES
#endif
-#if !defined(Q_CLANG_QDOC) && __has_include(<vulkan/vulkan.h>)
+#if !defined(Q_QDOC) && __has_include(<vulkan/vulkan.h>)
#include <vulkan/vulkan.h>
#else
// QT_CONFIG(vulkan) implies vulkan.h being available at Qt build time, but it
@@ -45,7 +45,7 @@ typedef int VkDebugReportObjectTypeEXT;
// QVulkanInstance itself is only applicable if vulkan.h is available, or if
// it's qdoc. An application that is built on a vulkan.h-less system against a
// Vulkan-enabled Qt gets the dummy typedefs but not QVulkan*.
-#if __has_include(<vulkan/vulkan.h>) || defined(Q_CLANG_QDOC)
+#if __has_include(<vulkan/vulkan.h>) || defined(Q_QDOC)
#include <QtCore/qbytearraylist.h>
#include <QtCore/qdebug.h>
@@ -135,7 +135,8 @@ public:
~QVulkanInstance();
enum Flag {
- NoDebugOutputRedirect = 0x01
+ NoDebugOutputRedirect = 0x01,
+ NoPortabilityDrivers = 0x02
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -202,9 +203,9 @@ public:
};
Q_DECLARE_FLAGS(DebugMessageTypeFlags, DebugMessageTypeFlag)
- typedef bool (*DebugUtilsFilter)(DebugMessageSeverityFlags severity, DebugMessageTypeFlags type, const void *callbackData);
+ using DebugUtilsFilter = std::function<bool(DebugMessageSeverityFlags severity, DebugMessageTypeFlags type, const void *message)>;
void installDebugOutputFilter(DebugUtilsFilter filter);
- void removeDebugOutputFilter(DebugUtilsFilter filter);
+ void clearDebugOutputFilters();
private:
friend class QVulkanInstancePrivate;
@@ -218,8 +219,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QVulkanInstance::DebugMessageSeverityFlags)
QT_END_NAMESPACE
-#endif // __has_include(<vulkan/vulkan.h>) || defined(Q_CLANG_QDOC)
+#endif // __has_include(<vulkan/vulkan.h>) || defined(Q_QDOC)
-#endif // QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+#endif // QT_CONFIG(vulkan) || defined(Q_QDOC)
#endif // QVULKANINSTANCE_H
diff --git a/src/gui/vulkan/qvulkaninstance_p.h b/src/gui/vulkan/qvulkaninstance_p.h
index 9545d4e688..d707b301c6 100644
--- a/src/gui/vulkan/qvulkaninstance_p.h
+++ b/src/gui/vulkan/qvulkaninstance_p.h
@@ -6,7 +6,7 @@
#include <QtGui/private/qtguiglobal_p.h>
-#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(vulkan) || defined(Q_QDOC)
#include "qvulkaninstance.h"
#include <private/qvulkanfunctions_p.h>
diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp
index 29d6d0d5bd..00a5c5f869 100644
--- a/src/gui/vulkan/qvulkanwindow.cpp
+++ b/src/gui/vulkan/qvulkanwindow.cpp
@@ -178,12 +178,11 @@ Q_DECLARE_LOGGING_CATEGORY(lcGuiVk)
As an exception to this rule, \c robustBufferAccess is never enabled. Use the
callback mechanism described below, if enabling that feature is desired.
- Just enabling the 1.0 core features is not always sufficient, and therefore
- full control over the VkPhysicalDeviceFeatures used for device creation is
- possible too by registering a callback function with
+ This is not always desirable, and may be insufficient with Vulkan 1.1 and
+ higher. Therefore, full control over the VkPhysicalDeviceFeatures used for
+ device creation is possible too by registering a callback function with
setEnabledFeaturesModifier(). When set, the callback function is invoked,
- letting it alter the VkPhysicalDeviceFeatures, instead of enabling only the
- 1.0 core features.
+ letting it alter the VkPhysicalDeviceFeatures or VkPhysicalDeviceFeatures2.
\sa QVulkanInstance, QWindow
*/
@@ -335,7 +334,7 @@ void QVulkanWindow::setPhysicalDeviceIndex(int idx)
qWarning("QVulkanWindow: Attempted to set physical device when already initialized");
return;
}
- const int count = availablePhysicalDevices().count();
+ const int count = availablePhysicalDevices().size();
if (idx < 0 || idx >= count) {
qWarning("QVulkanWindow: Invalid physical device index %d (total physical devices: %d)", idx, count);
return;
@@ -448,7 +447,7 @@ void QVulkanWindow::setPreferredColorFormats(const QList<VkFormat> &formats)
static struct {
VkSampleCountFlagBits mask;
int count;
-} qvk_sampleCounts[] = {
+} q_vk_sampleCounts[] = {
// keep this sorted by 'count'
{ VK_SAMPLE_COUNT_1_BIT, 1 },
{ VK_SAMPLE_COUNT_2_BIT, 2 },
@@ -488,7 +487,7 @@ QList<int> QVulkanWindow::supportedSampleCounts()
VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
- for (const auto &qvk_sampleCount : qvk_sampleCounts) {
+ for (const auto &qvk_sampleCount : q_vk_sampleCounts) {
if ((color & qvk_sampleCount.mask)
&& (depth & qvk_sampleCount.mask)
&& (stencil & qvk_sampleCount.mask))
@@ -537,7 +536,7 @@ void QVulkanWindow::setSampleCount(int sampleCount)
return;
}
- for (const auto &qvk_sampleCount : qvk_sampleCounts) {
+ for (const auto &qvk_sampleCount : q_vk_sampleCounts) {
if (qvk_sampleCount.count == sampleCount) {
d->sampleCount = qvk_sampleCount.mask;
return;
@@ -581,7 +580,7 @@ void QVulkanWindowPrivate::init()
return;
}
- if (physDevIndex < 0 || physDevIndex >= physDevs.count()) {
+ if (physDevIndex < 0 || physDevIndex >= physDevs.size()) {
qWarning("QVulkanWindow: Invalid physical device index; defaulting to 0");
physDevIndex = 0;
}
@@ -600,7 +599,7 @@ void QVulkanWindowPrivate::init()
f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
gfxQueueFamilyIdx = uint32_t(-1);
presQueueFamilyIdx = uint32_t(-1);
- for (int i = 0; i < queueFamilyProps.count(); ++i) {
+ for (int i = 0; i < queueFamilyProps.size(); ++i) {
const bool supportsPresent = inst->supportsPresent(physDev, i, q);
qCDebug(lcGuiVk, "queue family %d: flags=0x%x count=%d supportsPresent=%d", i,
queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount, supportsPresent);
@@ -613,7 +612,7 @@ void QVulkanWindowPrivate::init()
presQueueFamilyIdx = gfxQueueFamilyIdx;
} else {
qCDebug(lcGuiVk, "No queue with graphics+present; trying separate queues");
- for (int i = 0; i < queueFamilyProps.count(); ++i) {
+ for (int i = 0; i < queueFamilyProps.size(); ++i) {
if (gfxQueueFamilyIdx == uint32_t(-1) && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
gfxQueueFamilyIdx = i;
if (presQueueFamilyIdx == uint32_t(-1) && inst->supportsPresent(physDev, i, q))
@@ -657,7 +656,7 @@ void QVulkanWindowPrivate::init()
queueCreateInfoModifier(queueFamilyProps.constData(), queueCount, queueInfo);
bool foundGfxQueue = false;
bool foundPresQueue = false;
- for (const VkDeviceQueueCreateInfo& createInfo : qAsConst(queueInfo)) {
+ for (const VkDeviceQueueCreateInfo& createInfo : std::as_const(queueInfo)) {
foundGfxQueue |= createInfo.queueFamilyIndex == gfxQueueFamilyIdx;
foundPresQueue |= createInfo.queueFamilyIndex == presQueueFamilyIdx;
}
@@ -699,20 +698,25 @@ void QVulkanWindowPrivate::init()
devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
devInfo.queueCreateInfoCount = queueInfo.size();
devInfo.pQueueCreateInfos = queueInfo.constData();
- devInfo.enabledExtensionCount = devExts.count();
+ devInfo.enabledExtensionCount = devExts.size();
devInfo.ppEnabledExtensionNames = devExts.constData();
- VkPhysicalDeviceFeatures features;
- memset(&features, 0, sizeof(features));
- if (enabledFeaturesModifier) {
+ VkPhysicalDeviceFeatures features = {};
+ VkPhysicalDeviceFeatures2 features2 = {};
+ if (enabledFeatures2Modifier) {
+ features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ enabledFeatures2Modifier(features2);
+ devInfo.pNext = &features2;
+ } else if (enabledFeaturesModifier) {
enabledFeaturesModifier(features);
+ devInfo.pEnabledFeatures = &features;
} else {
// Enable all supported 1.0 core features, except ones that likely
// involve a performance penalty.
f->vkGetPhysicalDeviceFeatures(physDev, &features);
features.robustBufferAccess = VK_FALSE;
+ devInfo.pEnabledFeatures = &features;
}
- devInfo.pEnabledFeatures = &features;
// Device layers are not supported by QVulkanWindow since that's an already deprecated
// API. However, have a workaround for systems with older API and layers (f.ex. L4T
@@ -857,7 +861,7 @@ void QVulkanWindowPrivate::init()
// Try to honor the user request.
if (!formats.isEmpty() && !requestedColorFormats.isEmpty()) {
- for (VkFormat reqFmt : qAsConst(requestedColorFormats)) {
+ for (VkFormat reqFmt : std::as_const(requestedColorFormats)) {
auto r = std::find_if(formats.cbegin(), formats.cend(),
[reqFmt](const VkSurfaceFormatKHR &sfmt) { return sfmt.format == reqFmt; });
if (r != formats.cend()) {
@@ -1625,16 +1629,12 @@ void QVulkanWindow::setQueueCreateInfoModifier(const QueueCreateInfoModifier &mo
praticular, \c robustBufferAccess is always disabled in order to avoid
unexpected performance hits.
- This however is not always sufficient when working with Vulkan 1.1 or 1.2
- features and extensions. Hence this callback mechanism.
-
The VkPhysicalDeviceFeatures reference passed in is all zeroed out at the
point when the function is invoked. It is up to the function to change
- members to true, or set up \c pNext chains as it sees fit.
+ members as it sees fit.
- \note When setting up \c pNext chains, make sure the referenced objects
- have a long enough lifetime, for example by storing them as member
- variables in the QVulkanWindow subclass.
+ \note To control Vulkan 1.1, 1.2, or 1.3 features, use
+ EnabledFeatures2Modifier instead.
\sa setEnabledFeaturesModifier()
*/
@@ -1642,9 +1642,14 @@ void QVulkanWindow::setQueueCreateInfoModifier(const QueueCreateInfoModifier &mo
/*!
Sets the enabled device features modification function \a modifier.
- \sa EnabledFeaturesModifier
+ \note To control Vulkan 1.1, 1.2, or 1.3 features, use
+ the overload taking a EnabledFeatures2Modifier instead.
+
+ \note \a modifier is passed to the callback function with all members set
+ to false. It is up to the function to change members as it sees fit.
- \since 6.4
+ \since 6.7
+ \sa EnabledFeaturesModifier
*/
void QVulkanWindow::setEnabledFeaturesModifier(const EnabledFeaturesModifier &modifier)
{
@@ -1653,6 +1658,45 @@ void QVulkanWindow::setEnabledFeaturesModifier(const EnabledFeaturesModifier &mo
}
/*!
+ \typedef QVulkanWindow::EnabledFeatures2Modifier
+
+ A function that is called during graphics initialization to alter the
+ VkPhysicalDeviceFeatures2 that is changed to the VkDeviceCreateInfo.
+
+ By default QVulkanWindow enables all Vulkan 1.0 core features that the
+ physical device reports as supported, with certain exceptions. In
+ praticular, \c robustBufferAccess is always disabled in order to avoid
+ unexpected performance hits.
+
+ This however is not always sufficient when working with Vulkan 1.1, 1.2, or
+ 1.3 features and extensions. Hence this callback mechanism. If only Vulkan
+ 1.0 is relevant at run time, use setEnabledFeaturesModifier() instead.
+
+ The VkPhysicalDeviceFeatures2 reference passed to the callback function
+ with \c sType set, but the rest zeroed out. It is up to the function to
+ change members to true, or set up \c pNext chains as it sees fit.
+
+ \note When setting up \c pNext chains, make sure the referenced objects
+ have a long enough lifetime, for example by storing them as member
+ variables in the QVulkanWindow subclass.
+
+ \since 6.7
+ \sa setEnabledFeaturesModifier()
+ */
+
+/*!
+ Sets the enabled device features modification function \a modifier.
+ \overload
+ \since 6.7
+ \sa EnabledFeatures2Modifier
+*/
+void QVulkanWindow::setEnabledFeaturesModifier(EnabledFeatures2Modifier modifier)
+{
+ Q_D(QVulkanWindow);
+ d->enabledFeatures2Modifier = std::move(modifier);
+}
+
+/*!
Returns true if this window has successfully initialized all Vulkan
resources, including the swapchain.
@@ -1852,13 +1896,26 @@ void QVulkanWindowRenderer::logicalDeviceLost()
{
}
+QSize QVulkanWindowPrivate::surfacePixelSize() const
+{
+ Q_Q(const QVulkanWindow);
+ VkSurfaceCapabilitiesKHR surfaceCaps = {};
+ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDevs.at(physDevIndex), surface, &surfaceCaps);
+ VkExtent2D bufferSize = surfaceCaps.currentExtent;
+ if (bufferSize.width == uint32_t(-1)) {
+ Q_ASSERT(bufferSize.height == uint32_t(-1));
+ return q->size() * q->devicePixelRatio();
+ }
+ return QSize(int(bufferSize.width), int(bufferSize.height));
+}
+
void QVulkanWindowPrivate::beginFrame()
{
if (!swapChain || framePending)
return;
Q_Q(QVulkanWindow);
- if (q->size() * q->devicePixelRatio() != swapChainImageSize) {
+ if (swapChainImageSize != surfacePixelSize()) {
recreateSwapChain();
if (!swapChain)
return;
@@ -1927,7 +1984,7 @@ void QVulkanWindowPrivate::beginFrame()
}
if (frameGrabbing)
- frameGrabTargetImage = QImage(swapChainImageSize, QImage::Format_RGBA8888);
+ frameGrabTargetImage = QImage(swapChainImageSize, QImage::Format_RGBA8888); // the format is as documented
if (renderer) {
framePending = true;
@@ -2273,7 +2330,7 @@ void QVulkanWindowPrivate::finishBlockingReadback()
VkPhysicalDevice QVulkanWindow::physicalDevice() const
{
Q_D(const QVulkanWindow);
- if (d->physDevIndex < d->physDevs.count())
+ if (d->physDevIndex < d->physDevs.size())
return d->physDevs[d->physDevIndex];
qWarning("QVulkanWindow: Physical device not available");
return VK_NULL_HANDLE;
@@ -2289,7 +2346,7 @@ VkPhysicalDevice QVulkanWindow::physicalDevice() const
const VkPhysicalDeviceProperties *QVulkanWindow::physicalDeviceProperties() const
{
Q_D(const QVulkanWindow);
- if (d->physDevIndex < d->physDevProps.count())
+ if (d->physDevIndex < d->physDevProps.size())
return &d->physDevProps[d->physDevIndex];
qWarning("QVulkanWindow: Physical device properties not available");
return nullptr;
@@ -2443,6 +2500,19 @@ VkFormat QVulkanWindow::depthStencilFormat() const
This usually matches the size of the window, but may also differ in case
\c vkGetPhysicalDeviceSurfaceCapabilitiesKHR reports a fixed size.
+ In addition, it has been observed on some platforms that the
+ Vulkan-reported surface size is different with high DPI scaling active,
+ meaning the QWindow-reported
+ \l{QWindow::}{size()} multiplied with the \l{QWindow::}{devicePixelRatio()}
+ was 1 pixel less or more when compared to the value returned from here,
+ presumably due to differences in rounding. Rendering code should be aware
+ of this, and any related rendering logic must be based in the value returned
+ from here, never on the QWindow-reported size. Regardless of which pixel size
+ is correct in theory, Vulkan rendering must only ever rely on the Vulkan
+ API-reported surface size. Otherwise validation errors may occur, e.g. when
+ setting the viewport, because the application-provided values may become
+ out-of-bounds from Vulkan's perspective.
+
\note Calling this function is only valid from the invocation of
QVulkanWindowRenderer::initSwapChainResources() up until
QVulkanWindowRenderer::releaseSwapChainResources().
@@ -2714,6 +2784,12 @@ bool QVulkanWindow::supportsGrab() const
incomplete image, that has the correct size but not the content yet. The
content will be delivered via the frameGrabbed() signal in the latter case.
+ The returned QImage always has a format of QImage::Format_RGBA8888. If the
+ colorFormat() is \c VK_FORMAT_B8G8R8A8_UNORM, the red and blue channels are
+ swapped automatically since this format is commonly used as the default
+ choice for swapchain color buffers. With any other color buffer format,
+ there is no conversion performed by this function.
+
\note This function should not be called when a frame is in progress
(that is, frameReady() has not yet been called back by the application).
@@ -2742,6 +2818,9 @@ QImage QVulkanWindow::grab()
d->frameGrabbing = true;
d->beginFrame();
+ if (d->colorFormat == VK_FORMAT_B8G8R8A8_UNORM)
+ d->frameGrabTargetImage = std::move(d->frameGrabTargetImage).rgbSwapped();
+
return d->frameGrabTargetImage;
}
diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h
index a2b538ed54..537dbc4ae1 100644
--- a/src/gui/vulkan/qvulkanwindow.h
+++ b/src/gui/vulkan/qvulkanwindow.h
@@ -11,7 +11,7 @@
#pragma qt_sync_skip_header_check
#endif
-#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(vulkan) || defined(Q_QDOC)
#include <QtGui/qvulkaninstance.h>
#include <QtGui/qwindow.h>
@@ -19,7 +19,7 @@
#include <QtGui/qmatrix4x4.h>
#include <QtCore/qset.h>
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
typedef void* VkQueue;
typedef void* VkCommandPool;
typedef void* VkRenderPass;
@@ -54,6 +54,14 @@ public:
virtual void logicalDeviceLost();
};
+#ifndef VK_VERSION_1_1
+typedef struct VkPhysicalDeviceFeatures2 {
+ VkStructureType sType;
+ void* pNext;
+ VkPhysicalDeviceFeatures features;
+} VkPhysicalDeviceFeatures2;
+#endif
+
class Q_GUI_EXPORT QVulkanWindow : public QWindow
{
Q_OBJECT
@@ -79,6 +87,8 @@ public:
typedef std::function<void(VkPhysicalDeviceFeatures &)> EnabledFeaturesModifier;
void setEnabledFeaturesModifier(const EnabledFeaturesModifier &modifier);
+ typedef std::function<void(VkPhysicalDeviceFeatures2 &)> EnabledFeatures2Modifier;
+ void setEnabledFeaturesModifier(EnabledFeatures2Modifier modifier);
void setPreferredColorFormats(const QList<VkFormat> &formats);
diff --git a/src/gui/vulkan/qvulkanwindow_p.h b/src/gui/vulkan/qvulkanwindow_p.h
index 6327334222..7a0ee091e6 100644
--- a/src/gui/vulkan/qvulkanwindow_p.h
+++ b/src/gui/vulkan/qvulkanwindow_p.h
@@ -6,7 +6,7 @@
#include <QtGui/private/qtguiglobal_p.h>
-#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(vulkan) || defined(Q_QDOC)
#include "qvulkanwindow.h"
#include <QtCore/QHash>
@@ -36,6 +36,7 @@ public:
void init();
void reset();
bool createDefaultRenderPass();
+ QSize surfacePixelSize() const;
void recreateSwapChain();
uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex);
bool createTransientImage(VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectMask,
@@ -68,6 +69,7 @@ public:
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
QVulkanWindow::QueueCreateInfoModifier queueCreateInfoModifier;
QVulkanWindow::EnabledFeaturesModifier enabledFeaturesModifier;
+ QVulkanWindow::EnabledFeatures2Modifier enabledFeatures2Modifier;
VkDevice dev = VK_NULL_HANDLE;
QVulkanDeviceFunctions *devFuncs;