From ab557a2eed98f936a6022ee626d91b20b22b39d3 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 13 Sep 2024 13:17:36 +0200 Subject: [PATCH] [dxvk] Use global buffer whenever possible Drastically reduces the number of Vulkan buffer objects allocated. --- src/dxvk/dxvk_buffer.cpp | 57 +++++++++++++++++++++++++--------------- src/dxvk/dxvk_buffer.h | 32 +++++++--------------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/dxvk/dxvk_buffer.cpp b/src/dxvk/dxvk_buffer.cpp index 4fd2a2639..333cf480d 100644 --- a/src/dxvk/dxvk_buffer.cpp +++ b/src/dxvk/dxvk_buffer.cpp @@ -37,7 +37,7 @@ namespace dxvk { m_buffer = allocBuffer(m_physSliceCount, m_physSliceCount > 1); m_physSlice.handle = m_buffer.buffer; - m_physSlice.offset = 0; + m_physSlice.offset = m_buffer.getBaseOffset(); m_physSlice.length = m_physSliceLength; m_physSlice.mapPtr = m_buffer.memory.mapPtr(0); @@ -88,10 +88,13 @@ namespace dxvk { DxvkBuffer::~DxvkBuffer() { - for (const auto& buffer : m_buffers) - m_vkd->vkDestroyBuffer(m_vkd->device(), buffer.buffer, nullptr); + for (const auto& buffer : m_buffers) { + if (buffer.buffer != buffer.memory.buffer()) + m_vkd->vkDestroyBuffer(m_vkd->device(), buffer.buffer, nullptr); + } - m_vkd->vkDestroyBuffer(m_vkd->device(), m_buffer.buffer, nullptr); + if (m_buffer.buffer != m_buffer.memory.buffer()) + m_vkd->vkDestroyBuffer(m_vkd->device(), m_buffer.buffer, nullptr); } @@ -104,31 +107,21 @@ namespace dxvk { DxvkBufferHandle handle; - if (m_vkd->vkCreateBuffer(m_vkd->device(), &info, nullptr, &handle.buffer)) { - throw DxvkError(str::format( - "DxvkBuffer: Failed to create buffer:" - "\n flags: ", std::hex, info.flags, - "\n size: ", std::dec, info.size, - "\n usage: ", std::hex, info.usage)); - } - // Query memory requirements and whether to use a dedicated allocation DxvkMemoryRequirements memoryRequirements = { }; memoryRequirements.tiling = VK_IMAGE_TILING_LINEAR; memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS }; memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated }; - VkBufferMemoryRequirementsInfo2 memoryRequirementInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 }; - memoryRequirementInfo.buffer = handle.buffer; - - m_vkd->vkGetBufferMemoryRequirements2(m_vkd->device(), - &memoryRequirementInfo, &memoryRequirements.core); + m_memAlloc->getBufferMemoryRequirements(info, memoryRequirements.core); // Fill in desired memory properties DxvkMemoryProperties memoryProperties = { }; memoryProperties.flags = m_memFlags; if (memoryRequirements.dedicated.prefersDedicatedAllocation) { + handle.buffer = createBuffer(info); + memoryProperties.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO }; memoryProperties.dedicated.buffer = handle.buffer; } @@ -151,10 +144,17 @@ namespace dxvk { hints.set(DxvkMemoryFlag::Transient); handle.memory = m_memAlloc->alloc(memoryRequirements, memoryProperties, hints); - - if (m_vkd->vkBindBufferMemory(m_vkd->device(), handle.buffer, - handle.memory.memory(), handle.memory.offset()) != VK_SUCCESS) - throw DxvkError("DxvkBuffer: Failed to bind device memory"); + + if (!handle.buffer && (!handle.memory.buffer() || (handle.memory.getBufferUsage() & info.usage) != info.usage)) + handle.buffer = createBuffer(info); + + if (handle.buffer) { + if (m_vkd->vkBindBufferMemory(m_vkd->device(), handle.buffer, + handle.memory.memory(), handle.memory.offset()) != VK_SUCCESS) + throw DxvkError("DxvkBuffer: Failed to bind device memory"); + } else { + handle.buffer = handle.memory.buffer(); + } if (clear && (m_memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) std::memset(handle.memory.mapPtr(0), 0, info.size); @@ -185,6 +185,21 @@ namespace dxvk { } + VkBuffer DxvkBuffer::createBuffer(const VkBufferCreateInfo& info) const { + VkBuffer buffer = VK_NULL_HANDLE; + + if (m_vkd->vkCreateBuffer(m_vkd->device(), &info, nullptr, &buffer)) { + throw DxvkError(str::format( + "DxvkBuffer: Failed to create buffer:" + "\n flags: ", std::hex, info.flags, + "\n size: ", std::dec, info.size, + "\n usage: ", std::hex, info.usage)); + } + + return buffer; + } + + VkDeviceSize DxvkBuffer::computeSliceAlignment(DxvkDevice* device) const { const auto& devInfo = device->properties(); diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index 5be994060..4f289239e 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -80,6 +80,12 @@ namespace dxvk { struct DxvkBufferHandle { VkBuffer buffer = VK_NULL_HANDLE; DxvkMemory memory; + + VkDeviceSize getBaseOffset() const { + return buffer == memory.buffer() + ? memory.offset() + : 0u; + } }; @@ -218,16 +224,6 @@ namespace dxvk { return result; } - /** - * \brief Retrieves dynamic offset - * - * \param [in] offset Offset into the buffer - * \returns Offset for dynamic descriptors - */ - VkDeviceSize getDynamicOffset(VkDeviceSize offset) const { - return m_physSlice.offset + offset; - } - /** * \brief Replaces backing resource * @@ -356,9 +352,9 @@ namespace dxvk { void pushSlice(const DxvkBufferHandle& handle, uint32_t index) { DxvkBufferSliceHandle slice; slice.handle = handle.buffer; + slice.offset = handle.getBaseOffset() + m_physSliceStride * index; slice.length = m_physSliceLength; - slice.offset = m_physSliceStride * index; - slice.mapPtr = handle.memory.mapPtr(slice.offset); + slice.mapPtr = handle.memory.mapPtr(m_physSliceStride * index); m_freeSlices.push_back(slice); } @@ -368,6 +364,8 @@ namespace dxvk { DxvkBufferHandle createSparseBuffer() const; + VkBuffer createBuffer(const VkBufferCreateInfo& info) const; + VkDeviceSize computeSliceAlignment( DxvkDevice* device) const; @@ -494,16 +492,6 @@ namespace dxvk { DxvkDescriptorInfo getDescriptor() const { return m_buffer->getDescriptor(m_offset, m_length); } - - /** - * \brief Retrieves dynamic offset - * - * Used for descriptor set binding. - * \returns Buffer slice offset - */ - VkDeviceSize getDynamicOffset() const { - return m_buffer->getDynamicOffset(m_offset); - } /** * \brief Pointer to mapped memory region