From 3eca3fc52c10f01dba29a5c82e0d1c289a073530 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 17 Oct 2024 22:43:45 +0200 Subject: [PATCH] [dxvk] Introduce DxvkAllocationInfo Useful when more properties are added in the future. --- src/dxvk/dxvk_buffer.h | 5 ++- src/dxvk/dxvk_image.cpp | 5 ++- src/dxvk/dxvk_memory.cpp | 92 ++++++++++++++++++++++++---------------- src/dxvk/dxvk_memory.h | 25 +++++++---- 4 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index 5e2b74524..7b33528ce 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -312,13 +312,16 @@ namespace dxvk { * \returns The new buffer slice */ Rc allocateStorage(DxvkLocalAllocationCache* cache) { + DxvkAllocationInfo allocationInfo = { }; + allocationInfo.properties = m_properties; + VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; info.flags = m_info.flags; info.usage = m_info.usage; info.size = m_info.size; m_sharingMode.fill(info); - return m_allocator->createBufferResource(info, m_properties, cache); + return m_allocator->createBufferResource(info, allocationInfo, cache); } /** diff --git a/src/dxvk/dxvk_image.cpp b/src/dxvk/dxvk_image.cpp index 146f8c846..4fb8f2e2c 100644 --- a/src/dxvk/dxvk_image.cpp +++ b/src/dxvk/dxvk_image.cpp @@ -173,8 +173,11 @@ namespace dxvk { sharedImportWin32.handle = m_info.sharing.handle; } + DxvkAllocationInfo allocationInfo = { }; + allocationInfo.properties = m_properties; + return m_allocator->createImageResource(imageInfo, - m_properties, sharedMemoryInfo); + allocationInfo, sharedMemoryInfo); } diff --git a/src/dxvk/dxvk_memory.cpp b/src/dxvk/dxvk_memory.cpp index 9e1843e22..bc99081c1 100644 --- a/src/dxvk/dxvk_memory.cpp +++ b/src/dxvk/dxvk_memory.cpp @@ -505,19 +505,19 @@ namespace dxvk { Rc DxvkMemoryAllocator::allocateMemory( const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags properties) { + const DxvkAllocationInfo& allocationInfo) { std::lock_guard lock(m_mutex); // Ensure the allocation size is also aligned VkDeviceSize size = align(requirements.size, requirements.alignment); - for (auto typeIndex : bit::BitMask(requirements.memoryTypeBits & getMemoryTypeMask(properties))) { + for (auto typeIndex : bit::BitMask(requirements.memoryTypeBits & getMemoryTypeMask(allocationInfo.properties))) { auto& type = m_memTypes[typeIndex]; // Use correct memory pool depending on property flags. This way we avoid // wasting address space on fallback allocations, or on UMA devices that // only expose one memory type. - auto& selectedPool = (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + auto& selectedPool = (allocationInfo.properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? type.mappedPool : type.devicePool; @@ -531,7 +531,7 @@ namespace dxvk { // If the memory type is host-visible, try to find an existing chunk // in the other memory pool of the memory type and move over. if (type.properties.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { - auto& oppositePool = (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + auto& oppositePool = (allocationInfo.properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? type.devicePool : type.mappedPool; @@ -546,7 +546,7 @@ namespace dxvk { oppositePool.pageAllocator.removeChunk(freeChunkIndex); oppositePool.chunks[freeChunkIndex] = DxvkMemoryChunk(); - mapDeviceMemory(selectedPool.chunks[poolChunkIndex].memory, properties); + mapDeviceMemory(selectedPool.chunks[poolChunkIndex].memory, allocationInfo.properties); address = selectedPool.alloc(size, requirements.alignment); @@ -558,7 +558,7 @@ namespace dxvk { // If the allocation is very large, use a dedicated allocation instead // of creating a new chunk. This way we avoid excessive fragmentation, // especially when a multiple such resources are created at once. - uint32_t minResourcesPerChunk = (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? 1u : 4u; + uint32_t minResourcesPerChunk = (allocationInfo.properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? 1u : 4u; // If we're on a mapped memory type and we're about to lose an entire chunk // worth of memory to huge resources causing fragmentation, use dedicated @@ -573,7 +573,7 @@ namespace dxvk { if (!memory.memory) continue; - mapDeviceMemory(memory, properties); + mapDeviceMemory(memory, allocationInfo.properties); return createAllocation(type, memory); } @@ -584,7 +584,7 @@ namespace dxvk { while (desiredSize < size * minResourcesPerChunk) desiredSize *= 2u; - if (allocateChunkInPool(type, selectedPool, properties, size, desiredSize)) { + if (allocateChunkInPool(type, selectedPool, allocationInfo.properties, size, desiredSize)) { address = selectedPool.alloc(size, requirements.alignment); return createAllocation(type, selectedPool, address, size); } @@ -596,18 +596,18 @@ namespace dxvk { Rc DxvkMemoryAllocator::allocateDedicatedMemory( const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags properties, + const DxvkAllocationInfo& allocationInfo, const void* next) { std::lock_guard lock(m_mutex); DxvkDeviceMemory memory = { }; - for (auto typeIndex : bit::BitMask(requirements.memoryTypeBits & getMemoryTypeMask(properties))) { + for (auto typeIndex : bit::BitMask(requirements.memoryTypeBits & getMemoryTypeMask(allocationInfo.properties))) { auto& type = m_memTypes[typeIndex]; memory = allocateDeviceMemory(type, requirements.size, next); if (likely(memory.memory != VK_NULL_HANDLE)) { - mapDeviceMemory(memory, properties); + mapDeviceMemory(memory, allocationInfo.properties); return createAllocation(type, memory); } } @@ -618,7 +618,7 @@ namespace dxvk { Rc DxvkMemoryAllocator::createBufferResource( const VkBufferCreateInfo& createInfo, - VkMemoryPropertyFlags properties, + const DxvkAllocationInfo& allocationInfo, DxvkLocalAllocationCache* allocationCache) { Rc allocation; @@ -638,7 +638,7 @@ namespace dxvk { // are expected to happen frequently. if (allocationCache && createInfo.size <= DxvkLocalAllocationCache::MaxSize && allocationCache->m_memoryTypes && !(allocationCache->m_memoryTypes & ~memoryRequirements.memoryTypeBits) - && (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + && (allocationInfo.properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { allocation = allocationCache->allocateFromCache(createInfo.size); if (likely(allocation)) @@ -647,21 +647,23 @@ namespace dxvk { // If the cache is currently empty for the required allocation size, // make sure it's not. This will also initialize the shared caches // for any relevant memory pools as necessary. - if (refillAllocationCache(allocationCache, memoryRequirements, properties)) + if (refillAllocationCache(allocationCache, memoryRequirements, allocationInfo.properties)) return allocationCache->allocateFromCache(createInfo.size); } // 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, properties); + allocation = allocateMemory(memoryRequirements, allocationInfo); if (likely(allocation && allocation->m_buffer)) return allocation; - if (!allocation && (properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { - allocation = allocateMemory(memoryRequirements, - properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { + DxvkAllocationInfo fallbackInfo = allocationInfo; + fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + allocation = allocateMemory(memoryRequirements, fallbackInfo); if (likely(allocation && allocation->m_buffer)) return allocation; @@ -702,11 +704,13 @@ namespace dxvk { if (!allocation || !(requirements.memoryRequirements.memoryTypeBits & (1u << allocation->m_type->index)) || (allocation->m_size < requirements.memoryRequirements.size) || (allocation->m_address & requirements.memoryRequirements.alignment)) - allocation = allocateMemory(requirements.memoryRequirements, properties); + allocation = allocateMemory(requirements.memoryRequirements, allocationInfo); - if (!allocation && (properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { - allocation = allocateMemory(requirements.memoryRequirements, - properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { + DxvkAllocationInfo fallbackInfo = allocationInfo; + fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + allocation = allocateMemory(requirements.memoryRequirements, fallbackInfo); } if (!allocation) { @@ -752,7 +756,7 @@ namespace dxvk { Rc DxvkMemoryAllocator::createImageResource( const VkImageCreateInfo& createInfo, - VkMemoryPropertyFlags properties, + const DxvkAllocationInfo& allocationInfo, const void* next) { auto vk = m_device->vkd(); @@ -792,14 +796,18 @@ namespace dxvk { VkMemoryDedicatedAllocateInfo dedicatedInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, next }; dedicatedInfo.image = image; - allocation = allocateDedicatedMemory(requirements.memoryRequirements, properties, &dedicatedInfo); + allocation = allocateDedicatedMemory(requirements.memoryRequirements, + allocationInfo, &dedicatedInfo); // Only retry with a dedicated sysmem allocation if a dedicated allocation // is required. Otherwise, we should try to suballocate in device memory. if (!allocation && dedicatedRequirements.requiresDedicatedAllocation - && (properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { + && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { + DxvkAllocationInfo fallbackInfo = allocationInfo; + fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + allocation = allocateDedicatedMemory(requirements.memoryRequirements, - properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &dedicatedInfo); + fallbackInfo, &dedicatedInfo); } } @@ -812,11 +820,13 @@ namespace dxvk { } // Try to suballocate memory and fall back to system memory on error. - allocation = allocateMemory(requirements.memoryRequirements, properties); + allocation = allocateMemory(requirements.memoryRequirements, allocationInfo); - if (!allocation && (properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { - allocation = allocateMemory(requirements.memoryRequirements, - properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { + DxvkAllocationInfo fallbackInfo = allocationInfo; + fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + allocation = allocateMemory(requirements.memoryRequirements, fallbackInfo); } } } else { @@ -831,10 +841,15 @@ namespace dxvk { metadataRequirements.alignment = SparseMemoryPageSize; metadataRequirements.memoryTypeBits = requirements.memoryRequirements.memoryTypeBits; - allocation = allocateMemory(metadataRequirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + DxvkAllocationInfo metadataInfo = { }; + metadataInfo.properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - if (!allocation) - allocation = allocateMemory(metadataRequirements, 0u); + allocation = allocateMemory(metadataRequirements, metadataInfo); + + if (!allocation) { + metadataInfo.properties = 0u; + allocation = allocateMemory(metadataRequirements, metadataInfo); + } if (allocation) allocation->m_sparsePageTable = pageTable.release(); @@ -883,10 +898,15 @@ namespace dxvk { // Try device memory first, fall back to system memory if that fails. // We might get an allocation with a global buffer, just ignore that. - auto allocation = allocateMemory(requirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + DxvkAllocationInfo allocationInfo = { }; + allocationInfo.properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - if (!allocation) - allocation = allocateMemory(requirements, 0); + auto allocation = allocateMemory(requirements, allocationInfo); + + if (!allocation) { + allocationInfo.properties = 0u; + allocation = allocateMemory(requirements, allocationInfo); + } if (!allocation) return nullptr; diff --git a/src/dxvk/dxvk_memory.h b/src/dxvk/dxvk_memory.h index 82358e79a..2a00cb090 100644 --- a/src/dxvk/dxvk_memory.h +++ b/src/dxvk/dxvk_memory.h @@ -917,6 +917,15 @@ namespace dxvk { }; + /** + * \brief Allocation properties + */ + struct DxvkAllocationInfo { + /// Desired memory property flags + VkMemoryPropertyFlags properties = 0u; + }; + + /** * \brief Memory allocator * @@ -952,27 +961,27 @@ namespace dxvk { * not required. Very large resources may still be placed in * a dedicated allocation. * \param [in] requirements Memory requirements + * \param [in] allocationInfo Allocation info * \param [in] properties Memory property flags. Some of * these may be ignored in case of memory pressure. * \returns Allocated memory */ Rc allocateMemory( const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags properties); + const DxvkAllocationInfo& allocationInfo); /** * \brief Allocates memory for a resource * * Will always create a dedicated allocation. * \param [in] requirements Memory requirements - * \param [in] properties Memory property flags. Some of - * these may be ignored in case of memory pressure. + * \param [in] allocationInfo Allocation info * \param [in] next Further memory properties * \returns Allocated memory */ Rc allocateDedicatedMemory( const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags properties, + const DxvkAllocationInfo& allocationInfo, const void* next); /** @@ -981,26 +990,26 @@ namespace dxvk { * Will make use of global buffers whenever possible, but * may fall back to creating a dedicated Vulkan buffer. * \param [in] createInfo Buffer create info - * \param [in] properties Memory property flags + * \param [in] allocationInfo Allocation properties * \param [in] allocationCache Optional allocation cache * \returns Buffer resource */ Rc createBufferResource( const VkBufferCreateInfo& createInfo, - VkMemoryPropertyFlags properties, + const DxvkAllocationInfo& allocationInfo, DxvkLocalAllocationCache* allocationCache); /** * \brief Creates image resource * * \param [in] createInfo Image create info - * \param [in] properties Memory property flags + * \param [in] allocationInfo Allocation properties * \param [in] next External memory properties * \returns Image resource */ Rc createImageResource( const VkImageCreateInfo& createInfo, - VkMemoryPropertyFlags properties, + const DxvkAllocationInfo& allocationInfo, const void* next); /**