From 25078203398b22869e975eb9fb644d5b2d503da3 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 7 Jan 2025 14:10:23 +0100 Subject: [PATCH] [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 1f71da961..364d7a59c 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 c287b89cc..4ea76fca6 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 9dc614b0e..83b0eb4a0 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 c08e9bf19..4c904aec4 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 bc25c49be..da216ccf7 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 f98184370..8647baa19 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 1cc27645e..3e0e1e413 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(); + } - // 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")); + 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")); + } } } } diff --git a/src/dxvk/dxvk_sparse.h b/src/dxvk/dxvk_sparse.h index a6efd031f..7eb9385a9 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 2dd1de987..c9ebf6954 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]; + } + }