summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAurĂ©lien Brooke <[email protected]>2025-03-29 08:56:22 +0100
committerAurĂ©lien Brooke <[email protected]>2025-05-30 12:23:09 +0200
commit433360c6cd4b7fc4c7ce7ca9c879e0cb024a69d5 (patch)
treebbb028f047f6000bd3015b271c47d0f7d7447771
parent70e75851bfc05ff9cd9bdf6689da745ea4eb619e (diff)
rhi: vulkan: make it easier to hunt VMA leaksHEADdev
When leaking a RHI resource, the VMA asserts (VMA_ASSERT_LEAK) before the RHI has a chance to list the leaks. Plug the VMA leak output to the QDebug infrastructure, and give names to the VmaAllocations so that we know exactly what leaked. This is only enabled for debug builds or when QT_RHI_LEAK_CHECK is set. Change-Id: Ief0e46cceaefb2e736542f9764264c29b0c28c64 Reviewed-by: Laszlo Agocs <[email protected]>
-rw-r--r--src/gui/rhi/qrhivulkan.cpp39
-rw-r--r--src/gui/rhi/qrhivulkan_p.h1
2 files changed, 40 insertions, 0 deletions
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index 6353d2afc12..e5ac6097a3d 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -9,9 +9,29 @@
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_RECORDING_ENABLED 0
#define VMA_DEDICATED_ALLOCATION 0
+QT_BEGIN_NAMESPACE
+Q_STATIC_LOGGING_CATEGORY(QRHI_LOG_VMA, "qt.rhi.vma")
+QT_END_NAMESPACE
+#define VMA_ASSERT(expr) Q_ASSERT(expr)
#ifdef QT_DEBUG
#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1
+#define VMA_DEBUG_LOG(str) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), (str))
+#define VMA_DEBUG_LOG_FORMAT(format, ...) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, __VA_ARGS__)
+#endif
+template<typename... Args>
+static void debugVmaLeak(const char *format, Args&&... args)
+{
+#ifndef QT_NO_DEBUG
+ // debug builds: just do it always
+ static bool leakCheck = true;
+#else
+ // release builds: opt-in
+ static bool leakCheck = QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)("QT_RHI_LEAK_CHECK");
#endif
+ if (leakCheck)
+ QT_PREPEND_NAMESPACE(qWarning)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, std::forward<Args>(args)...);
+}
+#define VMA_LEAK_LOG_FORMAT(format, ...) debugVmaLeak(format, __VA_ARGS__)
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wsuggest-override")
QT_WARNING_DISABLE_GCC("-Wundef")
@@ -4075,6 +4095,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
&bufD->stagingBuffers[currentFrameSlot], &allocation, nullptr);
if (err == VK_SUCCESS) {
bufD->stagingAllocations[currentFrameSlot] = allocation;
+ setAllocationName(allocation, bufD->name());
} else {
qWarning("Failed to create staging buffer of size %u: %d", bufD->m_size, err);
printExtraErrorInfo(err);
@@ -4161,6 +4182,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation, nullptr);
if (err == VK_SUCCESS) {
readback.stagingAlloc = allocation;
+ setAllocationName(allocation, bufD->name());
} else {
qWarning("Failed to create readback buffer of size %u: %d", readback.byteSize, err);
printExtraErrorInfo(err);
@@ -4217,6 +4239,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
continue;
}
utexD->stagingAllocations[currentFrameSlot] = allocation;
+ setAllocationName(allocation, utexD->name());
BufferImageCopyList copyInfos;
size_t curOfs = 0;
@@ -4374,6 +4397,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation, nullptr);
if (err == VK_SUCCESS) {
readback.stagingAlloc = allocation;
+ setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
} else {
qWarning("Failed to create readback buffer of size %u: %d", readback.byteSize, err);
printExtraErrorInfo(err);
@@ -6284,6 +6308,19 @@ double QRhiVulkan::lastCompletedGpuTime(QRhiCommandBuffer *cb)
return cbD->lastGpuTime;
}
+void QRhiVulkan::setAllocationName(QVkAlloc allocation, const QByteArray &name, int slot)
+{
+ if (!debugMarkers || name.isEmpty())
+ return;
+
+ QByteArray decoratedName = name;
+ if (slot >= 0) {
+ decoratedName += '/';
+ decoratedName += QByteArray::number(slot);
+ }
+ vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
+}
+
void QRhiVulkan::setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot)
{
#ifdef VK_EXT_debug_utils
@@ -6803,6 +6840,7 @@ bool QVkBuffer::create()
if (err != VK_SUCCESS)
break;
allocations[i] = allocation;
+ rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
m_type == Dynamic ? i : -1);
}
@@ -7250,6 +7288,7 @@ bool QVkTexture::create()
return false;
}
imageAlloc = allocation;
+ rhiD->setAllocationName(allocation, m_objectName);
if (!finishCreate())
return false;
diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h
index 15e866b7c63..2d812a9d5f0 100644
--- a/src/gui/rhi/qrhivulkan_p.h
+++ b/src/gui/rhi/qrhivulkan_p.h
@@ -857,6 +857,7 @@ public:
void executeDeferredReleases(bool forced = false);
void finishActiveReadbacks(bool forced = false);
+ void setAllocationName(QVkAlloc allocation, 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);