diff options
Diffstat (limited to 'src/gui/vulkan/qbasicvulkanplatforminstance.cpp')
-rw-r--r-- | src/gui/vulkan/qbasicvulkanplatforminstance.cpp | 216 |
1 files changed, 124 insertions, 92 deletions
diff --git a/src/gui/vulkan/qbasicvulkanplatforminstance.cpp b/src/gui/vulkan/qbasicvulkanplatforminstance.cpp index 233f884ce6..bbe9f9e1cb 100644 --- a/src/gui/vulkan/qbasicvulkanplatforminstance.cpp +++ b/src/gui/vulkan/qbasicvulkanplatforminstance.cpp @@ -1,46 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qbasicvulkanplatforminstance_p.h" #include <QCoreApplication> #include <QList> #include <QLoggingCategory> +#include <QVarLengthArray> QT_BEGIN_NAMESPACE @@ -61,11 +26,6 @@ Q_LOGGING_CATEGORY(lcPlatVk, "qt.vulkan") */ QBasicPlatformVulkanInstance::QBasicPlatformVulkanInstance() - : m_vkInst(VK_NULL_HANDLE), - m_vkGetInstanceProcAddr(nullptr), - m_ownsVkInst(false), - m_errorCode(VK_SUCCESS), - m_debugCallback(VK_NULL_HANDLE) { } @@ -74,26 +34,54 @@ QBasicPlatformVulkanInstance::~QBasicPlatformVulkanInstance() if (!m_vkInst) return; - if (m_debugCallback && m_vkDestroyDebugReportCallbackEXT) - m_vkDestroyDebugReportCallbackEXT(m_vkInst, m_debugCallback, nullptr); +#ifdef VK_EXT_debug_utils + if (m_debugMessenger) + m_vkDestroyDebugUtilsMessengerEXT(m_vkInst, m_debugMessenger, nullptr); +#endif if (m_ownsVkInst) m_vkDestroyInstance(m_vkInst, nullptr); } -void QBasicPlatformVulkanInstance::loadVulkanLibrary(const QString &defaultLibraryName) +void QBasicPlatformVulkanInstance::loadVulkanLibrary(const QString &defaultLibraryName, int defaultLibraryVersion) { + QVarLengthArray<std::pair<QString, int>, 3> loadList; + + // First in the list of libraries to try is the manual override, relevant on + // embedded systems without a Vulkan loader and possibly with custom vendor + // library names. if (qEnvironmentVariableIsSet("QT_VULKAN_LIB")) - m_vulkanLib.setFileName(QString::fromUtf8(qgetenv("QT_VULKAN_LIB"))); - else - m_vulkanLib.setFileName(defaultLibraryName); + loadList.append({ QString::fromUtf8(qgetenv("QT_VULKAN_LIB")), -1 }); + + // Then what the platform specified. On Linux the version is likely 1, thus + // preferring libvulkan.so.1 over libvulkan.so. + loadList.append({ defaultLibraryName, defaultLibraryVersion }); + + // If there was a version given, we must still try without it if the first + // attempt fails, so that libvulkan.so is picked up if the .so.1 is not + // present on the system (so loaderless embedded systems still work). + if (defaultLibraryVersion >= 0) + loadList.append({ defaultLibraryName, -1 }); + + bool ok = false; + for (const auto &lib : loadList) { + m_vulkanLib.reset(new QLibrary); + if (lib.second >= 0) + m_vulkanLib->setFileNameAndVersion(lib.first, lib.second); + else + m_vulkanLib->setFileName(lib.first); + if (m_vulkanLib->load()) { + ok = true; + break; + } + } - if (!m_vulkanLib.load()) { - qWarning("Failed to load %s: %s", qPrintable(m_vulkanLib.fileName()), qPrintable(m_vulkanLib.errorString())); + if (!ok) { + qWarning("Failed to load %s: %s", qPrintable(m_vulkanLib->fileName()), qPrintable(m_vulkanLib->errorString())); return; } - init(&m_vulkanLib); + init(m_vulkanLib.get()); } void QBasicPlatformVulkanInstance::init(QLibrary *lib) @@ -159,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; @@ -178,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; @@ -217,8 +205,7 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const m_enabledExtensions = instance->extensions(); if (!m_vkInst) { - VkApplicationInfo appInfo; - memset(&appInfo, 0, sizeof(appInfo)); + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; QByteArray appName = QCoreApplication::applicationName().toUtf8(); appInfo.pApplicationName = appName.constData(); @@ -229,10 +216,11 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const apiVersion.microVersion()); } - if (!flags.testFlag(QVulkanInstance::NoDebugOutputRedirect)) - m_enabledExtensions.append("VK_EXT_debug_report"); - 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"); for (const QByteArray &ext : extraExts) m_enabledExtensions.append(ext); @@ -255,37 +243,43 @@ 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--); } qDebug(lcPlatVk) << "Enabling Vulkan instance extensions:" << m_enabledExtensions; - VkInstanceCreateInfo instInfo; - memset(&instInfo, 0, sizeof(instInfo)); + 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(); } @@ -374,55 +368,93 @@ void QBasicPlatformVulkanInstance::setDebugFilters(const QList<QVulkanInstance:: m_debugFilters = filters; } +void QBasicPlatformVulkanInstance::setDebugUtilsFilters(const QList<QVulkanInstance::DebugUtilsFilter> &filters) +{ + m_debugUtilsFilters = filters; +} + void QBasicPlatformVulkanInstance::destroySurface(VkSurfaceKHR surface) const { if (m_destroySurface && surface) m_destroySurface(m_vkInst, surface, nullptr); } -static VKAPI_ATTR VkBool32 VKAPI_CALL defaultDebugCallbackFunc(VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char *pLayerPrefix, - const char *pMessage, +#ifdef VK_EXT_debug_utils +static VKAPI_ATTR VkBool32 VKAPI_CALL defaultDebugCallbackFunc(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData) { QBasicPlatformVulkanInstance *self = static_cast<QBasicPlatformVulkanInstance *>(pUserData); + + // legacy filters for (QVulkanInstance::DebugFilter filter : *self->debugFilters()) { - if (filter(flags, objectType, object, location, messageCode, pLayerPrefix, pMessage)) + // As per docs in qvulkaninstance.cpp we pass object, messageCode, + // pMessage to the callback with the legacy signature. + uint64_t object = 0; + if (pCallbackData->objectCount > 0) + object = pCallbackData->pObjects[0].objectHandle; + if (filter(0, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, object, 0, + pCallbackData->messageIdNumber, "", pCallbackData->pMessage)) + { + return VK_FALSE; + } + } + + // filters with new signature + for (QVulkanInstance::DebugUtilsFilter filter : *self->debugUtilsFilters()) { + QVulkanInstance::DebugMessageSeverityFlags severity; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) + severity |= QVulkanInstance::VerboseSeverity; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) + severity |= QVulkanInstance::InfoSeverity; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) + severity |= QVulkanInstance::WarningSeverity; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + severity |= QVulkanInstance::ErrorSeverity; + QVulkanInstance::DebugMessageTypeFlags type; + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) + type |= QVulkanInstance::GeneralMessage; + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) + type |= QVulkanInstance::ValidationMessage; + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + type |= QVulkanInstance::PerformanceMessage; + if (filter(severity, type, pCallbackData)) return VK_FALSE; } // not categorized, just route to plain old qDebug - qDebug("vkDebug: %s: %d: %s", pLayerPrefix, messageCode, pMessage); + qDebug("vkDebug: %s", pCallbackData->pMessage); return VK_FALSE; } +#endif void QBasicPlatformVulkanInstance::setupDebugOutput() { - if (!m_enabledExtensions.contains("VK_EXT_debug_report")) +#ifdef VK_EXT_debug_utils + if (!m_enabledExtensions.contains("VK_EXT_debug_utils")) return; - PFN_vkCreateDebugReportCallbackEXT createDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>( - m_vkGetInstanceProcAddr(m_vkInst, "vkCreateDebugReportCallbackEXT")); - m_vkDestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>( - m_vkGetInstanceProcAddr(m_vkInst, "vkDestroyDebugReportCallbackEXT")); - - VkDebugReportCallbackCreateInfoEXT dbgCallbackInfo; - memset(&dbgCallbackInfo, 0, sizeof(dbgCallbackInfo)); - dbgCallbackInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; - dbgCallbackInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT - | VK_DEBUG_REPORT_WARNING_BIT_EXT - | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; - dbgCallbackInfo.pfnCallback = defaultDebugCallbackFunc; - dbgCallbackInfo.pUserData = this; - - VkResult err = createDebugReportCallback(m_vkInst, &dbgCallbackInfo, nullptr, &m_debugCallback); + PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>( + m_vkGetInstanceProcAddr(m_vkInst, "vkCreateDebugUtilsMessengerEXT")); + + m_vkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>( + m_vkGetInstanceProcAddr(m_vkInst, "vkDestroyDebugUtilsMessengerEXT")); + + VkDebugUtilsMessengerCreateInfoEXT messengerInfo = {}; + messengerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + messengerInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + messengerInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + messengerInfo.pfnUserCallback = defaultDebugCallbackFunc; + messengerInfo.pUserData = this; + VkResult err = vkCreateDebugUtilsMessengerEXT(m_vkInst, &messengerInfo, nullptr, &m_debugMessenger); if (err != VK_SUCCESS) qWarning("Failed to create debug report callback: %d", err); +#endif } QT_END_NAMESPACE |