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
*/
Rc<DxvkResourceAllocation> 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);
}
/**

View File

@ -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);
}

View File

@ -505,19 +505,19 @@ namespace dxvk {
Rc<DxvkResourceAllocation> DxvkMemoryAllocator::allocateMemory(
const VkMemoryRequirements& requirements,
VkMemoryPropertyFlags properties) {
const DxvkAllocationInfo& allocationInfo) {
std::lock_guard<dxvk::mutex> 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<DxvkResourceAllocation> DxvkMemoryAllocator::allocateDedicatedMemory(
const VkMemoryRequirements& requirements,
VkMemoryPropertyFlags properties,
const DxvkAllocationInfo& allocationInfo,
const void* next) {
std::lock_guard<dxvk::mutex> 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<DxvkResourceAllocation> DxvkMemoryAllocator::createBufferResource(
const VkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags properties,
const DxvkAllocationInfo& allocationInfo,
DxvkLocalAllocationCache* allocationCache) {
Rc<DxvkResourceAllocation> 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<DxvkResourceAllocation> 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;

View File

@ -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<DxvkResourceAllocation> 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<DxvkResourceAllocation> 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<DxvkResourceAllocation> 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<DxvkResourceAllocation> createImageResource(
const VkImageCreateInfo& createInfo,
VkMemoryPropertyFlags properties,
const DxvkAllocationInfo& allocationInfo,
const void* next);
/**