vulkan: Port to VK_EXT_debug_utils

Fixes: QTBUG-89762
Change-Id: Ie32043578968cbeda7c7f87990b98c10f5d06ff8
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Laszlo Agocs 2022-08-09 15:56:27 +02:00
parent 525a3f08e8
commit 595526e446
9 changed files with 291 additions and 112 deletions

View File

@ -300,7 +300,6 @@ QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
{
return {
QByteArrayLiteral("VK_KHR_swapchain"),
QByteArrayLiteral("VK_EXT_debug_marker"),
QByteArrayLiteral("VK_EXT_vertex_attribute_divisor")
};
}
@ -328,20 +327,19 @@ QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *im
}
}
static bool qvk_debug_filter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object,
size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage)
static bool qvk_debug_filter(QVulkanInstance::DebugMessageSeverityFlags severity,
QVulkanInstance::DebugMessageTypeFlags type,
const void *callbackData)
{
Q_UNUSED(flags);
Q_UNUSED(objectType);
Q_UNUSED(object);
Q_UNUSED(location);
Q_UNUSED(messageCode);
Q_UNUSED(pLayerPrefix);
Q_UNUSED(severity);
Q_UNUSED(type);
#ifdef VK_EXT_debug_utils
const VkDebugUtilsMessengerCallbackDataEXT *d = static_cast<const VkDebugUtilsMessengerCallbackDataEXT *>(callbackData);
// Filter out certain misleading validation layer messages, as per
// VulkanMemoryAllocator documentation.
if (strstr(pMessage, "Mapping an image with layout")
&& strstr(pMessage, "can result in undefined behavior if this memory is used by the device"))
if (strstr(d->pMessage, "Mapping an image with layout")
&& strstr(d->pMessage, "can result in undefined behavior if this memory is used by the device"))
{
return true;
}
@ -352,9 +350,11 @@ static bool qvk_debug_filter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTyp
// then move on to another pool. If there is a real error, a qWarning
// message is shown by allocateDescriptorSet(), so the validation warning
// does not have any value and is just noise.
if (strstr(pMessage, "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
if (strstr(d->pMessage, "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
return true;
#else
Q_UNUSED(callbackData);
#endif
return false;
}
@ -394,6 +394,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
for (const char *ext : inst->extensions())
qCDebug(QRHI_LOG_INFO, " %s", ext);
}
caps.debugUtils = inst->extensions().contains(QByteArrayLiteral("VK_EXT_debug_utils"));
QList<VkQueueFamilyProperties> queueFamilyProps;
auto queryQueueFamilyProps = [this, &queueFamilyProps] {
@ -551,12 +552,6 @@ bool QRhiVulkan::create(QRhi::Flags flags)
QList<const char *> requestedDevExts;
requestedDevExts.append("VK_KHR_swapchain");
caps.debugMarkers = false;
if (devExts.contains(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
caps.debugMarkers = true;
}
caps.vertexAttribDivisor = false;
if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) {
@ -770,12 +765,14 @@ bool QRhiVulkan::create(QRhi::Flags flags)
timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS); // 1 bit per pair
timestampQueryPoolMap.fill(false);
if (caps.debugMarkers) {
vkCmdDebugMarkerBegin = reinterpret_cast<PFN_vkCmdDebugMarkerBeginEXT>(f->vkGetDeviceProcAddr(dev, "vkCmdDebugMarkerBeginEXT"));
vkCmdDebugMarkerEnd = reinterpret_cast<PFN_vkCmdDebugMarkerEndEXT>(f->vkGetDeviceProcAddr(dev, "vkCmdDebugMarkerEndEXT"));
vkCmdDebugMarkerInsert = reinterpret_cast<PFN_vkCmdDebugMarkerInsertEXT>(f->vkGetDeviceProcAddr(dev, "vkCmdDebugMarkerInsertEXT"));
vkDebugMarkerSetObjectName = reinterpret_cast<PFN_vkDebugMarkerSetObjectNameEXT>(f->vkGetDeviceProcAddr(dev, "vkDebugMarkerSetObjectNameEXT"));
#ifdef VK_EXT_debug_utils
if (caps.debugUtils) {
vkSetDebugUtilsObjectNameEXT = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev, "vkSetDebugUtilsObjectNameEXT"));
vkCmdBeginDebugUtilsLabelEXT = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev, "vkCmdBeginDebugUtilsLabelEXT"));
vkCmdEndDebugUtilsLabelEXT = reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev, "vkCmdEndDebugUtilsLabelEXT"));
vkCmdInsertDebugUtilsLabelEXT = reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev, "vkCmdInsertDebugUtilsLabelEXT"));
}
#endif
deviceLost = false;
@ -3914,17 +3911,23 @@ void QRhiVulkan::recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
cmd.args.drawIndexed.firstInstance);
break;
case QVkCommandBuffer::Command::DebugMarkerBegin:
cmd.args.debugMarkerBegin.marker.pMarkerName =
cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.markerNameIndex].constData();
vkCmdDebugMarkerBegin(cbD->cb, &cmd.args.debugMarkerBegin.marker);
#ifdef VK_EXT_debug_utils
cmd.args.debugMarkerBegin.label.pLabelName =
cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
#endif
break;
case QVkCommandBuffer::Command::DebugMarkerEnd:
vkCmdDebugMarkerEnd(cbD->cb);
#ifdef VK_EXT_debug_utils
vkCmdEndDebugUtilsLabelEXT(cbD->cb);
#endif
break;
case QVkCommandBuffer::Command::DebugMarkerInsert:
cmd.args.debugMarkerInsert.marker.pMarkerName =
cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.markerNameIndex].constData();
vkCmdDebugMarkerInsert(cbD->cb, &cmd.args.debugMarkerInsert.marker);
#ifdef VK_EXT_debug_utils
cmd.args.debugMarkerInsert.label.pLabelName =
cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
#endif
break;
case QVkCommandBuffer::Command::TransitionPassResources:
recordTransitionPassResources(cbD, cbD->passResTrackers[cmd.args.transitionResources.trackerIndex]);
@ -4251,7 +4254,7 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
case QRhi::MultisampleRenderBuffer:
return true;
case QRhi::DebugMarkers:
return caps.debugMarkers;
return caps.debugUtils;
case QRhi::Timestamps:
return timestampValidBits != 0;
case QRhi::Instancing:
@ -5046,58 +5049,72 @@ void QRhiVulkan::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
void QRhiVulkan::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name)
{
if (!debugMarkers || !caps.debugMarkers)
#ifdef VK_EXT_debug_utils
if (!debugMarkers || !caps.debugUtils)
return;
VkDebugMarkerMarkerInfoEXT marker = {};
marker.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
VkDebugUtilsLabelEXT label = {};
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
marker.pMarkerName = name.constData();
vkCmdDebugMarkerBegin(cbD->activeSecondaryCbStack.last(), &marker);
label.pLabelName = name.constData();
vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
} else {
QVkCommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
cmd.args.debugMarkerBegin.marker = marker;
cmd.args.debugMarkerBegin.markerNameIndex = cbD->pools.debugMarkerData.count();
cmd.args.debugMarkerBegin.label = label;
cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.count();
cbD->pools.debugMarkerData.append(name);
}
#else
Q_UNUSED(cb);
Q_UNUSED(name);
#endif
}
void QRhiVulkan::debugMarkEnd(QRhiCommandBuffer *cb)
{
if (!debugMarkers || !caps.debugMarkers)
#ifdef VK_EXT_debug_utils
if (!debugMarkers || !caps.debugUtils)
return;
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
vkCmdDebugMarkerEnd(cbD->activeSecondaryCbStack.last());
vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
} else {
QVkCommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
}
#else
Q_UNUSED(cb);
#endif
}
void QRhiVulkan::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
{
if (!debugMarkers || !caps.debugMarkers)
#ifdef VK_EXT_debug_utils
if (!debugMarkers || !caps.debugUtils)
return;
VkDebugMarkerMarkerInfoEXT marker = {};
marker.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
VkDebugUtilsLabelEXT label = {};
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
marker.pMarkerName = msg.constData();
vkCmdDebugMarkerInsert(cbD->activeSecondaryCbStack.last(), &marker);
label.pLabelName = msg.constData();
vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
} else {
QVkCommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
cmd.args.debugMarkerInsert.marker = marker;
cmd.args.debugMarkerInsert.markerNameIndex = cbD->pools.debugMarkerData.count();
cmd.args.debugMarkerInsert.label = label;
cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.count();
cbD->pools.debugMarkerData.append(msg);
}
#else
Q_UNUSED(cb);
Q_UNUSED(msg);
#endif
}
const QRhiNativeHandles *QRhiVulkan::nativeHandles(QRhiCommandBuffer *cb)
@ -5178,22 +5195,29 @@ void QRhiVulkan::endExternal(QRhiCommandBuffer *cb)
cbD->resetCachedState();
}
void QRhiVulkan::setObjectName(uint64_t object, VkDebugReportObjectTypeEXT type, const QByteArray &name, int slot)
void QRhiVulkan::setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot)
{
if (!debugMarkers || !caps.debugMarkers || name.isEmpty())
#ifdef VK_EXT_debug_utils
if (!debugMarkers || !caps.debugUtils || name.isEmpty())
return;
VkDebugMarkerObjectNameInfoEXT nameInfo = {};
nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT;
VkDebugUtilsObjectNameInfoEXT nameInfo = {};
nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
nameInfo.objectType = type;
nameInfo.object = object;
nameInfo.objectHandle = object;
QByteArray decoratedName = name;
if (slot >= 0) {
decoratedName += '/';
decoratedName += QByteArray::number(slot);
}
nameInfo.pObjectName = decoratedName.constData();
vkDebugMarkerSetObjectName(dev, &nameInfo);
vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
#else
Q_UNUSED(object);
Q_UNUSED(type);
Q_UNUSED(name);
Q_UNUSED(slot);
#endif
}
static inline VkBufferUsageFlagBits toVkBufferUsage(QRhiBuffer::UsageFlags usage)
@ -5681,7 +5705,7 @@ bool QVkBuffer::create()
if (err != VK_SUCCESS)
break;
allocations[i] = allocation;
rhiD->setObjectName(uint64_t(buffers[i]), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, m_objectName,
rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
m_type == Dynamic ? i : -1);
}
}
@ -5831,7 +5855,7 @@ bool QVkRenderBuffer::create()
{
return false;
}
rhiD->setObjectName(uint64_t(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, m_objectName);
rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
break;
default:
Q_UNREACHABLE();
@ -6095,7 +6119,7 @@ bool QVkTexture::create()
if (!finishCreate())
return false;
rhiD->setObjectName(uint64_t(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, m_objectName);
rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
owns = true;
rhiD->registerResource(this);

View File

@ -499,14 +499,18 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
uint32_t firstInstance;
} drawIndexed;
struct {
VkDebugMarkerMarkerInfoEXT marker;
int markerNameIndex;
#ifdef VK_EXT_debug_utils
VkDebugUtilsLabelEXT label;
int labelNameIndex;
#endif
} debugMarkerBegin;
struct {
} debugMarkerEnd;
struct {
VkDebugMarkerMarkerInfoEXT marker;
int markerNameIndex;
#ifdef VK_EXT_debug_utils
VkDebugUtilsLabelEXT label;
int labelNameIndex;
#endif
} debugMarkerInsert;
struct {
int trackerIndex;
@ -795,7 +799,7 @@ public:
void executeDeferredReleases(bool forced = false);
void finishActiveReadbacks(bool forced = false);
void setObjectName(uint64_t object, VkDebugReportObjectTypeEXT type, const QByteArray &name, int slot = -1);
void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot = -1);
void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot,
VkAccessFlags access, VkPipelineStageFlags stage);
void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD,
@ -833,10 +837,12 @@ public:
bool deviceLost = false;
bool releaseCachedResourcesCalledBeforeFrameStart = false;
PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBegin = nullptr;
PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEnd = nullptr;
PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsert = nullptr;
PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectName = nullptr;
#ifdef VK_EXT_debug_utils
PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT = nullptr;
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT = nullptr;
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT = nullptr;
PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT = nullptr;
#endif
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
@ -850,7 +856,7 @@ public:
struct {
bool compute = false;
bool wideLines = false;
bool debugMarkers = false;
bool debugUtils = false;
bool vertexAttribDivisor = false;
bool texture3DSliceAs2D = false;
bool tessellation = false;

View File

@ -26,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)
{
}
@ -39,8 +34,10 @@ 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);
@ -208,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();
@ -221,7 +217,7 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const
}
if (!flags.testFlag(QVulkanInstance::NoDebugOutputRedirect))
m_enabledExtensions.append("VK_EXT_debug_report");
m_enabledExtensions.append("VK_EXT_debug_utils");
m_enabledExtensions.append("VK_KHR_surface");
@ -259,8 +255,7 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const
}
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;
@ -365,55 +360,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"));
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
m_vkGetInstanceProcAddr(m_vkInst, "vkCreateDebugUtilsMessengerEXT"));
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;
m_vkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
m_vkGetInstanceProcAddr(m_vkInst, "vkDestroyDebugUtilsMessengerEXT"));
VkResult err = createDebugReportCallback(m_vkInst, &dbgCallbackInfo, nullptr, &m_debugCallback);
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

View File

@ -40,17 +40,19 @@ public:
PFN_vkVoidFunction getInstanceProcAddr(const char *name) override;
bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override;
void setDebugFilters(const QList<QVulkanInstance::DebugFilter> &filters) override;
void setDebugUtilsFilters(const QList<QVulkanInstance::DebugUtilsFilter> &filters) override;
void destroySurface(VkSurfaceKHR surface) const;
const QList<QVulkanInstance::DebugFilter> *debugFilters() const { return &m_debugFilters; }
const QList<QVulkanInstance::DebugUtilsFilter> *debugUtilsFilters() const { return &m_debugUtilsFilters; }
protected:
void loadVulkanLibrary(const QString &defaultLibraryName, int defaultLibraryVersion = -1);
void init(QLibrary *lib);
void initInstance(QVulkanInstance *instance, const QByteArrayList &extraExts);
VkInstance m_vkInst;
PFN_vkGetInstanceProcAddr m_vkGetInstanceProcAddr;
VkInstance m_vkInst = VK_NULL_HANDLE;
PFN_vkGetInstanceProcAddr m_vkGetInstanceProcAddr = nullptr;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR m_getPhysDevSurfaceSupport;
PFN_vkDestroySurfaceKHR m_destroySurface;
@ -59,8 +61,8 @@ private:
std::unique_ptr<QLibrary> m_vulkanLib;
bool m_ownsVkInst;
VkResult m_errorCode;
bool m_ownsVkInst = false;
VkResult m_errorCode = VK_SUCCESS;
QVulkanInfoVector<QVulkanLayer> m_supportedLayers;
QVulkanInfoVector<QVulkanExtension> m_supportedExtensions;
QVersionNumber m_supportedApiVersion;
@ -73,9 +75,12 @@ private:
PFN_vkDestroyInstance m_vkDestroyInstance;
VkDebugReportCallbackEXT m_debugCallback;
PFN_vkDestroyDebugReportCallbackEXT m_vkDestroyDebugReportCallbackEXT;
#ifdef VK_EXT_debug_utils
VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE;
PFN_vkDestroyDebugUtilsMessengerEXT m_vkDestroyDebugUtilsMessengerEXT;
#endif
QList<QVulkanInstance::DebugFilter> m_debugFilters;
QList<QVulkanInstance::DebugUtilsFilter> m_debugUtilsFilters;
};
QT_END_NAMESPACE

View File

@ -59,4 +59,9 @@ void QPlatformVulkanInstance::setDebugFilters(const QList<QVulkanInstance::Debug
Q_UNUSED(filters);
}
void QPlatformVulkanInstance::setDebugUtilsFilters(const QList<QVulkanInstance::DebugUtilsFilter> &filters)
{
Q_UNUSED(filters);
}
QT_END_NAMESPACE

View File

@ -45,6 +45,7 @@ public:
virtual void presentAboutToBeQueued(QWindow *window);
virtual void presentQueued(QWindow *window);
virtual void setDebugFilters(const QList<QVulkanInstance::DebugFilter> &filters);
virtual void setDebugUtilsFilters(const QList<QVulkanInstance::DebugUtilsFilter> &filters);
private:
QScopedPointer<QPlatformVulkanInstancePrivate> d_ptr;

View File

@ -104,7 +104,7 @@ QT_BEGIN_NAMESPACE
\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
in question, and \c{VK_EXT_debug_utils} in case QVulkanInstance's debug
output redirection is desired.
\section1 Accessing Core Vulkan Commands
@ -205,7 +205,7 @@ QT_BEGIN_NAMESPACE
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.
\value NoDebugOutputRedirect Disables Vulkan debug output (\c{VK_EXT_debug_utils}) redirection to qDebug.
*/
bool QVulkanInstancePrivate::ensureVulkan()
@ -425,7 +425,7 @@ QVersionNumber QVulkanInstance::supportedApiVersion() const
\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
debug output redirection is functional, \c{VK_EXT_debug_utils} is needed as
well.
\note This function can only be called before create() and has no effect if
@ -812,10 +812,21 @@ void QVulkanInstance::presentQueued(QWindow *window)
Typedef for debug filtering callback functions.
Returning \c true suppresses the printing of the message.
\note Starting with Qt 6.5 \c{VK_EXT_debug_utils} is used instead of the
deprecated \c{VK_EXT_debug_report}. The callback signature is based on
VK_EXT_debug_report. Therefore, not all arguments can be expected to be
valid anymore. Avoid relying on arguments other than \c pMessage, \c
messageCode, and \c object. Applications wishing to access all the callback
data as specified in VK_EXT_debug_utils should migrate to DebugUtilsFilter.
\sa installDebugOutputFilter(), removeDebugOutputFilter()
*/
/*!
\overload
Installs a \a filter function that is called for every Vulkan debug
message. When the callback returns \c true, the message is stopped (filtered
out) and will not appear on the debug output.
@ -837,6 +848,8 @@ void QVulkanInstance::installDebugOutputFilter(DebugFilter filter)
}
/*!
\overload
Removes a \a filter function previously installed by
installDebugOutputFilter().
@ -851,6 +864,76 @@ void QVulkanInstance::removeDebugOutputFilter(DebugFilter filter)
d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
}
/*!
\typedef QVulkanInstance::DebugUtilsFilter
Typedef for debug filtering callback functions. The \c callbackData
argument is a pointer to the VkDebugUtilsMessengerCallbackDataEXT
structure.
Returning \c true suppresses the printing of the message.
\sa installDebugOutputFilter(), removeDebugOutputFilter()
\since 6.5
*/
/*!
\enum QVulkanInstance::DebugMessageSeverityFlag
\since 6.5
\value VerboseSeverity
\value InfoSeverity
\value WarningSeverity
\value ErrorSeverity
*/
/*!
\enum QVulkanInstance::DebugMessageTypeFlag
\since 6.5
\value GeneralMessage
\value ValidationMessage
\value PerformanceMessage
*/
/*!
Installs a \a filter function that is called for every Vulkan debug
message. When the callback returns \c true, the message is stopped (filtered
out) and will not appear on the debug output.
\note Filtering is only effective when NoDebugOutputRedirect is not
\l{setFlags()}{set}. Installing filters has no effect otherwise.
\note This function can be called before create().
\sa removeDebugOutputFilter()
\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);
}
}
/*!
Removes a \a filter function previously installed by
installDebugOutputFilter().
\note This function can be called before create().
\sa installDebugOutputFilter()
\since 6.5
*/
void QVulkanInstance::removeDebugOutputFilter(DebugUtilsFilter filter)
{
d_ptr->debugUtilsFilters.removeOne(filter);
if (d_ptr->platformInst)
d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QVulkanLayer &layer)
{

View File

@ -187,6 +187,25 @@ public:
void installDebugOutputFilter(DebugFilter filter);
void removeDebugOutputFilter(DebugFilter filter);
enum DebugMessageSeverityFlag {
VerboseSeverity = 0x01,
InfoSeverity = 0x02,
WarningSeverity = 0x04,
ErrorSeverity = 0x08
};
Q_DECLARE_FLAGS(DebugMessageSeverityFlags, DebugMessageSeverityFlag)
enum DebugMessageTypeFlag {
GeneralMessage = 0x01,
ValidationMessage = 0x02,
PerformanceMessage = 0x04
};
Q_DECLARE_FLAGS(DebugMessageTypeFlags, DebugMessageTypeFlag)
typedef bool (*DebugUtilsFilter)(DebugMessageSeverityFlags severity, DebugMessageTypeFlags type, const void *callbackData);
void installDebugOutputFilter(DebugUtilsFilter filter);
void removeDebugOutputFilter(DebugUtilsFilter filter);
private:
friend class QVulkanInstancePrivate;
QScopedPointer<QVulkanInstancePrivate> d_ptr;
@ -194,6 +213,8 @@ private:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QVulkanInstance::Flags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QVulkanInstance::DebugMessageTypeFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QVulkanInstance::DebugMessageSeverityFlags)
QT_END_NAMESPACE

View File

@ -49,7 +49,8 @@ public:
VkResult errorCode;
QScopedPointer<QVulkanFunctions> funcs;
QHash<VkDevice, QVulkanDeviceFunctions *> deviceFuncs;
QList<QVulkanInstance::DebugFilter> debugFilters;
QList<QVulkanInstance::DebugFilter> debugFilters; // legacy filters based on VK_EXT_debug_report
QList<QVulkanInstance::DebugUtilsFilter> debugUtilsFilters; // the modern version based on VK_EXT_debug_utils
};
QT_END_NAMESPACE