From f90107341cf22229110df615b5e4c52466976602 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 23 Sep 2022 16:42:21 +0200 Subject: [PATCH] vulkan: Re-enable VK_KHR_portability drivers The Vulkan loader as of SDK 1.3.216 and MoltenVK decided that all existing applications need to stop working with non-conformant Vulkan implementations such as MoltenVK, unless they start specifying the right soup of instance flags, extensions, and device extensions. Set VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR in VkInstanceCreateInfo::flags. Automatically request VK_KHR_portability_enumeration, if supported, on the instance. This handles the instance side. On the device side we can add support in QRhi so Qt Quick continues to work with MoltenVK. This involves requesting VK_KHR_portability_subset on the device whenever the extension is reported as supported (not doing so would be an error) However, applications creating their own VkDevice will need to take care of this themselves. This device extension requires VK_KHR_get_physical_device_properties2 on the instance (which QRhi does not control). This is no problem with Qt Quick as that already does this automatically, but in the unlikely case of wrapping an existing VkInstance in QVulkanInstance it will be up to the creator of VkInstance to enable that as well. Fixes: QTBUG-106912 Change-Id: Idaf277549b3ec982e99bfc49e4ad6a67976c141a Reviewed-by: Andy Nichols (cherry picked from commit 7fbc741d107ab679f6abd680ec909ce9b2bf333a) Reviewed-by: Qt CI Bot --- src/gui/rhi/qrhivulkan.cpp | 32 ++++++++++++++----- .../vulkan/qbasicvulkanplatforminstance.cpp | 5 +-- src/gui/vulkan/qvulkaninstance.cpp | 14 ++++++-- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 4bdd16e0219..bcf5dab1171 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -534,6 +534,18 @@ bool QRhiVulkan::create(QRhi::Flags flags) QList requestedDevExts; requestedDevExts.append("VK_KHR_swapchain"); + const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2")); + + if (devExts.contains(QByteArrayLiteral("VK_KHR_portability_subset"))) { + if (hasPhysDevProp2) { + requestedDevExts.append("VK_KHR_portability_subset"); + } else { + qWarning("VK_KHR_portability_subset should be enabled on the device " + "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. " + "Expect problems."); + } + } + caps.debugMarkers = false; if (devExts.contains(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); @@ -542,28 +554,32 @@ bool QRhiVulkan::create(QRhi::Flags flags) caps.vertexAttribDivisor = false; if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { - if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { + if (hasPhysDevProp2) { requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); caps.vertexAttribDivisor = true; } } for (const QByteArray &ext : requestedDeviceExtensions) { - if (!ext.isEmpty()) { - if (devExts.contains(ext)) + if (!ext.isEmpty() && !requestedDevExts.contains(ext)) { + if (devExts.contains(ext)) { requestedDevExts.append(ext.constData()); - else - qWarning("Device extension %s is not supported", ext.constData()); + } else { + qWarning("Device extension %s requested in QRhiVulkanInitParams is not supported", + ext.constData()); + } } } QByteArrayList envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';'); for (const QByteArray &ext : envExtList) { if (!ext.isEmpty() && !requestedDevExts.contains(ext)) { - if (devExts.contains(ext)) + if (devExts.contains(ext)) { requestedDevExts.append(ext.constData()); - else - qWarning("Device extension %s is not supported", ext.constData()); + } else { + qWarning("Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported", + ext.constData()); + } } } diff --git a/src/gui/vulkan/qbasicvulkanplatforminstance.cpp b/src/gui/vulkan/qbasicvulkanplatforminstance.cpp index 6825da80695..55d13d966cb 100644 --- a/src/gui/vulkan/qbasicvulkanplatforminstance.cpp +++ b/src/gui/vulkan/qbasicvulkanplatforminstance.cpp @@ -220,11 +220,11 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const apiVersion.microVersion()); } + m_enabledExtensions.append("VK_KHR_surface"); + m_enabledExtensions.append("VK_KHR_portability_enumeration"); if (!flags.testFlag(QVulkanInstance::NoDebugOutputRedirect)) m_enabledExtensions.append("VK_EXT_debug_report"); - m_enabledExtensions.append("VK_KHR_surface"); - for (const QByteArray &ext : extraExts) m_enabledExtensions.append(ext); @@ -263,6 +263,7 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const memset(&instInfo, 0, sizeof(instInfo)); instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instInfo.pApplicationInfo = &appInfo; + instInfo.flags = 0x00000001; // VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR QList layerNameVec; for (const QByteArray &ba : qAsConst(m_enabledLayers)) diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp index bfc4b38b5a9..8a0f691c37b 100644 --- a/src/gui/vulkan/qvulkaninstance.cpp +++ b/src/gui/vulkan/qvulkaninstance.cpp @@ -478,9 +478,13 @@ 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. \note This function can only be called before create() and has no effect if called afterwards. @@ -538,6 +542,10 @@ void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion) The Vulkan instance and library is available as long as this QVulkanInstance exists, or until destroy() is called. + + The VkInstance is always 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. */ bool QVulkanInstance::create() {