From 2230bd76a47de8253a1faaaa6d2dc9b6564425fa Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 6 Nov 2024 12:02:24 +0100 Subject: [PATCH 01/21] [dxvk] Add convenience methods to check for debug utils support --- src/d3d11/d3d11_annotation.cpp | 2 +- src/d3d9/d3d9_device.cpp | 2 +- src/dxvk/dxvk_device.h | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/d3d11/d3d11_annotation.cpp b/src/d3d11/d3d11_annotation.cpp index b7c1fdf7766..4e02c599020 100644 --- a/src/d3d11/d3d11_annotation.cpp +++ b/src/d3d11/d3d11_annotation.cpp @@ -38,7 +38,7 @@ namespace dxvk { ContextType* container, const Rc& dxvkDevice) : m_container(container), m_eventDepth(0), - m_annotationsEnabled(dxvkDevice->instance()->extensions().extDebugUtils) { + m_annotationsEnabled(dxvkDevice->isDebugEnabled()) { if (!IsDeferred && m_annotationsEnabled) RegisterUserDefinedAnnotation(this); } diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 56150dc8cbc..ace712f8ea9 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -70,7 +70,7 @@ namespace dxvk { if (canSWVP) Logger::info("D3D9DeviceEx: Using extended constant set for software vertex processing."); - if (m_dxvkDevice->instance()->extensions().extDebugUtils) + if (m_dxvkDevice->isDebugEnabled()) m_annotation = new D3D9UserDefinedAnnotation(this); m_initializer = new D3D9Initializer(this); diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index a3a2b2b2900..219655fa989 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -92,6 +92,14 @@ namespace dxvk { return m_vkd; } + /** + * \brief Vulkan instance functions + * \returns Vulkan instance functions + */ + Rc vki() const { + return m_instance->vki(); + } + /** * \brief Logical device handle * \returns The device handle @@ -100,6 +108,14 @@ namespace dxvk { return m_vkd->device(); } + /** + * \brief Checks whether debug functionality is enabled + * \returns \c true if debug utils are enabled + */ + bool isDebugEnabled() const { + return bool(m_instance->extensions().extDebugUtils); + } + /** * \brief Device options * \returns Device options From a8791fdd6a49552974687f9bebdeb01768b547c3 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 6 Nov 2024 11:07:47 +0100 Subject: [PATCH 02/21] [dxvk] Add command buffer parameter to debug label functions --- src/dxvk/dxvk_cmdlist.h | 15 +++++++++------ src/dxvk/dxvk_context.cpp | 22 +++++++++------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 96f82681328..53b44f0ee99 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -1048,25 +1048,28 @@ namespace dxvk { void cmdBeginDebugUtilsLabel( - VkDebugUtilsLabelEXT* pLabelInfo) { + DxvkCmdBuffer cmdBuffer, + const VkDebugUtilsLabelEXT& labelInfo) { m_cmd.execCommands = true; - m_vki->vkCmdBeginDebugUtilsLabelEXT(getCmdBuffer(), pLabelInfo); + m_vki->vkCmdBeginDebugUtilsLabelEXT(getCmdBuffer(cmdBuffer), &labelInfo); } - void cmdEndDebugUtilsLabel() { + void cmdEndDebugUtilsLabel( + DxvkCmdBuffer cmdBuffer) { m_cmd.execCommands = true; - m_vki->vkCmdEndDebugUtilsLabelEXT(getCmdBuffer()); + m_vki->vkCmdEndDebugUtilsLabelEXT(getCmdBuffer(cmdBuffer)); } void cmdInsertDebugUtilsLabel( - VkDebugUtilsLabelEXT* pLabelInfo) { + DxvkCmdBuffer cmdBuffer, + const VkDebugUtilsLabelEXT& labelInfo) { m_cmd.execCommands = true; - m_vki->vkCmdInsertDebugUtilsLabelEXT(getCmdBuffer(), pLabelInfo); + m_vki->vkCmdInsertDebugUtilsLabelEXT(getCmdBuffer(cmdBuffer), &labelInfo); } diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 4523be3830d..9dc614b0ec3 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2477,25 +2477,21 @@ namespace dxvk { } - void DxvkContext::beginDebugLabel(VkDebugUtilsLabelEXT *label) { - if (!m_device->instance()->extensions().extDebugUtils) - return; - - m_cmd->cmdBeginDebugUtilsLabel(label); + void DxvkContext::beginDebugLabel(VkDebugUtilsLabelEXT* label) { + if (m_device->isDebugEnabled()) + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, *label); } - void DxvkContext::endDebugLabel() { - if (!m_device->instance()->extensions().extDebugUtils) - return; - m_cmd->cmdEndDebugUtilsLabel(); + void DxvkContext::endDebugLabel() { + if (m_device->isDebugEnabled()) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); } - void DxvkContext::insertDebugLabel(VkDebugUtilsLabelEXT *label) { - if (!m_device->instance()->extensions().extDebugUtils) - return; - m_cmd->cmdInsertDebugUtilsLabel(label); + void DxvkContext::insertDebugLabel(VkDebugUtilsLabelEXT* label) { + if (m_device->isDebugEnabled()) + m_cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, *label); } From 2aa932d48ad69f7a4fdd810684725d9145963f44 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 7 Jan 2025 14:10:23 +0100 Subject: [PATCH 03/21] [dxvk] Add support for resource debug names --- src/dxvk/dxvk_buffer.cpp | 38 ++++++++++++++++++++++++- src/dxvk/dxvk_buffer.h | 18 ++++++++++++ src/dxvk/dxvk_context.cpp | 8 ++++++ src/dxvk/dxvk_context.h | 8 ++++++ src/dxvk/dxvk_image.cpp | 39 +++++++++++++++++++++++++ src/dxvk/dxvk_image.h | 15 ++++++++++ src/dxvk/dxvk_memory.cpp | 60 ++++++++++++++++++++++----------------- src/dxvk/dxvk_sparse.h | 12 ++++++++ src/vulkan/vulkan_util.h | 16 +++++++++++ 9 files changed, 187 insertions(+), 27 deletions(-) diff --git a/src/dxvk/dxvk_buffer.cpp b/src/dxvk/dxvk_buffer.cpp index 1f71da96118..364d7a59c5a 100644 --- a/src/dxvk/dxvk_buffer.cpp +++ b/src/dxvk/dxvk_buffer.cpp @@ -19,6 +19,14 @@ namespace dxvk { m_info (createInfo) { m_allocator->registerResource(this); + // Assign debug name to buffer + if (device->isDebugEnabled()) { + m_debugName = createDebugName(createInfo.debugName); + m_info.debugName = m_debugName.c_str(); + } else { + m_info.debugName = nullptr; + } + // Create and assign actual buffer resource assignStorage(allocateStorage()); } @@ -99,5 +107,33 @@ namespace dxvk { return m_allocator->createBufferResource(info, allocationInfo, nullptr); } - + + + void DxvkBuffer::setDebugName(const char* name) { + if (likely(!m_info.debugName)) + return; + + m_debugName = createDebugName(name); + m_info.debugName = m_debugName.c_str(); + + updateDebugName(); + } + + + void DxvkBuffer::updateDebugName() { + if (m_storage->flags().test(DxvkAllocationFlag::OwnsBuffer)) { + VkDebugUtilsObjectNameInfoEXT nameInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT }; + nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; + nameInfo.objectHandle = vk::getObjectHandle(m_bufferInfo.buffer); + nameInfo.pObjectName = m_info.debugName; + + m_vkd->vkSetDebugUtilsObjectNameEXT(m_vkd->device(), &nameInfo); + } + } + + + std::string DxvkBuffer::createDebugName(const char* name) const { + return str::format(vk::isValidDebugName(name) ? name : "Buffer", " (", cookie(), ")"); + } + } diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index c287b89cc37..4ea76fca67c 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -35,6 +35,9 @@ namespace dxvk { /// Buffer create flags VkBufferCreateFlags flags = 0; + + /// Debug name. + const char* debugName = nullptr; }; @@ -341,6 +344,9 @@ namespace dxvk { m_storage = std::move(slice); m_bufferInfo = m_storage->getBufferInfo(); + if (unlikely(m_info.debugName)) + updateDebugName(); + // Implicitly invalidate views m_version += 1u; return result; @@ -406,6 +412,12 @@ namespace dxvk { Rc relocateStorage( DxvkAllocationModes mode); + /** + * \brief Sets debug name for the backing resource + * \param [in] name New debug name + */ + void setDebugName(const char* name); + private: Rc m_vkd; @@ -429,6 +441,12 @@ namespace dxvk { std::unordered_map m_views; + std::string m_debugName; + + void updateDebugName(); + + std::string createDebugName(const char* name) const; + }; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 9dc614b0ec3..83b0eb4a0f6 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2493,6 +2493,14 @@ namespace dxvk { if (m_device->isDebugEnabled()) m_cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, *label); } + + + void DxvkContext::setDebugName(const Rc& resource, const char* name) { + if (!m_device->isDebugEnabled()) + return; + + resource->setDebugName(name); + } void DxvkContext::blitImageFb( diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index c08e9bf196e..4c904aec495 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1365,6 +1365,14 @@ namespace dxvk { m_cmd->addStatCtr(counter, value); } + /** + * \brief Sets new debug name for a resource + * + * \param [in] buffer Buffer object + * \param [in] name New debug name, or \c nullptr + */ + void setDebugName(const Rc& resource, const char* name); + private: Rc m_device; diff --git a/src/dxvk/dxvk_image.cpp b/src/dxvk/dxvk_image.cpp index bc25c49be30..da216ccf7ac 100644 --- a/src/dxvk/dxvk_image.cpp +++ b/src/dxvk/dxvk_image.cpp @@ -18,6 +18,14 @@ namespace dxvk { copyFormatList(createInfo.viewFormatCount, createInfo.viewFormats); + // Assign debug name to image + if (device->isDebugEnabled()) { + m_debugName = createDebugName(createInfo.debugName); + m_info.debugName = m_debugName.c_str(); + } else { + m_info.debugName = nullptr; + } + // Always enable depth-stencil attachment usage for depth-stencil // formats since some internal operations rely on it. Read-only // versions of these make little sense to begin with. @@ -228,6 +236,9 @@ namespace dxvk { m_info.viewFormats = m_viewFormats.data(); } + if (unlikely(m_info.debugName)) + updateDebugName(); + m_stableAddress |= usageInfo.stableGpuAddress; return old; } @@ -283,6 +294,34 @@ namespace dxvk { } + void DxvkImage::setDebugName(const char* name) { + if (likely(!m_info.debugName)) + return; + + m_debugName = createDebugName(name); + m_info.debugName = m_debugName.c_str(); + + updateDebugName(); + } + + + void DxvkImage::updateDebugName() { + if (m_storage->flags().test(DxvkAllocationFlag::OwnsImage)) { + VkDebugUtilsObjectNameInfoEXT nameInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT }; + nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; + nameInfo.objectHandle = vk::getObjectHandle(m_imageInfo.image); + nameInfo.pObjectName = m_info.debugName; + + m_vkd->vkSetDebugUtilsObjectNameEXT(m_vkd->device(), &nameInfo); + } + } + + + std::string DxvkImage::createDebugName(const char* name) const { + return str::format(vk::isValidDebugName(name) ? name : "Image", " (", cookie(), ")"); + } + + VkImageCreateInfo DxvkImage::getImageCreateInfo( const DxvkImageUsageInfo& usageInfo) const { VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index f98184370ea..8647baa199f 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -66,6 +66,9 @@ namespace dxvk { // Shared handle info DxvkSharedHandleInfo sharing = { }; + + // Debug name + const char* debugName = nullptr; }; @@ -601,6 +604,12 @@ namespace dxvk { bool isInitialized( const VkImageSubresourceRange& subresources) const; + /** + * \brief Sets debug name for the backing resource + * \param [in] name New debug name + */ + void setDebugName(const char* name); + private: Rc m_vkd; @@ -626,6 +635,12 @@ namespace dxvk { std::unordered_map m_views; + std::string m_debugName; + + void updateDebugName(); + + std::string createDebugName(const char* name) const; + VkImageCreateInfo getImageCreateInfo( const DxvkImageUsageInfo& usageInfo) const; diff --git a/src/dxvk/dxvk_memory.cpp b/src/dxvk/dxvk_memory.cpp index 1cc27645eb2..3e0e1e4131c 100644 --- a/src/dxvk/dxvk_memory.cpp +++ b/src/dxvk/dxvk_memory.cpp @@ -752,6 +752,8 @@ namespace dxvk { memoryRequirements.memoryTypeBits = findGlobalBufferMemoryTypeMask(createInfo.usage); if (likely(memoryRequirements.memoryTypeBits)) { + bool allowSuballocation = true; + // If the given allocation cache supports the memory types and usage // flags that we need, try to use it to service this allocation. // Only use the allocation cache for mappable allocations since those @@ -769,44 +771,50 @@ namespace dxvk { // for any relevant memory pools as necessary. if (refillAllocationCache(allocationCache, memoryRequirements, allocationInfo.properties)) return allocationCache->allocateFromCache(createInfo.size); + } else { + // Do not suballocate buffers if debug mode is enabled in order + // to allow the application to set meaningful debug names. + allowSuballocation = !m_device->isDebugEnabled(); } // If there is at least one memory type that supports the required // buffer usage flags and requested memory properties, suballocate // from a global buffer. - allocation = allocateMemory(memoryRequirements, allocationInfo); - - if (likely(allocation && allocation->m_buffer)) - return allocation; - - if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) - && !allocationInfo.mode.test(DxvkAllocationMode::NoFallback)) { - DxvkAllocationInfo fallbackInfo = allocationInfo; - fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - allocation = allocateMemory(memoryRequirements, fallbackInfo); + if (likely(allowSuballocation)) { + allocation = allocateMemory(memoryRequirements, allocationInfo); if (likely(allocation && allocation->m_buffer)) return allocation; - } - // If we can't get an allocation for a global buffer, there's no - // real point in retrying with a dedicated buffer since the result - // will most likely be the same. - if (!allocation) { - if (allocationInfo.mode.isClear()) { - logMemoryError(memoryRequirements); - logMemoryStats(); + if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + && !allocationInfo.mode.test(DxvkAllocationMode::NoFallback)) { + DxvkAllocationInfo fallbackInfo = allocationInfo; + fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + allocation = allocateMemory(memoryRequirements, fallbackInfo); + + if (likely(allocation && allocation->m_buffer)) + return allocation; } - return nullptr; - } + // If we can't get an allocation for a global buffer, there's no + // real point in retrying with a dedicated buffer since the result + // will most likely be the same. + if (!allocation) { + if (allocationInfo.mode.isClear()) { + logMemoryError(memoryRequirements); + logMemoryStats(); + } + + return nullptr; + } - // If we end up here with an allocation but no buffer, something - // is weird, but we can keep the allocation around for now. - if (!allocation->m_buffer) { - Logger::err(str::format("Got allocation from memory type ", - allocation->m_type->index, " without global buffer")); + // If we end up here with an allocation but no buffer, something + // is weird, but we can keep the allocation around for now. + if (!allocation->m_buffer) { + Logger::err(str::format("Got allocation from memory type ", + allocation->m_type->index, " without global buffer")); + } } } } diff --git a/src/dxvk/dxvk_sparse.h b/src/dxvk/dxvk_sparse.h index a6efd031f2d..7eb9385a938 100644 --- a/src/dxvk/dxvk_sparse.h +++ b/src/dxvk/dxvk_sparse.h @@ -604,6 +604,18 @@ namespace dxvk { virtual Rc relocateStorage( DxvkAllocationModes mode) = 0; + /** + * \brief Sets debug name for the backing resource + * + * The caller \e must ensure that the backing resource + * is not being swapped out at the same time. This may + * also be ignored for certain types of resources for + * performance reasons, and has no effect if the device + * does not have debug layers enabled. + * \param [in] name New debug name + */ + virtual void setDebugName(const char* name) = 0; + private: std::atomic m_useCount = { 0u }; diff --git a/src/vulkan/vulkan_util.h b/src/vulkan/vulkan_util.h index 2dd1de987c7..c9ebf695435 100644 --- a/src/vulkan/vulkan_util.h +++ b/src/vulkan/vulkan_util.h @@ -211,6 +211,22 @@ namespace dxvk::vk { } } + + inline uint64_t getObjectHandle(uint64_t handle) { + return handle; + } + + + template + uint64_t getObjectHandle(T* object) { + return reinterpret_cast(object); + } + + + inline bool isValidDebugName(const char* name) { + return name && name[0]; + } + } From 37ac1e700c5f2ae4400f4cdb7c7e92aef0521889 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 7 Jan 2025 15:09:33 +0100 Subject: [PATCH 04/21] [hud] Set debug names for HUD resources --- src/dxvk/hud/dxvk_hud_item.cpp | 2 ++ src/dxvk/hud/dxvk_hud_renderer.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/dxvk/hud/dxvk_hud_item.cpp b/src/dxvk/hud/dxvk_hud_item.cpp index 8ceee1ebce7..bccc94644fc 100644 --- a/src/dxvk/hud/dxvk_hud_item.cpp +++ b/src/dxvk/hud/dxvk_hud_item.cpp @@ -445,6 +445,7 @@ namespace dxvk::hud { | VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + bufferInfo.debugName = "HUD frame time data"; m_gpuBuffer = m_device->createBuffer(bufferInfo, VK_MEMORY_HEAP_DEVICE_LOCAL_BIT); @@ -1203,6 +1204,7 @@ namespace dxvk::hud { bufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; bufferInfo.access = VK_ACCESS_SHADER_READ_BIT; bufferInfo.stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + bufferInfo.debugName = "HUD memory data"; m_dataBuffer = m_device->createBuffer(bufferInfo, VK_MEMORY_HEAP_DEVICE_LOCAL_BIT | diff --git a/src/dxvk/hud/dxvk_hud_renderer.cpp b/src/dxvk/hud/dxvk_hud_renderer.cpp index f712316c498..4ac05c94878 100644 --- a/src/dxvk/hud/dxvk_hud_renderer.cpp +++ b/src/dxvk/hud/dxvk_hud_renderer.cpp @@ -140,6 +140,7 @@ namespace dxvk::hud { | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; textBufferInfo.access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + textBufferInfo.debugName = "HUD text buffer"; m_textBuffer = m_device->createBuffer(textBufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | @@ -327,6 +328,7 @@ namespace dxvk::hud { fontBufferInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT; + fontBufferInfo.debugName = "HUD font metadata"; m_fontBuffer = m_device->createBuffer(fontBufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); @@ -348,6 +350,7 @@ namespace dxvk::hud { fontTextureInfo.tiling = VK_IMAGE_TILING_OPTIMAL; fontTextureInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; fontTextureInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + fontTextureInfo.debugName = "HUD font texture"; m_fontTexture = m_device->createImage(fontTextureInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); From 792b9d085a89a6dddad2a33c733d349155d1a0ce Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 7 Jan 2025 15:10:44 +0100 Subject: [PATCH 05/21] [dxvk] Set debug names for swap chain blitter resources --- src/dxvk/dxvk_swapchain_blitter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dxvk/dxvk_swapchain_blitter.cpp b/src/dxvk/dxvk_swapchain_blitter.cpp index 6f991fa6abb..a2c5e91c89c 100644 --- a/src/dxvk/dxvk_swapchain_blitter.cpp +++ b/src/dxvk/dxvk_swapchain_blitter.cpp @@ -212,6 +212,7 @@ namespace dxvk { | VK_ACCESS_SHADER_READ_BIT; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.debugName = "Swapchain cursor"; m_cursorImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); @@ -367,6 +368,7 @@ namespace dxvk { imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.debugName = "Swapchain gamma ramp"; m_gammaImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); From 566aea1e110d7500c31b4660dd2342f794b0fca5 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 15:14:47 +0100 Subject: [PATCH 06/21] [dxvk] Set debug names for internal buffers --- src/dxvk/dxvk_context.cpp | 5 +++++ src/dxvk/dxvk_staging.cpp | 1 + src/dxvk/dxvk_unbound.cpp | 1 + 3 files changed, 7 insertions(+) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 83b0eb4a0f6..0c8f28111d8 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -456,6 +456,7 @@ namespace dxvk { bufInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT; bufInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; + bufInfo.debugName = "Temp buffer"; auto tmpBuffer = m_device->createBuffer( bufInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); @@ -567,6 +568,7 @@ namespace dxvk { | VK_ACCESS_TRANSFER_READ_BIT; imgInfo.tiling = dstImage->info().tiling; imgInfo.layout = VK_IMAGE_LAYOUT_GENERAL; + imgInfo.debugName = "Temp image"; auto tmpImage = m_device->createImage( imgInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); @@ -679,6 +681,8 @@ namespace dxvk { | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; bufferInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; + bufferInfo.debugName = "Temp buffer"; + Rc tmpBuffer = m_device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); auto tmpBufferSlice = tmpBuffer->getSliceHandle(); @@ -6615,6 +6619,7 @@ namespace dxvk { bufInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT; bufInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; + bufInfo.debugName = "Zero buffer"; m_zeroBuffer = m_device->createBuffer(bufInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); diff --git a/src/dxvk/dxvk_staging.cpp b/src/dxvk/dxvk_staging.cpp index dd16becd604..1047ab75639 100644 --- a/src/dxvk/dxvk_staging.cpp +++ b/src/dxvk/dxvk_staging.cpp @@ -27,6 +27,7 @@ namespace dxvk { | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; info.access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT; + info.debugName = "Staging buffer"; VkDeviceSize alignedSize = dxvk::align(size, 256u); m_allocationCounter += alignedSize; diff --git a/src/dxvk/dxvk_unbound.cpp b/src/dxvk/dxvk_unbound.cpp index eed31c0172e..63e3f4d566f 100644 --- a/src/dxvk/dxvk_unbound.cpp +++ b/src/dxvk/dxvk_unbound.cpp @@ -83,6 +83,7 @@ namespace dxvk { info.access = VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + info.debugName = "Null buffer"; Rc buffer = m_device->createBuffer(info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | From 611f1d5455e3e6588894e1c41abf67c244f280e7 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 17:30:17 +0100 Subject: [PATCH 07/21] [dxvk] Set debug names for memory allocations Makes it easier to work out what is allocated where. --- src/dxvk/dxvk_memory.cpp | 47 ++++++++++++++++++++++++++++++++++++++-- src/dxvk/dxvk_memory.h | 11 ++++++---- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/dxvk/dxvk_memory.cpp b/src/dxvk/dxvk_memory.cpp index 3e0e1e4131c..c58cfcd4e3d 100644 --- a/src/dxvk/dxvk_memory.cpp +++ b/src/dxvk/dxvk_memory.cpp @@ -1217,11 +1217,55 @@ namespace dxvk { } } + result.cookie = ++m_nextCookie; + + if (unlikely(m_device->isDebugEnabled())) + assignMemoryDebugName(result, type); + type.stats.memoryAllocated += size; return result; } + void DxvkMemoryAllocator::assignMemoryDebugName( + const DxvkDeviceMemory& memory, + const DxvkMemoryType& type) { + auto vk = m_device->vkd(); + + const char* memoryType = "Unspecified memory"; + + if (type.properties.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { + if (type.properties.propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) + memoryType = "Cached system memory"; + else if (type.properties.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + memoryType = "Mapped video memory"; + else + memoryType = "Write-combined system memory"; + } else if (type.properties.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + memoryType = "Video memory"; + } + + std::string memoryName = str::format(memoryType, " (", memory.cookie, ")"); + + VkDebugUtilsObjectNameInfoEXT nameInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT }; + nameInfo.objectType = VK_OBJECT_TYPE_DEVICE_MEMORY; + nameInfo.objectHandle = vk::getObjectHandle(memory.memory); + nameInfo.pObjectName = memoryName.c_str(); + + vk->vkSetDebugUtilsObjectNameEXT(vk->device(), &nameInfo); + + if (memory.buffer) { + std::string bufferName = str::format("Global buffer (", memory.cookie, ")"); + + nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; + nameInfo.objectHandle = vk::getObjectHandle(memory.buffer); + nameInfo.pObjectName = bufferName.c_str(); + + vk->vkSetDebugUtilsObjectNameEXT(vk->device(), &nameInfo); + } + } + + bool DxvkMemoryAllocator::allocateChunkInPool( DxvkMemoryType& type, DxvkMemoryPool& pool, @@ -1255,7 +1299,6 @@ namespace dxvk { pool.chunks.resize(std::max(pool.chunks.size(), chunkIndex + 1u)); pool.chunks[chunkIndex].memory = chunk; pool.chunks[chunkIndex].unusedTime = high_resolution_clock::time_point(); - pool.chunks[chunkIndex].chunkCookie = ++pool.nextChunkCookie; pool.chunks[chunkIndex].canMove = true; return true; } @@ -1687,7 +1730,7 @@ namespace dxvk { chunkStats.pageCount = pool.pageAllocator.pageCount(i); chunkStats.mapped = &pool == &type.mappedPool; chunkStats.active = pool.pageAllocator.chunkIsAvailable(i); - chunkStats.cookie = pool.chunks[i].chunkCookie; + chunkStats.cookie = pool.chunks[i].memory.cookie; size_t maskCount = (chunkStats.pageCount + 31u) / 32u; stats.pageMasks.resize(chunkStats.pageMaskOffset + maskCount); diff --git a/src/dxvk/dxvk_memory.h b/src/dxvk/dxvk_memory.h index 01cf5ecb1a8..bd7f685d1eb 100644 --- a/src/dxvk/dxvk_memory.h +++ b/src/dxvk/dxvk_memory.h @@ -67,6 +67,7 @@ namespace dxvk { VkDeviceSize size = 0u; void* mapPtr = nullptr; VkDeviceAddress gpuVa = 0u; + uint64_t cookie = 0u; }; @@ -83,8 +84,6 @@ namespace dxvk { high_resolution_clock::time_point unusedTime = { }; /// Unordered list of resources suballocated from this chunk. DxvkResourceAllocation* allocationList = nullptr; - /// Chunk cookie - uint32_t chunkCookie = 0u; /// Whether defragmentation can be performed on this chunk. /// Only relevant for chunks in non-mappable device memory. VkBool32 canMove = true; @@ -115,8 +114,6 @@ namespace dxvk { VkDeviceSize nextChunkSize = MinChunkSize; /// Maximum chunk size for the memory pool. Hard limit. VkDeviceSize maxChunkSize = MaxChunkSize; - /// Next chunk cookie, used to order chunks in statistics - uint32_t nextChunkCookie = 0u; /// Next chunk to relocate for defragmentation uint32_t nextDefragChunk = ~0u; @@ -1322,6 +1319,8 @@ namespace dxvk { DxvkResourceAllocationPool m_allocationPool; + uint64_t m_nextCookie = 0u; + alignas(CACHE_LINE_SIZE) high_resolution_clock::time_point m_taskDeadline = { }; std::array m_adapterHeapStats = { }; @@ -1338,6 +1337,10 @@ namespace dxvk { VkDeviceSize size, const void* next); + void assignMemoryDebugName( + const DxvkDeviceMemory& memory, + const DxvkMemoryType& type); + bool allocateChunkInPool( DxvkMemoryType& type, DxvkMemoryPool& pool, From 64bd8bee6274075cf455910f2d0ef13e683ce6a9 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 15:21:39 +0100 Subject: [PATCH 08/21] [d3d9] Set debug names for internal buffers --- src/d3d9/d3d9_constant_buffer.cpp | 1 + src/d3d9/d3d9_device.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/d3d9/d3d9_constant_buffer.cpp b/src/d3d9/d3d9_constant_buffer.cpp index cac2a289701..efb218c0be7 100644 --- a/src/d3d9/d3d9_constant_buffer.cpp +++ b/src/d3d9/d3d9_constant_buffer.cpp @@ -101,6 +101,7 @@ namespace dxvk { bufferInfo.usage = m_usage; bufferInfo.access = 0; bufferInfo.stages = util::pipelineStages(m_stages); + bufferInfo.debugName = "Constant buffer"; if (m_usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) bufferInfo.access |= VK_ACCESS_UNIFORM_READ_BIT; diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index ace712f8ea9..5679c1a3d0e 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -4576,6 +4576,7 @@ namespace dxvk { info.access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT; info.stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + info.debugName = "UP buffer"; Rc buffer = m_dxvkDevice->createBuffer(info, memoryFlags); void* mapPtr = buffer->mapPtr(0); From f420c69d329f025b6dee7c89c3b34aa979868c9c Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 15:21:54 +0100 Subject: [PATCH 09/21] [d3d11] Set debug names for internal buffers --- src/d3d11/d3d11_buffer.cpp | 2 ++ src/d3d11/d3d11_shader.cpp | 1 + src/d3d11/d3d11_swapchain.cpp | 3 +++ src/d3d11/d3d11_texture.cpp | 1 + src/d3d11/d3d11_video.cpp | 2 ++ src/d3d11/d3d11_view_uav.cpp | 1 + 6 files changed, 10 insertions(+) diff --git a/src/d3d11/d3d11_buffer.cpp b/src/d3d11/d3d11_buffer.cpp index bcef8a1c650..fad81782ed5 100644 --- a/src/d3d11/d3d11_buffer.cpp +++ b/src/d3d11/d3d11_buffer.cpp @@ -370,6 +370,8 @@ namespace dxvk { | VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT; + info.debugName = "SO counter"; + return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); } diff --git a/src/d3d11/d3d11_shader.cpp b/src/d3d11/d3d11_shader.cpp index 3753c075ef6..9560eb131d2 100644 --- a/src/d3d11/d3d11_shader.cpp +++ b/src/d3d11/d3d11_shader.cpp @@ -67,6 +67,7 @@ namespace dxvk { info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; info.stages = util::pipelineStages(shaderInfo.stage); info.access = VK_ACCESS_UNIFORM_READ_BIT; + info.debugName = "Icb"; VkMemoryPropertyFlags memFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index a9320ae2b2f..bfaaab772d6 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -571,6 +571,7 @@ namespace dxvk { imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; imageInfo.shared = VK_TRUE; + imageInfo.debugName = "Swap image"; DxvkImageViewKey viewInfo; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; @@ -652,6 +653,8 @@ namespace dxvk { cImages = std::move(images) ] (DxvkContext* ctx) { for (size_t i = 0; i < cImages.size(); i++) { + ctx->setDebugName(cImages[i], str::format("Back buffer ", i).c_str()); + ctx->initImage(cImages[i], cImages[i]->getAvailableSubresources(), VK_IMAGE_LAYOUT_UNDEFINED); diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index 98960f16de6..653c78cec9d 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -754,6 +754,7 @@ namespace dxvk { | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + info.debugName = "Image buffer"; // We may read mapped buffers even if it is // marked as CPU write-only on the D3D11 side. diff --git a/src/d3d11/d3d11_video.cpp b/src/d3d11/d3d11_video.cpp index 962f23dac2f..78f2b016a06 100644 --- a/src/d3d11/d3d11_video.cpp +++ b/src/d3d11/d3d11_video.cpp @@ -1323,6 +1323,8 @@ namespace dxvk { bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; bufferInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; bufferInfo.access = VK_ACCESS_UNIFORM_READ_BIT; + bufferInfo.debugName = "Video blit parameters"; + m_ubo = m_device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); } diff --git a/src/d3d11/d3d11_view_uav.cpp b/src/d3d11/d3d11_view_uav.cpp index 3c8231921ed..f3643dbc69d 100644 --- a/src/d3d11/d3d11_view_uav.cpp +++ b/src/d3d11/d3d11_view_uav.cpp @@ -450,6 +450,7 @@ namespace dxvk { | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; + info.debugName = "UAV counter"; Rc buffer = device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); From ffbf8f0fd938b77b31a83d58d3f7b3493e3e54f8 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 7 Jan 2025 14:55:36 +0100 Subject: [PATCH 10/21] [d3d11] Support debug names for buffers and textures Co-authored-by: Aaron Leiby --- src/d3d11/d3d11_buffer.cpp | 13 ++++++++++ src/d3d11/d3d11_buffer.h | 2 ++ src/d3d11/d3d11_device_child.h | 24 +++++++++++------ src/d3d11/d3d11_texture.cpp | 47 +++++++++++++++++++++++++++++++--- src/d3d11/d3d11_texture.h | 14 ++++++++++ 5 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/d3d11/d3d11_buffer.cpp b/src/d3d11/d3d11_buffer.cpp index fad81782ed5..22aa6d71584 100644 --- a/src/d3d11/d3d11_buffer.cpp +++ b/src/d3d11/d3d11_buffer.cpp @@ -1,5 +1,6 @@ #include "d3d11_buffer.h" #include "d3d11_context.h" +#include "d3d11_context_imm.h" #include "d3d11_device.h" namespace dxvk { @@ -211,6 +212,18 @@ namespace dxvk { } + void D3D11Buffer::SetDebugName(const char* pName) { + if (m_buffer) { + m_parent->GetContext()->InjectCs([ + cBuffer = m_buffer, + cName = std::string(pName ? pName : "") + ] (DxvkContext* ctx) { + ctx->setDebugName(cBuffer, cName.c_str()); + }); + } + } + + HRESULT D3D11Buffer::NormalizeBufferProperties(D3D11_BUFFER_DESC* pDesc) { // Zero-sized buffers are illegal if (!pDesc->ByteWidth && !(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL)) diff --git a/src/d3d11/d3d11_buffer.h b/src/d3d11/d3d11_buffer.h index b65df66a64b..af71a5d0ff9 100644 --- a/src/d3d11/d3d11_buffer.h +++ b/src/d3d11/d3d11_buffer.h @@ -61,6 +61,8 @@ namespace dxvk { void STDMETHODCALLTYPE GetDesc( D3D11_BUFFER_DESC *pDesc) final; + void STDMETHODCALLTYPE SetDebugName(const char* pName) final; + bool CheckViewCompatibility( UINT BindFlags, DXGI_FORMAT Format) const; diff --git a/src/d3d11/d3d11_device_child.h b/src/d3d11/d3d11_device_child.h index 60eff07afd8..0b14f684ed5 100644 --- a/src/d3d11/d3d11_device_child.h +++ b/src/d3d11/d3d11_device_child.h @@ -19,24 +19,28 @@ namespace dxvk { } HRESULT STDMETHODCALLTYPE GetPrivateData( - REFGUID guid, - UINT *pDataSize, - void *pData) final { + REFGUID guid, + UINT* pDataSize, + void* pData) final { return m_privateData.getData( guid, pDataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateData( - REFGUID guid, - UINT DataSize, - const void *pData) final { + REFGUID guid, + UINT DataSize, + const void* pData) final { + // WKPDID_D3DDebugObjectName, can't use directly due to MSVC link errors + if (guid == GUID{0x429b8c22,0x9188,0x4b0c,0x87,0x42,0xac,0xb0,0xbf,0x85,0xc2,0x00}) + SetDebugName(static_cast(pData)); + return m_privateData.setData( guid, DataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( - REFGUID guid, - const IUnknown *pUnknown) final { + REFGUID guid, + const IUnknown* pUnknown) final { return m_privateData.setInterface( guid, pUnknown); } @@ -46,6 +50,10 @@ namespace dxvk { *ppDevice = ref(GetParentInterface()); } + virtual void STDMETHODCALLTYPE SetDebugName(const char* pName) { + // No-op by default + } + protected: ID3D11Device* GetParentInterface() const { diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index 653c78cec9d..781c2596013 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -1,4 +1,5 @@ #include "d3d11_device.h" +#include "d3d11_context_imm.h" #include "d3d11_gdi.h" #include "d3d11_texture.h" @@ -372,8 +373,31 @@ namespace dxvk { return viewFormat.Format == baseFormat.Format && planeCount == 1; } } - - + + + void D3D11CommonTexture::SetDebugName(const char* pName) { + if (m_image) { + m_device->GetContext()->InjectCs([ + cImage = m_image, + cName = std::string(pName ? pName : "") + ] (DxvkContext* ctx) { + ctx->setDebugName(cImage, cName.c_str()); + }); + } + + if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) { + for (uint32_t i = 0; i < m_buffers.size(); i++) { + m_device->GetContext()->InjectCs([ + cBuffer = m_buffers[i].buffer, + cName = std::string(pName ? pName : "") + ] (DxvkContext* ctx) { + ctx->setDebugName(cBuffer, cName.c_str()); + }); + } + } + } + + HRESULT D3D11CommonTexture::NormalizeTextureProperties(D3D11_COMMON_TEXTURE_DESC* pDesc) { if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0 || pDesc->ArraySize == 0) return E_INVALIDARG; @@ -1194,8 +1218,13 @@ namespace dxvk { pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags; pDesc->MiscFlags = m_texture.Desc()->MiscFlags; } - - + + + void STDMETHODCALLTYPE D3D11Texture1D::SetDebugName(const char* pName) { + m_texture.SetDebugName(pName); + } + + /////////////////////////////////////////// // D 3 D 1 1 T E X T U R E 2 D D3D11Texture2D::D3D11Texture2D( @@ -1377,6 +1406,11 @@ namespace dxvk { } + void STDMETHODCALLTYPE D3D11Texture2D::SetDebugName(const char* pName) { + m_texture.SetDebugName(pName); + } + + /////////////////////////////////////////// // D 3 D 1 1 T E X T U R E 3 D D3D11Texture3D::D3D11Texture3D( @@ -1488,6 +1522,11 @@ namespace dxvk { } + void STDMETHODCALLTYPE D3D11Texture3D::SetDebugName(const char* pName) { + m_texture.SetDebugName(pName); + } + + D3D11CommonTexture* GetCommonTexture(ID3D11Resource* pResource) { D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN; pResource->GetType(&dimension); diff --git a/src/d3d11/d3d11_texture.h b/src/d3d11/d3d11_texture.h index 5e799afc1b3..4b28253d959 100644 --- a/src/d3d11/d3d11_texture.h +++ b/src/d3d11/d3d11_texture.h @@ -525,6 +525,14 @@ namespace dxvk { return m_11on12; } + /** + * \brief Sets debug name for texture + * + * Passes the given name to the backing image or buffer. + * \param [in] name Debug name + */ + void SetDebugName(const char* pName); + /** * \brief Normalizes and validates texture description * @@ -759,6 +767,8 @@ namespace dxvk { void STDMETHODCALLTYPE GetDesc( D3D11_TEXTURE1D_DESC *pDesc) final; + void STDMETHODCALLTYPE SetDebugName(const char* pName) final; + D3D11CommonTexture* GetCommonTexture() { return &m_texture; } @@ -825,6 +835,8 @@ namespace dxvk { void STDMETHODCALLTYPE GetDesc1( D3D11_TEXTURE2D_DESC1* pDesc) final; + void STDMETHODCALLTYPE SetDebugName(const char* pName) final; + D3D11CommonTexture* GetCommonTexture() { return &m_texture; } @@ -875,6 +887,8 @@ namespace dxvk { void STDMETHODCALLTYPE GetDesc1( D3D11_TEXTURE3D_DESC1* pDesc) final; + void STDMETHODCALLTYPE SetDebugName(const char* pName) final; + D3D11CommonTexture* GetCommonTexture() { return &m_texture; } From c70504bf460bd84733703c0cb80e63c161085eb3 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 8 Nov 2024 19:31:21 +0100 Subject: [PATCH 11/21] [dxvk] Add context feature flag for debug utils support --- src/dxvk/dxvk_context.cpp | 22 +++++++++++++--------- src/dxvk/dxvk_context.h | 1 + src/dxvk/dxvk_context_state.h | 1 + 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 0c8f28111d8..65770701105 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -63,6 +63,10 @@ namespace dxvk { // Maintenance5 introduced a bounded BindIndexBuffer function if (m_device->features().khrMaintenance5.maintenance5) m_features.set(DxvkContextFeature::IndexBufferRobustness); + + // Add a fast path to query debug utils support + if (m_device->isDebugEnabled()) + m_features.set(DxvkContextFeature::DebugUtils); } @@ -101,6 +105,8 @@ namespace dxvk { m_cmd->trackDescriptorPool(m_descriptorPool, m_descriptorManager); m_descriptorPool = m_descriptorManager->getDescriptorPool(); } + + m_renderPassIndex = 0u; } @@ -2481,29 +2487,27 @@ namespace dxvk { } - void DxvkContext::beginDebugLabel(VkDebugUtilsLabelEXT* label) { - if (m_device->isDebugEnabled()) + void DxvkContext::beginDebugLabel(VkDebugUtilsLabelEXT *label) { + if (m_features.test(DxvkContextFeature::DebugUtils)) m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, *label); } void DxvkContext::endDebugLabel() { - if (m_device->isDebugEnabled()) + if (m_features.test(DxvkContextFeature::DebugUtils)) m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); } - void DxvkContext::insertDebugLabel(VkDebugUtilsLabelEXT* label) { - if (m_device->isDebugEnabled()) + void DxvkContext::insertDebugLabel(VkDebugUtilsLabelEXT *label) { + if (m_features.test(DxvkContextFeature::DebugUtils)) m_cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, *label); } void DxvkContext::setDebugName(const Rc& resource, const char* name) { - if (!m_device->isDebugEnabled()) - return; - - resource->setDebugName(name); + if (m_features.test(DxvkContextFeature::DebugUtils)) + resource->setDebugName(name); } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 4c904aec495..1ead0df0be8 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1379,6 +1379,7 @@ namespace dxvk { DxvkObjects* m_common; uint64_t m_trackingId = 0u; + uint32_t m_renderPassIndex = 0u; Rc m_cmd; Rc m_zeroBuffer; diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index b6066cb8a9f..c29bb443943 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -66,6 +66,7 @@ namespace dxvk { TrackGraphicsPipeline, VariableMultisampleRate, IndexBufferRobustness, + DebugUtils, FeatureCount }; From f6bdca7fc1db1a14f8a1865eb50d180e0b04cce9 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 6 Nov 2024 11:06:12 +0100 Subject: [PATCH 12/21] [dxvk] Add debug regions to command buffers --- src/dxvk/dxvk_cmdlist.cpp | 29 +++++++++++++++++++++++++---- src/dxvk/dxvk_cmdlist.h | 4 +++- src/vulkan/vulkan_util.h | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/dxvk/dxvk_cmdlist.cpp b/src/dxvk/dxvk_cmdlist.cpp index c1edfef0c3a..ca27a017e04 100644 --- a/src/dxvk/dxvk_cmdlist.cpp +++ b/src/dxvk/dxvk_cmdlist.cpp @@ -115,7 +115,7 @@ namespace dxvk { } - VkCommandBuffer DxvkCommandPool::getCommandBuffer() { + VkCommandBuffer DxvkCommandPool::getCommandBuffer(DxvkCmdBuffer type) { auto vk = m_device->vkd(); if (m_next == m_commandBuffers.size()) { @@ -143,6 +143,24 @@ namespace dxvk { if (vk->vkBeginCommandBuffer(commandBuffer, &info)) throw DxvkError("DxvkCommandPool: Failed to begin command buffer"); + if (m_device->isDebugEnabled()) { + auto vki = m_device->vki(); + + VkDebugUtilsLabelEXT label = { }; + + switch (type) { + case DxvkCmdBuffer::ExecBuffer: label = vk::makeLabel(0xdcc0a2, "Graphics commands"); break; + case DxvkCmdBuffer::InitBuffer: label = vk::makeLabel(0xc0dca2, "Init commands"); break; + case DxvkCmdBuffer::InitBarriers: label = vk::makeLabel(0xd0e6b8, "Init barriers"); break; + case DxvkCmdBuffer::SdmaBuffer: label = vk::makeLabel(0xc0a2dc, "Upload commands"); break; + case DxvkCmdBuffer::SdmaBarriers: label = vk::makeLabel(0xd0b8e6, "Upload barriers"); break; + default: ; + } + + if (label.pLabelName) + vki->vkCmdBeginDebugUtilsLabelEXT(commandBuffer, &label); + } + return commandBuffer; } @@ -162,7 +180,7 @@ namespace dxvk { DxvkCommandList::DxvkCommandList(DxvkDevice* device) : m_device (device), m_vkd (device->vkd()), - m_vki (device->instance()->vki()) { + m_vki (device->vki()) { const auto& graphicsQueue = m_device->queues().graphics; const auto& transferQueue = m_device->queues().transfer; @@ -409,6 +427,9 @@ namespace dxvk { void DxvkCommandList::endCommandBuffer(VkCommandBuffer cmdBuffer) { auto vk = m_device->vkd(); + if (m_device->isDebugEnabled()) + m_vki->vkCmdEndDebugUtilsLabelEXT(cmdBuffer); + if (vk->vkEndCommandBuffer(cmdBuffer)) throw DxvkError("DxvkCommandList: Failed to end command buffer"); } @@ -416,8 +437,8 @@ namespace dxvk { VkCommandBuffer DxvkCommandList::allocateCommandBuffer(DxvkCmdBuffer type) { return type == DxvkCmdBuffer::SdmaBuffer || type == DxvkCmdBuffer::SdmaBarriers - ? m_transferPool->getCommandBuffer() - : m_graphicsPool->getCommandBuffer(); + ? m_transferPool->getCommandBuffer(type) + : m_graphicsPool->getCommandBuffer(type); } } diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 53b44f0ee99..31f4a1bc5ec 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -172,9 +172,11 @@ namespace dxvk { /** * \brief Retrieves or allocates a command buffer + * + * \param [in] type Command buffer type * \returns New command buffer in begun state */ - VkCommandBuffer getCommandBuffer(); + VkCommandBuffer getCommandBuffer(DxvkCmdBuffer type); /** * \brief Resets command pool and all command buffers diff --git a/src/vulkan/vulkan_util.h b/src/vulkan/vulkan_util.h index c9ebf695435..2995c4f7d3b 100644 --- a/src/vulkan/vulkan_util.h +++ b/src/vulkan/vulkan_util.h @@ -227,6 +227,23 @@ namespace dxvk::vk { return name && name[0]; } + + /** + * \brief Makes debug label + * + * \param [in] color Color, as BGR with implied opaque alpha + * \param [in] text Label text + */ + inline VkDebugUtilsLabelEXT makeLabel(uint32_t color, const char* text) { + VkDebugUtilsLabelEXT label = { VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT }; + label.color[0] = ((color >> 16u) & 0xffu) / 255.0f; + label.color[1] = ((color >> 8u) & 0xffu) / 255.0f; + label.color[2] = ((color >> 0u) & 0xffu) / 255.0f; + label.color[3] = 1.0f; + label.pLabelName = text; + return label; + } + } From 28897698a414dca15e1d2faa85b44ca45ed344ff Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 13:48:16 +0100 Subject: [PATCH 13/21] [dxvk] Add debug region stack Ensures that we correctly begin and end app-provided regions within each command buffer. --- src/d3d11/d3d11_annotation.cpp | 4 +-- src/d3d9/d3d9_annotation.cpp | 4 +-- src/dxvk/dxvk_context.cpp | 58 ++++++++++++++++++++++++++++++---- src/dxvk/dxvk_context.h | 20 +++++++++--- src/dxvk/dxvk_util.h | 36 ++++++++++++++++++++- 5 files changed, 106 insertions(+), 16 deletions(-) diff --git a/src/d3d11/d3d11_annotation.cpp b/src/d3d11/d3d11_annotation.cpp index 4e02c599020..5b5494501cc 100644 --- a/src/d3d11/d3d11_annotation.cpp +++ b/src/d3d11/d3d11_annotation.cpp @@ -87,7 +87,7 @@ namespace dxvk { label.pLabelName = labelName.c_str(); DecodeD3DCOLOR(color, label.color); - ctx->beginDebugLabel(&label); + ctx->beginDebugLabel(label); }); return m_eventDepth++; @@ -125,7 +125,7 @@ namespace dxvk { label.pLabelName = labelName.c_str(); DecodeD3DCOLOR(color, label.color); - ctx->insertDebugLabel(&label); + ctx->insertDebugLabel(label); }); } diff --git a/src/d3d9/d3d9_annotation.cpp b/src/d3d9/d3d9_annotation.cpp index 09b3ef18ada..71ed9769ca4 100644 --- a/src/d3d9/d3d9_annotation.cpp +++ b/src/d3d9/d3d9_annotation.cpp @@ -135,7 +135,7 @@ namespace dxvk { label.pLabelName = labelName.c_str(); DecodeD3DCOLOR(color, label.color); - ctx->beginDebugLabel(&label); + ctx->beginDebugLabel(label); }); // Handled by the global list. @@ -165,7 +165,7 @@ namespace dxvk { label.pLabelName = labelName.c_str(); DecodeD3DCOLOR(color, label.color); - ctx->insertDebugLabel(&label); + ctx->insertDebugLabel(label); }); } diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 65770701105..e6bfd504aaf 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2487,21 +2487,29 @@ namespace dxvk { } - void DxvkContext::beginDebugLabel(VkDebugUtilsLabelEXT *label) { - if (m_features.test(DxvkContextFeature::DebugUtils)) - m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, *label); + void DxvkContext::beginDebugLabel(const VkDebugUtilsLabelEXT& label) { + if (m_features.test(DxvkContextFeature::DebugUtils)) { + endInternalDebugRegion(); + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, label); + m_debugLabelStack.emplace_back(label); + } } void DxvkContext::endDebugLabel() { - if (m_features.test(DxvkContextFeature::DebugUtils)) - m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + if (m_features.test(DxvkContextFeature::DebugUtils)) { + if (!m_debugLabelStack.empty()) { + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_debugLabelStack.pop_back(); + } + } } - void DxvkContext::insertDebugLabel(VkDebugUtilsLabelEXT *label) { + void DxvkContext::insertDebugLabel(const VkDebugUtilsLabelEXT& label) { if (m_features.test(DxvkContextFeature::DebugUtils)) - m_cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, *label); + m_cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, label); } @@ -6665,6 +6673,8 @@ namespace dxvk { void DxvkContext::beginCurrentCommands() { + beginActiveDebugRegions(); + // The current state of the internal command buffer is // undefined, so we have to bind and set up everything // before any draw or dispatch command is recorded. @@ -6713,6 +6723,8 @@ namespace dxvk { m_execBarriers.finalize(m_cmd); m_barrierTracker.clear(); + + endActiveDebugRegions(); } @@ -7256,4 +7268,36 @@ namespace dxvk { } } + + void DxvkContext::beginInternalDebugRegion(const VkDebugUtilsLabelEXT& label) { + if (m_features.test(DxvkContextFeature::DebugUtils)) { + // If the app provides us with debug regions, don't add any + // internal ones to avoid potential issues with scoping. + if (m_debugLabelStack.empty()) { + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, label); + m_debugLabelInternalActive = true; + } + } + } + + + void DxvkContext::endInternalDebugRegion() { + if (m_debugLabelInternalActive) { + m_debugLabelInternalActive = false; + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + } + } + + + void DxvkContext::beginActiveDebugRegions() { + for (const auto& region : m_debugLabelStack) + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, region.get()); + } + + + void DxvkContext::endActiveDebugRegions() { + for (size_t i = 0; i < m_debugLabelStack.size(); i++) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + } + } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 1ead0df0be8..debce68619b 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1328,12 +1328,12 @@ namespace dxvk { /** * \brief Begins a debug label region - * \param [in] label The debug label * * Marks the start of a debug label region. Used by debugging/profiling * tools to mark different workloads within a frame. + * \param [in] label The debug label */ - void beginDebugLabel(VkDebugUtilsLabelEXT *label); + void beginDebugLabel(const VkDebugUtilsLabelEXT& label); /** * \brief Ends a debug label region @@ -1345,12 +1345,12 @@ namespace dxvk { /** * \brief Inserts a debug label - * \param [in] label The debug label * * Inserts an instantaneous debug label. Used by debugging/profiling * tools to mark different workloads within a frame. + * \param [in] label The debug label */ - void insertDebugLabel(VkDebugUtilsLabelEXT *label); + void insertDebugLabel(const VkDebugUtilsLabelEXT& label); /** * \brief Increments a given stat counter @@ -1418,6 +1418,9 @@ namespace dxvk { std::vector m_imageLayoutTransitions; + std::vector m_debugLabelStack; + bool m_debugLabelInternalActive = false; + void blitImageFb( Rc dstView, const VkOffset3D* dstOffsets, @@ -1935,6 +1938,15 @@ namespace dxvk { return pred(DxvkAccess::Read); } + void beginInternalDebugRegion( + const VkDebugUtilsLabelEXT& label); + + void endInternalDebugRegion(); + + void beginActiveDebugRegions(); + + void endActiveDebugRegions(); + static bool formatsAreCopyCompatible( VkFormat imageFormat, VkFormat bufferFormat); diff --git a/src/dxvk/dxvk_util.h b/src/dxvk/dxvk_util.h index edeb22398dd..863647f2475 100644 --- a/src/dxvk/dxvk_util.h +++ b/src/dxvk/dxvk_util.h @@ -3,7 +3,41 @@ #include "dxvk_include.h" namespace dxvk::util { - + + /** + * \brief Debug label wrapper + * + * Wrapper around a Vulkan debug label that + * persistently stores the string in question. + */ + class DxvkDebugLabel { + + public: + + DxvkDebugLabel() = default; + + DxvkDebugLabel(const VkDebugUtilsLabelEXT& label) + : m_text(label.pLabelName ? label.pLabelName : "") { + for (uint32_t i = 0; i < m_color.size(); i++) + m_color[i] = label.color[i]; + } + + VkDebugUtilsLabelEXT get() const { + VkDebugUtilsLabelEXT label = { VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT }; + label.pLabelName = m_text.c_str(); + for (uint32_t i = 0; i < m_color.size(); i++) + label.color[i] = m_color[i]; + return label; + } + + private: + + std::string m_text; + std::array m_color = { }; + + }; + + /** * \brief Gets pipeline stage flags for shader stages * From d023374be8685b4d67281fcbc2bb7a66ad81847f Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 14:18:28 +0100 Subject: [PATCH 14/21] [dxvk] Add debug regions for render passes --- src/dxvk/dxvk_context.cpp | 50 +++++++++++++++++++++++++++++++++++++++ src/dxvk/dxvk_context.h | 2 ++ 2 files changed, 52 insertions(+) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index e6bfd504aaf..573e958e76b 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2487,6 +2487,52 @@ namespace dxvk { } + void DxvkContext::beginRenderPassDebugRegion() { + bool hasColorAttachments = false; + bool hasDepthAttachment = m_state.om.renderTargets.depth.view != nullptr; + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) + hasColorAttachments |= m_state.om.renderTargets.color[i].view != nullptr; + + std::stringstream label; + + if (hasColorAttachments) + label << "Color"; + else if (hasDepthAttachment) + label << "Depth"; + else + label << "Render"; + + label << " pass " << uint32_t(++m_renderPassIndex) << " ("; + + hasColorAttachments = false; + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + if (m_state.om.renderTargets.color[i].view) { + const char* imageName = m_state.om.renderTargets.color[i].view->image()->info().debugName; + label << (hasColorAttachments ? ", " : "") << i << ": " << (imageName ? imageName : "unknown"); + + hasColorAttachments = true; + } + } + + if (m_state.om.renderTargets.depth.view) { + if (hasColorAttachments) + label << ", "; + + const char* imageName = m_state.om.renderTargets.depth.view->image()->info().debugName; + label << "DS:" << (imageName ? imageName : "unknown"); + } + + if (!hasColorAttachments && !hasDepthAttachment) + label << "No attachments"; + + label << ")"; + + beginInternalDebugRegion(vk::makeLabel(0xf0e6dc, label.str().c_str())); + } + + void DxvkContext::beginDebugLabel(const VkDebugUtilsLabelEXT& label) { if (m_features.test(DxvkContextFeature::DebugUtils)) { endInternalDebugRegion(); @@ -4483,6 +4529,9 @@ namespace dxvk { DxvkContextFlag::GpRenderPassSuspended, DxvkContextFlag::GpIndependentSets); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + beginRenderPassDebugRegion(); + this->renderPassBindFramebuffer( m_state.om.framebufferInfo, m_state.om.renderPassOps); @@ -4520,6 +4569,7 @@ namespace dxvk { this->transitionRenderTargetLayouts(false); flushBarriers(); + endInternalDebugRegion(); } else if (!suspend) { // We may end a previously suspended render pass if (m_flags.test(DxvkContextFlag::GpRenderPassSuspended)) { diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index debce68619b..a978af177b1 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1938,6 +1938,8 @@ namespace dxvk { return pred(DxvkAccess::Read); } + void beginRenderPassDebugRegion(); + void beginInternalDebugRegion( const VkDebugUtilsLabelEXT& label); From 5b9bf8ea5d714d211af5248068eaa315ea7c495d Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 14:50:13 +0100 Subject: [PATCH 15/21] [dxvk] Add debug label for render target clears --- src/dxvk/dxvk_context.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 573e958e76b..320c042c51d 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1798,6 +1798,12 @@ namespace dxvk { flushPendingAccesses(*imageView, DxvkAccess::Write); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* imageName = imageView->image()->info().debugName; + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xe6f0dc, str::format("Clear render target (", imageName ? imageName : "unknown", ")").c_str())); + } + // Set up a temporary render pass to execute the clear VkImageLayout imageLayout = ((clearAspects | discardAspects) & VK_IMAGE_ASPECT_COLOR_BIT) ? imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) @@ -1883,6 +1889,9 @@ namespace dxvk { imageView->image()->info().stages, imageView->image()->info().access); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(imageView->image(), DxvkAccess::Write); } else { // Perform the operation when starting the next render pass From 5037bcc5ce5cc151cf9eec8e14a14044882710b5 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 15:43:02 +0100 Subject: [PATCH 16/21] [dxvk] Add debug labels for pipeline binding --- src/dxvk/dxvk_compute.cpp | 11 ++++++++++- src/dxvk/dxvk_compute.h | 16 +++++++++++++++- src/dxvk/dxvk_context.cpp | 10 ++++++++++ src/dxvk/dxvk_graphics.cpp | 26 +++++++++++++++++++++++++- src/dxvk/dxvk_graphics.h | 17 ++++++++++++++++- 5 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index 04972b0c0b4..560872792e0 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -24,7 +24,8 @@ namespace dxvk { m_library (library), m_libraryHandle (VK_NULL_HANDLE), m_shaders (std::move(shaders)), - m_bindings (layout) { + m_bindings (layout), + m_debugName (createDebugName()) { } @@ -157,4 +158,12 @@ namespace dxvk { Logger::log(level, sstr.str()); } + + std::string DxvkComputePipeline::createDebugName() const { + std::string shaderName = m_shaders.cs->debugName(); + size_t len = std::min(shaderName.size(), size_t(10)); + + return str::format("[", shaderName.substr(0, len), "]"); + } + } diff --git a/src/dxvk/dxvk_compute.h b/src/dxvk/dxvk_compute.h index c684d976218..c437d7ad539 100644 --- a/src/dxvk/dxvk_compute.h +++ b/src/dxvk/dxvk_compute.h @@ -119,7 +119,17 @@ namespace dxvk { */ void compilePipeline( const DxvkComputePipelineStateInfo& state); - + + /** + * \brief Debug name + * + * Consists of the compute shader's debug name. + * \returns Debug name + */ + const char* debugName() const { + return m_debugName.c_str(); + } + private: DxvkDevice* m_device; @@ -132,6 +142,8 @@ namespace dxvk { DxvkComputePipelineShaders m_shaders; DxvkBindingLayoutObjects* m_bindings; + std::string m_debugName; + alignas(CACHE_LINE_SIZE) dxvk::mutex m_mutex; sync::List m_pipelines; @@ -152,6 +164,8 @@ namespace dxvk { LogLevel level, const DxvkComputePipelineStateInfo& state) const; + std::string createDebugName() const; + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 320c042c51d..960b2b186de 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -4940,6 +4940,11 @@ namespace dxvk { if (newPipeline->getBindings()->layout().getPushConstantRange(true).size) m_flags.set(DxvkContextFlag::DirtyPushConstants); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + m_cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xf0dca2, newPipeline->debugName())); + } + m_flags.clr(DxvkContextFlag::CpDirtyPipelineState); return true; } @@ -5108,6 +5113,11 @@ namespace dxvk { dstBarrier.stages, dstBarrier.access); } + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + m_cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xa2dcf0, m_state.gp.pipeline->debugName())); + } + m_flags.clr(DxvkContextFlag::GpDirtyPipelineState); return true; } diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 1f44f57d5a1..ec6b2147bd9 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -945,7 +945,8 @@ namespace dxvk { m_bindings (layout), m_barrier (layout->getGlobalBarrier()), m_vsLibrary (vsLibrary), - m_fsLibrary (fsLibrary) { + m_fsLibrary (fsLibrary), + m_debugName (createDebugName()) { m_vsIn = m_shaders.vs != nullptr ? m_shaders.vs->info().inputMask : 0; m_fsOut = m_shaders.fs != nullptr ? m_shaders.fs->info().outputMask : 0; m_specConstantMask = this->computeSpecConstantMask(); @@ -1673,5 +1674,28 @@ namespace dxvk { Logger::log(level, sstr.str()); } + + + std::string DxvkGraphicsPipeline::createDebugName() const { + std::stringstream name; + + std::array, 5> shaders = {{ + m_shaders.vs, + m_shaders.tcs, + m_shaders.tes, + m_shaders.gs, + m_shaders.fs, + }}; + + for (const auto& shader : shaders) { + if (shader) { + std::string shaderName = shader->debugName(); + size_t len = std::min(shaderName.size(), size_t(10)); + name << "[" << shaderName.substr(0, len) << "] "; + } + } + + return name.str(); + } } diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 5b8ee6b14f6..3503fd89684 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -561,6 +561,17 @@ namespace dxvk { */ void releasePipeline(); + /** + * \brief Queries debug name for the pipeline + * + * The pipeline debug name contains the debug name of + * each shader included in the pipeline. + * \returns Pipeline debug name + */ + const char* debugName() const { + return m_debugName.c_str(); + } + private: DxvkDevice* m_device; @@ -582,6 +593,8 @@ namespace dxvk { uint32_t m_specConstantMask = 0; + std::string m_debugName; + alignas(CACHE_LINE_SIZE) dxvk::mutex m_mutex; sync::List m_pipelines; @@ -596,7 +609,7 @@ namespace dxvk { std::unordered_map< DxvkGraphicsPipelineFastInstanceKey, VkPipeline, DxvkHash, DxvkEq> m_fastPipelines; - + DxvkGraphicsPipelineInstance* createInstance( const DxvkGraphicsPipelineStateInfo& state, bool doCreateBasePipeline); @@ -643,6 +656,8 @@ namespace dxvk { LogLevel level, const DxvkGraphicsPipelineStateInfo& state) const; + std::string createDebugName() const; + }; } \ No newline at end of file From 26ad7785c45b19695dd56ca0b2804b02a5084da8 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 14:54:42 +0100 Subject: [PATCH 17/21] [dxvk] Add debug region for memory defragmentation --- src/dxvk/dxvk_context.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 960b2b186de..3639322c7a7 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -6612,6 +6612,11 @@ namespace dxvk { if (resourceList.empty()) return; + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xc0a2f0, "Memory defrag")); + } + std::vector bufferInfos; std::vector imageInfos; @@ -6649,6 +6654,9 @@ namespace dxvk { imageInfos.size(), imageInfos.data()); m_cmd->setSubmissionBarrier(); + + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); } From 1c0c6c6e05c9d4bbfdde545f96c6b4633b561347 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 18:47:08 +0100 Subject: [PATCH 18/21] [dxvk] Add debug region for mip generation --- src/dxvk/dxvk_context.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 3639322c7a7..1c791906b5a 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1234,6 +1234,13 @@ namespace dxvk { flushPendingAccesses(*imageView->image(), imageView->imageSubresources(), DxvkAccess::Write); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = imageView->image()->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, vk::makeLabel(0xe6dcf0, + str::format("Mip gen (", dstName ? dstName : "unknown", ")").c_str())); + } + // Create image views, etc. DxvkMetaMipGenViews mipGenerator(imageView); @@ -1367,6 +1374,9 @@ namespace dxvk { VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT); } + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(imageView->image(), DxvkAccess::Write); m_cmd->track(std::move(sampler)); } From b9dc562fb5438b53c00504e78fb4ea03842f3fa4 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 16:18:56 +0100 Subject: [PATCH 19/21] [dxvk] Add debug regions for internal operations --- src/dxvk/dxvk_context.cpp | 109 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 1c791906b5a..c0c3d92d617 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -277,6 +277,14 @@ namespace dxvk { cmdBuffer = DxvkCmdBuffer::ExecBuffer; } + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = bufferView->buffer()->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(cmdBuffer, + vk::makeLabel(0xf0dcdc, str::format("Clear view (", + dstName ? dstName : "unknown", ")").c_str())); + } + // Query pipeline objects to use for this clear operation DxvkMetaClearPipeline pipeInfo = m_common->metaClear().getClearBufferPipeline( lookupFormatInfo(bufferView->info().format)->flags); @@ -319,6 +327,9 @@ namespace dxvk { VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(cmdBuffer); + m_cmd->track(bufferView->buffer(), DxvkAccess::Write); } @@ -2608,6 +2619,16 @@ namespace dxvk { flushPendingAccesses(*dstView, DxvkAccess::Write); flushPendingAccesses(*srcView, DxvkAccess::Read); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = dstView->image()->info().debugName; + const char* srcName = srcView->image()->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xf0dcdc, str::format("Blit (", + dstName ? dstName : "unknown", ", ", + srcName ? srcName : "unknown", ")").c_str())); + } + VkImageLayout srcLayout = srcView->image()->pickLayout(srcIsDepthStencil ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -2744,6 +2765,9 @@ namespace dxvk { VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(dstView->image(), DxvkAccess::Write); m_cmd->track(srcView->image(), DxvkAccess::Read); m_cmd->track(std::move(sampler)); @@ -2974,6 +2998,16 @@ namespace dxvk { flushPendingAccesses(*image, vk::makeSubresourceRange(imageSubresource), DxvkAccess::Write); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = image->info().debugName; + const char* srcName = buffer->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xf0dcdc, str::format("Upload image (", + dstName ? dstName : "unknown", ", ", + srcName ? srcName : "unknown", ")").c_str())); + } + auto formatInfo = lookupFormatInfo(bufferFormat); if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) { @@ -3182,6 +3216,9 @@ namespace dxvk { VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(image, DxvkAccess::Write); m_cmd->track(buffer, DxvkAccess::Read); } @@ -3260,6 +3297,16 @@ namespace dxvk { flushPendingAccesses(*image, vk::makeSubresourceRange(imageSubresource), DxvkAccess::Read); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = buffer->info().debugName; + const char* srcName = image->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xf0dcdc, str::format("Readback image (", + dstName ? dstName : "unknown", ", ", + srcName ? srcName : "unknown", ")").c_str())); + } + auto formatInfo = lookupFormatInfo(bufferFormat); if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) { @@ -3397,6 +3444,9 @@ namespace dxvk { vk::makeSubresourceRange(imageSubresource), imageLayout, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(buffer, DxvkAccess::Write); m_cmd->track(image, DxvkAccess::Read); } @@ -3429,6 +3479,13 @@ namespace dxvk { flushPendingAccesses(*imageView->image(), imageView->imageSubresources(), DxvkAccess::Write); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = imageView->image()->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, vk::makeLabel(0xf0dcdc, + str::format("Clear view (", dstName ? dstName : "unknown", ")").c_str())); + } + clearLayout = (imageView->info().aspects & VK_IMAGE_ASPECT_COLOR_BIT) ? imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) : imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); @@ -3505,6 +3562,9 @@ namespace dxvk { *imageView->image(), imageView->imageSubresources(), clearLayout, clearStages, clearAccess); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(imageView->image(), DxvkAccess::Write); } } @@ -3526,6 +3586,13 @@ namespace dxvk { cmdBuffer = DxvkCmdBuffer::ExecBuffer; } + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = imageView->image()->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(cmdBuffer, vk::makeLabel(0xf0dcdc, + str::format("Clear view (", dstName ? dstName : "unknown", ")").c_str())); + } + addImageLayoutTransition(*imageView->image(), imageView->imageSubresources(), VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, imageView->image()->isFullSubresource(vk::pickSubresourceLayers(imageView->imageSubresources(), 0), extent)); @@ -3582,6 +3649,9 @@ namespace dxvk { VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(cmdBuffer); + m_cmd->track(imageView->image(), DxvkAccess::Write); } @@ -3694,6 +3764,16 @@ namespace dxvk { this->invalidateState(); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = dstImage->info().debugName; + const char* srcName = srcImage->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xf0dcdc, str::format("Copy image (", + dstName ? dstName : "unknown", ", ", + srcName ? srcName : "unknown", ")").c_str())); + } + auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresource); auto srcSubresourceRange = vk::makeSubresourceRange(srcSubresource); @@ -3846,6 +3926,9 @@ namespace dxvk { *dstImage, dstSubresourceRange, dstLayout, dstStages, dstAccess); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(dstImage, DxvkAccess::Write); m_cmd->track(srcImage, DxvkAccess::Read); } @@ -4153,6 +4236,16 @@ namespace dxvk { flushPendingAccesses(*dstImage, dstSubresourceRange, DxvkAccess::Write); flushPendingAccesses(*srcImage, srcSubresourceRange, DxvkAccess::Read); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = dstImage->info().debugName; + const char* srcName = srcImage->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xf0dcdc, str::format("Resolve DS (", + dstName ? dstName : "unknown", ", ", + srcName ? srcName : "unknown", ")").c_str())); + } + // Transition both images to usable layouts if necessary. For the source image we // can be fairly leniet since writable layouts are allowed for resolve attachments. VkImageLayout dstLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); @@ -4215,6 +4308,9 @@ namespace dxvk { VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(dstImage, DxvkAccess::Write); m_cmd->track(srcImage, DxvkAccess::Read); } @@ -4262,6 +4358,16 @@ namespace dxvk { flushPendingAccesses(*dstImage, dstSubresourceRange, DxvkAccess::Write); flushPendingAccesses(*srcImage, srcSubresourceRange, DxvkAccess::Read); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) { + const char* dstName = dstImage->info().debugName; + const char* srcName = srcImage->info().debugName; + + m_cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xf0dcdc, str::format("Resolve (", + dstName ? dstName : "unknown", ", ", + srcName ? srcName : "unknown", ")").c_str())); + } + // Discard the destination image if we're fully writing it, // and transition the image layout if necessary bool doDiscard = dstImage->isFullSubresource(region.dstSubresource, region.extent); @@ -4416,6 +4522,9 @@ namespace dxvk { *dstImage, dstSubresourceRange, dstLayout, dstStages, dstAccess); + if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) + m_cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer); + m_cmd->track(dstImage, DxvkAccess::Write); m_cmd->track(srcImage, DxvkAccess::Read); } From 70f3e0315e67d201415ab9fa70c1d57f3fc50837 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 16:25:38 +0100 Subject: [PATCH 20/21] [dxvk] Add debug label for swap chain blitter --- src/dxvk/dxvk_swapchain_blitter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dxvk/dxvk_swapchain_blitter.cpp b/src/dxvk/dxvk_swapchain_blitter.cpp index a2c5e91c89c..aca8718a03f 100644 --- a/src/dxvk/dxvk_swapchain_blitter.cpp +++ b/src/dxvk/dxvk_swapchain_blitter.cpp @@ -252,6 +252,11 @@ namespace dxvk { VkColorSpaceKHR srcColorSpace, VkRect2D srcRect, VkBool32 enableBlending) { + if (unlikely(m_device->isDebugEnabled())) { + ctx.cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xdcc0f0, "Swapchain blit")); + } + VkExtent3D dstExtent = dstView->mipLevelExtent(0); VkOffset2D coordA = dstRect.offset; From 74307e8e68695bbc0264042b860bd6e15e102cf6 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 8 Jan 2025 16:25:50 +0100 Subject: [PATCH 21/21] [hud] Add debug label for HUD rendering --- src/dxvk/hud/dxvk_hud_item.cpp | 8 ++++++++ src/dxvk/hud/dxvk_hud_renderer.cpp | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/dxvk/hud/dxvk_hud_item.cpp b/src/dxvk/hud/dxvk_hud_item.cpp index bccc94644fc..d676202a0ef 100644 --- a/src/dxvk/hud/dxvk_hud_item.cpp +++ b/src/dxvk/hud/dxvk_hud_item.cpp @@ -277,6 +277,11 @@ namespace dxvk::hud { uint32_t dataPoint, HudPos minPos, HudPos maxPos) { + if (unlikely(m_device->isDebugEnabled())) { + ctx.cmd->cmdBeginDebugUtilsLabel(DxvkCmdBuffer::InitBuffer, + vk::makeLabel(0xf0c0dc, "HUD frame time processing")); + } + // Write current time stamp to the buffer DxvkBufferSliceHandle sliceHandle = m_gpuBuffer->getSliceHandle(); std::pair query = m_query->getQuery(); @@ -372,6 +377,9 @@ namespace dxvk::hud { renderer.drawTextIndirect(ctx, key, drawParamBuffer, drawInfoBuffer, textBufferView, 2u); + if (unlikely(m_device->isDebugEnabled())) + ctx.cmd->cmdEndDebugUtilsLabel(DxvkCmdBuffer::InitBuffer); + // Make sure GPU resources are being kept alive as necessary ctx.cmd->track(m_gpuBuffer, DxvkAccess::Write); ctx.cmd->track(m_query); diff --git a/src/dxvk/hud/dxvk_hud_renderer.cpp b/src/dxvk/hud/dxvk_hud_renderer.cpp index 4ac05c94878..fa5159794d6 100644 --- a/src/dxvk/hud/dxvk_hud_renderer.cpp +++ b/src/dxvk/hud/dxvk_hud_renderer.cpp @@ -59,6 +59,11 @@ namespace dxvk::hud { const Rc& dstView, VkColorSpaceKHR dstColorSpace, const HudOptions& options) { + if (unlikely(m_device->isDebugEnabled())) { + ctx.cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, + vk::makeLabel(0xf0c0dc, "HUD")); + } + if (!m_fontTextureView) { createFontResources(); uploadFontResources(ctx);