1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-24 13:54:17 +01:00

[dxvk] Introduce DxvkAllocationInfo

Useful when more properties are added in the future.
This commit is contained in:
Philip Rebohle 2024-10-17 22:43:45 +02:00
parent 81380cddcf
commit 3eca3fc52c
4 changed files with 81 additions and 46 deletions

View File

@ -312,13 +312,16 @@ namespace dxvk {
* \returns The new buffer slice * \returns The new buffer slice
*/ */
Rc<DxvkResourceAllocation> allocateStorage(DxvkLocalAllocationCache* cache) { Rc<DxvkResourceAllocation> allocateStorage(DxvkLocalAllocationCache* cache) {
DxvkAllocationInfo allocationInfo = { };
allocationInfo.properties = m_properties;
VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
info.flags = m_info.flags; info.flags = m_info.flags;
info.usage = m_info.usage; info.usage = m_info.usage;
info.size = m_info.size; info.size = m_info.size;
m_sharingMode.fill(info); m_sharingMode.fill(info);
return m_allocator->createBufferResource(info, m_properties, cache); return m_allocator->createBufferResource(info, allocationInfo, cache);
} }
/** /**

View File

@ -173,8 +173,11 @@ namespace dxvk {
sharedImportWin32.handle = m_info.sharing.handle; sharedImportWin32.handle = m_info.sharing.handle;
} }
DxvkAllocationInfo allocationInfo = { };
allocationInfo.properties = m_properties;
return m_allocator->createImageResource(imageInfo, return m_allocator->createImageResource(imageInfo,
m_properties, sharedMemoryInfo); allocationInfo, sharedMemoryInfo);
} }

View File

@ -505,19 +505,19 @@ namespace dxvk {
Rc<DxvkResourceAllocation> DxvkMemoryAllocator::allocateMemory( Rc<DxvkResourceAllocation> DxvkMemoryAllocator::allocateMemory(
const VkMemoryRequirements& requirements, const VkMemoryRequirements& requirements,
VkMemoryPropertyFlags properties) { const DxvkAllocationInfo& allocationInfo) {
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
// Ensure the allocation size is also aligned // Ensure the allocation size is also aligned
VkDeviceSize size = align(requirements.size, requirements.alignment); 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]; auto& type = m_memTypes[typeIndex];
// Use correct memory pool depending on property flags. This way we avoid // Use correct memory pool depending on property flags. This way we avoid
// wasting address space on fallback allocations, or on UMA devices that // wasting address space on fallback allocations, or on UMA devices that
// only expose one memory type. // 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.mappedPool
: type.devicePool; : type.devicePool;
@ -531,7 +531,7 @@ namespace dxvk {
// If the memory type is host-visible, try to find an existing chunk // 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. // in the other memory pool of the memory type and move over.
if (type.properties.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 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.devicePool
: type.mappedPool; : type.mappedPool;
@ -546,7 +546,7 @@ namespace dxvk {
oppositePool.pageAllocator.removeChunk(freeChunkIndex); oppositePool.pageAllocator.removeChunk(freeChunkIndex);
oppositePool.chunks[freeChunkIndex] = DxvkMemoryChunk(); oppositePool.chunks[freeChunkIndex] = DxvkMemoryChunk();
mapDeviceMemory(selectedPool.chunks[poolChunkIndex].memory, properties); mapDeviceMemory(selectedPool.chunks[poolChunkIndex].memory, allocationInfo.properties);
address = selectedPool.alloc(size, requirements.alignment); address = selectedPool.alloc(size, requirements.alignment);
@ -558,7 +558,7 @@ namespace dxvk {
// If the allocation is very large, use a dedicated allocation instead // If the allocation is very large, use a dedicated allocation instead
// of creating a new chunk. This way we avoid excessive fragmentation, // of creating a new chunk. This way we avoid excessive fragmentation,
// especially when a multiple such resources are created at once. // 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 // 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 // worth of memory to huge resources causing fragmentation, use dedicated
@ -573,7 +573,7 @@ namespace dxvk {
if (!memory.memory) if (!memory.memory)
continue; continue;
mapDeviceMemory(memory, properties); mapDeviceMemory(memory, allocationInfo.properties);
return createAllocation(type, memory); return createAllocation(type, memory);
} }
@ -584,7 +584,7 @@ namespace dxvk {
while (desiredSize < size * minResourcesPerChunk) while (desiredSize < size * minResourcesPerChunk)
desiredSize *= 2u; desiredSize *= 2u;
if (allocateChunkInPool(type, selectedPool, properties, size, desiredSize)) { if (allocateChunkInPool(type, selectedPool, allocationInfo.properties, size, desiredSize)) {
address = selectedPool.alloc(size, requirements.alignment); address = selectedPool.alloc(size, requirements.alignment);
return createAllocation(type, selectedPool, address, size); return createAllocation(type, selectedPool, address, size);
} }
@ -596,18 +596,18 @@ namespace dxvk {
Rc<DxvkResourceAllocation> DxvkMemoryAllocator::allocateDedicatedMemory( Rc<DxvkResourceAllocation> DxvkMemoryAllocator::allocateDedicatedMemory(
const VkMemoryRequirements& requirements, const VkMemoryRequirements& requirements,
VkMemoryPropertyFlags properties, const DxvkAllocationInfo& allocationInfo,
const void* next) { const void* next) {
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
DxvkDeviceMemory memory = { }; 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]; auto& type = m_memTypes[typeIndex];
memory = allocateDeviceMemory(type, requirements.size, next); memory = allocateDeviceMemory(type, requirements.size, next);
if (likely(memory.memory != VK_NULL_HANDLE)) { if (likely(memory.memory != VK_NULL_HANDLE)) {
mapDeviceMemory(memory, properties); mapDeviceMemory(memory, allocationInfo.properties);
return createAllocation(type, memory); return createAllocation(type, memory);
} }
} }
@ -618,7 +618,7 @@ namespace dxvk {
Rc<DxvkResourceAllocation> DxvkMemoryAllocator::createBufferResource( Rc<DxvkResourceAllocation> DxvkMemoryAllocator::createBufferResource(
const VkBufferCreateInfo& createInfo, const VkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags properties, const DxvkAllocationInfo& allocationInfo,
DxvkLocalAllocationCache* allocationCache) { DxvkLocalAllocationCache* allocationCache) {
Rc<DxvkResourceAllocation> allocation; Rc<DxvkResourceAllocation> allocation;
@ -638,7 +638,7 @@ namespace dxvk {
// are expected to happen frequently. // are expected to happen frequently.
if (allocationCache && createInfo.size <= DxvkLocalAllocationCache::MaxSize if (allocationCache && createInfo.size <= DxvkLocalAllocationCache::MaxSize
&& allocationCache->m_memoryTypes && !(allocationCache->m_memoryTypes & ~memoryRequirements.memoryTypeBits) && 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); allocation = allocationCache->allocateFromCache(createInfo.size);
if (likely(allocation)) if (likely(allocation))
@ -647,21 +647,23 @@ namespace dxvk {
// If the cache is currently empty for the required allocation size, // If the cache is currently empty for the required allocation size,
// make sure it's not. This will also initialize the shared caches // make sure it's not. This will also initialize the shared caches
// for any relevant memory pools as necessary. // for any relevant memory pools as necessary.
if (refillAllocationCache(allocationCache, memoryRequirements, properties)) if (refillAllocationCache(allocationCache, memoryRequirements, allocationInfo.properties))
return allocationCache->allocateFromCache(createInfo.size); return allocationCache->allocateFromCache(createInfo.size);
} }
// If there is at least one memory type that supports the required // If there is at least one memory type that supports the required
// buffer usage flags and requested memory properties, suballocate // buffer usage flags and requested memory properties, suballocate
// from a global buffer. // from a global buffer.
allocation = allocateMemory(memoryRequirements, properties); allocation = allocateMemory(memoryRequirements, allocationInfo);
if (likely(allocation && allocation->m_buffer)) if (likely(allocation && allocation->m_buffer))
return allocation; return allocation;
if (!allocation && (properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
allocation = allocateMemory(memoryRequirements, DxvkAllocationInfo fallbackInfo = allocationInfo;
properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
allocation = allocateMemory(memoryRequirements, fallbackInfo);
if (likely(allocation && allocation->m_buffer)) if (likely(allocation && allocation->m_buffer))
return allocation; return allocation;
@ -702,11 +704,13 @@ namespace dxvk {
if (!allocation || !(requirements.memoryRequirements.memoryTypeBits & (1u << allocation->m_type->index)) if (!allocation || !(requirements.memoryRequirements.memoryTypeBits & (1u << allocation->m_type->index))
|| (allocation->m_size < requirements.memoryRequirements.size) || (allocation->m_size < requirements.memoryRequirements.size)
|| (allocation->m_address & requirements.memoryRequirements.alignment)) || (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)) { if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
allocation = allocateMemory(requirements.memoryRequirements, DxvkAllocationInfo fallbackInfo = allocationInfo;
properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
allocation = allocateMemory(requirements.memoryRequirements, fallbackInfo);
} }
if (!allocation) { if (!allocation) {
@ -752,7 +756,7 @@ namespace dxvk {
Rc<DxvkResourceAllocation> DxvkMemoryAllocator::createImageResource( Rc<DxvkResourceAllocation> DxvkMemoryAllocator::createImageResource(
const VkImageCreateInfo& createInfo, const VkImageCreateInfo& createInfo,
VkMemoryPropertyFlags properties, const DxvkAllocationInfo& allocationInfo,
const void* next) { const void* next) {
auto vk = m_device->vkd(); auto vk = m_device->vkd();
@ -792,14 +796,18 @@ namespace dxvk {
VkMemoryDedicatedAllocateInfo dedicatedInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, next }; VkMemoryDedicatedAllocateInfo dedicatedInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, next };
dedicatedInfo.image = image; 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 // Only retry with a dedicated sysmem allocation if a dedicated allocation
// is required. Otherwise, we should try to suballocate in device memory. // is required. Otherwise, we should try to suballocate in device memory.
if (!allocation && dedicatedRequirements.requiresDedicatedAllocation 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, 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. // 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)) { if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
allocation = allocateMemory(requirements.memoryRequirements, DxvkAllocationInfo fallbackInfo = allocationInfo;
properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
allocation = allocateMemory(requirements.memoryRequirements, fallbackInfo);
} }
} }
} else { } else {
@ -831,10 +841,15 @@ namespace dxvk {
metadataRequirements.alignment = SparseMemoryPageSize; metadataRequirements.alignment = SparseMemoryPageSize;
metadataRequirements.memoryTypeBits = requirements.memoryRequirements.memoryTypeBits; 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, metadataInfo);
allocation = allocateMemory(metadataRequirements, 0u);
if (!allocation) {
metadataInfo.properties = 0u;
allocation = allocateMemory(metadataRequirements, metadataInfo);
}
if (allocation) if (allocation)
allocation->m_sparsePageTable = pageTable.release(); allocation->m_sparsePageTable = pageTable.release();
@ -883,10 +898,15 @@ namespace dxvk {
// Try device memory first, fall back to system memory if that fails. // Try device memory first, fall back to system memory if that fails.
// We might get an allocation with a global buffer, just ignore that. // 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) auto allocation = allocateMemory(requirements, allocationInfo);
allocation = allocateMemory(requirements, 0);
if (!allocation) {
allocationInfo.properties = 0u;
allocation = allocateMemory(requirements, allocationInfo);
}
if (!allocation) if (!allocation)
return nullptr; return nullptr;

View File

@ -917,6 +917,15 @@ namespace dxvk {
}; };
/**
* \brief Allocation properties
*/
struct DxvkAllocationInfo {
/// Desired memory property flags
VkMemoryPropertyFlags properties = 0u;
};
/** /**
* \brief Memory allocator * \brief Memory allocator
* *
@ -952,27 +961,27 @@ namespace dxvk {
* not required. Very large resources may still be placed in * not required. Very large resources may still be placed in
* a dedicated allocation. * a dedicated allocation.
* \param [in] requirements Memory requirements * \param [in] requirements Memory requirements
* \param [in] allocationInfo Allocation info
* \param [in] properties Memory property flags. Some of * \param [in] properties Memory property flags. Some of
* these may be ignored in case of memory pressure. * these may be ignored in case of memory pressure.
* \returns Allocated memory * \returns Allocated memory
*/ */
Rc<DxvkResourceAllocation> allocateMemory( Rc<DxvkResourceAllocation> allocateMemory(
const VkMemoryRequirements& requirements, const VkMemoryRequirements& requirements,
VkMemoryPropertyFlags properties); const DxvkAllocationInfo& allocationInfo);
/** /**
* \brief Allocates memory for a resource * \brief Allocates memory for a resource
* *
* Will always create a dedicated allocation. * Will always create a dedicated allocation.
* \param [in] requirements Memory requirements * \param [in] requirements Memory requirements
* \param [in] properties Memory property flags. Some of * \param [in] allocationInfo Allocation info
* these may be ignored in case of memory pressure.
* \param [in] next Further memory properties * \param [in] next Further memory properties
* \returns Allocated memory * \returns Allocated memory
*/ */
Rc<DxvkResourceAllocation> allocateDedicatedMemory( Rc<DxvkResourceAllocation> allocateDedicatedMemory(
const VkMemoryRequirements& requirements, const VkMemoryRequirements& requirements,
VkMemoryPropertyFlags properties, const DxvkAllocationInfo& allocationInfo,
const void* next); const void* next);
/** /**
@ -981,26 +990,26 @@ namespace dxvk {
* Will make use of global buffers whenever possible, but * Will make use of global buffers whenever possible, but
* may fall back to creating a dedicated Vulkan buffer. * may fall back to creating a dedicated Vulkan buffer.
* \param [in] createInfo Buffer create info * \param [in] createInfo Buffer create info
* \param [in] properties Memory property flags * \param [in] allocationInfo Allocation properties
* \param [in] allocationCache Optional allocation cache * \param [in] allocationCache Optional allocation cache
* \returns Buffer resource * \returns Buffer resource
*/ */
Rc<DxvkResourceAllocation> createBufferResource( Rc<DxvkResourceAllocation> createBufferResource(
const VkBufferCreateInfo& createInfo, const VkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags properties, const DxvkAllocationInfo& allocationInfo,
DxvkLocalAllocationCache* allocationCache); DxvkLocalAllocationCache* allocationCache);
/** /**
* \brief Creates image resource * \brief Creates image resource
* *
* \param [in] createInfo Image create info * \param [in] createInfo Image create info
* \param [in] properties Memory property flags * \param [in] allocationInfo Allocation properties
* \param [in] next External memory properties * \param [in] next External memory properties
* \returns Image resource * \returns Image resource
*/ */
Rc<DxvkResourceAllocation> createImageResource( Rc<DxvkResourceAllocation> createImageResource(
const VkImageCreateInfo& createInfo, const VkImageCreateInfo& createInfo,
VkMemoryPropertyFlags properties, const DxvkAllocationInfo& allocationInfo,
const void* next); const void* next);
/** /**