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

[dxvk] Introduce allocation modes

Will be useful when relocating resources for defragmentation purposes.
This commit is contained in:
Philip Rebohle 2024-10-18 01:07:58 +02:00
parent 1525fbef03
commit 527d9c2236
3 changed files with 53 additions and 9 deletions

View File

@ -183,6 +183,7 @@ namespace dxvk {
DxvkAllocationInfo allocationInfo = { }; DxvkAllocationInfo allocationInfo = { };
allocationInfo.resourceCookie = cookie(); allocationInfo.resourceCookie = cookie();
allocationInfo.properties = m_properties; allocationInfo.properties = m_properties;
allocationInfo.mode = mode;
return m_allocator->createImageResource(imageInfo, return m_allocator->createImageResource(imageInfo,
allocationInfo, sharedMemoryInfo); allocationInfo, sharedMemoryInfo);

View File

@ -581,6 +581,10 @@ namespace dxvk {
} }
} }
// If we're not allowed to allocate device memory, move on.
if (allocationInfo.mode.test(DxvkAllocationMode::NoAllocation))
continue;
// 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.
@ -685,7 +689,8 @@ namespace dxvk {
if (likely(allocation && allocation->m_buffer)) if (likely(allocation && allocation->m_buffer))
return allocation; return allocation;
if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
&& !allocationInfo.mode.test(DxvkAllocationMode::NoFallback)) {
DxvkAllocationInfo fallbackInfo = allocationInfo; DxvkAllocationInfo fallbackInfo = allocationInfo;
fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
@ -695,9 +700,21 @@ namespace dxvk {
return allocation; 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();
}
return nullptr;
}
// If we end up here with an allocation but no buffer, something // If we end up here with an allocation but no buffer, something
// is weird, but we can keep the allocation around for now. // is weird, but we can keep the allocation around for now.
if (allocation && !allocation->m_buffer) { if (!allocation->m_buffer) {
Logger::err(str::format("Got allocation from memory type ", Logger::err(str::format("Got allocation from memory type ",
allocation->m_type->index, " without global buffer")); allocation->m_type->index, " without global buffer"));
} }
@ -732,14 +749,15 @@ namespace dxvk {
|| (allocation->m_address & requirements.memoryRequirements.alignment)) || (allocation->m_address & requirements.memoryRequirements.alignment))
allocation = allocateMemory(requirements.memoryRequirements, allocationInfo); allocation = allocateMemory(requirements.memoryRequirements, allocationInfo);
if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
&& !allocationInfo.mode.test(DxvkAllocationMode::NoFallback)) {
DxvkAllocationInfo fallbackInfo = allocationInfo; DxvkAllocationInfo fallbackInfo = allocationInfo;
fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
allocation = allocateMemory(requirements.memoryRequirements, fallbackInfo); allocation = allocateMemory(requirements.memoryRequirements, fallbackInfo);
} }
if (!allocation) { if (!allocation && allocationInfo.mode.isClear()) {
logMemoryError(requirements.memoryRequirements); logMemoryError(requirements.memoryRequirements);
logMemoryStats(); logMemoryStats();
} }
@ -820,7 +838,8 @@ namespace dxvk {
if (!(createInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) { if (!(createInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
// If a dedicated allocation is at least preferred for this resource, try this first // If a dedicated allocation is at least preferred for this resource, try this first
if (!allocation && dedicatedRequirements.prefersDedicatedAllocation) { if (!allocation && dedicatedRequirements.prefersDedicatedAllocation
&& !allocationInfo.mode.test(DxvkAllocationMode::NoAllocation)) {
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;
@ -830,6 +849,7 @@ namespace dxvk {
// 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
&& !allocationInfo.mode.test(DxvkAllocationMode::NoFallback)
&& (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
DxvkAllocationInfo fallbackInfo = allocationInfo; DxvkAllocationInfo fallbackInfo = allocationInfo;
fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
@ -850,7 +870,8 @@ 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, allocationInfo); allocation = allocateMemory(requirements.memoryRequirements, allocationInfo);
if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { if (!allocation && (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
&& !allocationInfo.mode.test(DxvkAllocationMode::NoFallback)) {
DxvkAllocationInfo fallbackInfo = allocationInfo; DxvkAllocationInfo fallbackInfo = allocationInfo;
fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
@ -890,8 +911,11 @@ namespace dxvk {
if (!allocation) { if (!allocation) {
vk->vkDestroyImage(vk->device(), image, nullptr); vk->vkDestroyImage(vk->device(), image, nullptr);
if (allocationInfo.mode.isClear()) {
logMemoryError(requirements.memoryRequirements); logMemoryError(requirements.memoryRequirements);
logMemoryStats(); logMemoryStats();
}
return nullptr; return nullptr;
} }

View File

@ -927,6 +927,23 @@ namespace dxvk {
}; };
/**
* \brief Allocation modes
*/
enum class DxvkAllocationMode : uint32_t {
/// If set, the allocation will fail if video memory is
/// full rather than falling back to system memory.
NoFallback = 0,
/// If set, the allocation will only succeed if it
/// can be suballocated from an existing chunk.
NoAllocation = 1,
eFlagEnum
};
using DxvkAllocationModes = Flags<DxvkAllocationMode>;
/** /**
* \brief Allocation properties * \brief Allocation properties
*/ */
@ -935,6 +952,8 @@ namespace dxvk {
uint64_t resourceCookie = 0u; uint64_t resourceCookie = 0u;
/// Desired memory property flags /// Desired memory property flags
VkMemoryPropertyFlags properties = 0u; VkMemoryPropertyFlags properties = 0u;
/// Allocation mode flags
DxvkAllocationModes mode = 0u;
}; };