From bd2b77120e1db8cb991aff23dd1f99cec792fa8e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 29 Feb 2020 15:38:07 +0100 Subject: [PATCH] rhi: vulkan: Sanitize device extension handling Instead of qputenv("QT_VULKAN_DEVICE_EXTENSIONS", "VK_KHR_get_memory_requirements2;VK_NV_ray_tracing"); one can now do params.deviceExtensions = { "VK_KHR_get_memory_requirements2", "VK_NV_ray_tracing" }; on the QRhiVulkanInitParams passed to QRhi::create(). The environment variable stays important for Qt Quick applications, which provide no configurability for the QRhi construction (yet). On the other hand, applications using QRhi directly can now also use the new approach to specify the list of device extensions to enable. In addition, take QVulkanInfoVector into use. There is no reason not to rely on the infrastructure provided by QVulkanInstance. This also implies showing an informative warning for unsupported extensions, instead of merely failing the device creation. (applications will likely not be able to recover of course, but at least the reason for failing is made obvious this way) Task-number: QTBUG-82435 Change-Id: Ib47fd1a10c02be5ceef2c973e61e896c34f92fa3 Reviewed-by: Eirik Aavitsland --- src/gui/rhi/qrhivulkan.cpp | 60 +++++++++++++++++++++++++----------- src/gui/rhi/qrhivulkan_p.h | 1 + src/gui/rhi/qrhivulkan_p_p.h | 1 + 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 8f6f118c9b..60ab15e89d 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -149,6 +149,10 @@ QT_BEGIN_NAMESPACE for other windows as well, as long as they all have their QWindow::surfaceType() set to QSurface::VulkanSurface. + To request additional extensions to be enabled on the Vulkan device, list them + in deviceExtensions. This can be relevant when integrating with native Vulkan + rendering code. + \section2 Working with existing Vulkan devices When interoperating with another graphics engine, it may be necessary to @@ -299,6 +303,7 @@ QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *im { inst = params->inst; maybeWindow = params->window; // may be null + requestedDeviceExtensions = params->deviceExtensions; importedDevice = importDevice != nullptr; if (importedDevice) { @@ -463,40 +468,59 @@ bool QRhiVulkan::create(QRhi::Flags flags) if (inst->layers().contains("VK_LAYER_LUNARG_standard_validation")) devLayers.append("VK_LAYER_LUNARG_standard_validation"); + QVulkanInfoVector devExts; uint32_t devExtCount = 0; f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, nullptr); - QVector devExts(devExtCount); - f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, devExts.data()); + if (devExtCount) { + QVector extProps(devExtCount); + f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, extProps.data()); + for (const VkExtensionProperties &p : qAsConst(extProps)) + devExts.append({ p.extensionName, p.specVersion }); + } qCDebug(QRHI_LOG_INFO, "%d device extensions available", devExts.count()); QVector requestedDevExts; requestedDevExts.append("VK_KHR_swapchain"); debugMarkersAvailable = false; + if (devExts.contains(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { + requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); + debugMarkersAvailable = true; + } + vertexAttribDivisorAvailable = false; - for (const VkExtensionProperties &ext : devExts) { - if (!strcmp(ext.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { - requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); - debugMarkersAvailable = true; - } else if (!strcmp(ext.extensionName, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { - if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { - requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); - vertexAttribDivisorAvailable = true; - } + if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { + if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { + requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); + vertexAttribDivisorAvailable = true; } } - QByteArrayList envExtList; - if (qEnvironmentVariableIsSet("QT_VULKAN_DEVICE_EXTENSIONS")) { - envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';'); - for (auto ext : requestedDevExts) - envExtList.removeAll(ext); - for (const QByteArray &ext : envExtList) { - if (!ext.isEmpty()) + for (const QByteArray &ext : requestedDeviceExtensions) { + if (!ext.isEmpty()) { + if (devExts.contains(ext)) requestedDevExts.append(ext.constData()); + else + qWarning("Device extension %s 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)) + requestedDevExts.append(ext.constData()); + else + qWarning("Device extension %s is not supported", ext.constData()); + } + } + + if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) { + qCDebug(QRHI_LOG_INFO, "Enabling device extensions:"); + for (const char *ext : requestedDevExts) + qCDebug(QRHI_LOG_INFO, " %s", ext); + } + VkDeviceCreateInfo devInfo; memset(&devInfo, 0, sizeof(devInfo)); devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h index d495919671..f8870dcd77 100644 --- a/src/gui/rhi/qrhivulkan_p.h +++ b/src/gui/rhi/qrhivulkan_p.h @@ -57,6 +57,7 @@ struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams { QVulkanInstance *inst = nullptr; QWindow *window = nullptr; + QByteArrayList deviceExtensions; }; struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 0f0a89cbff..a6bcb7e7b6 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -810,6 +810,7 @@ public: QVulkanInstance *inst = nullptr; QWindow *maybeWindow = nullptr; + QByteArrayList requestedDeviceExtensions; bool importedDevice = false; VkPhysicalDevice physDev = VK_NULL_HANDLE; VkDevice dev = VK_NULL_HANDLE;