1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-20 10:54:16 +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 committed by Philip Rebohle
parent 9a8406f28a
commit 3a1de271cb
3 changed files with 53 additions and 9 deletions

View File

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

View File

@ -579,6 +579,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
// of creating a new chunk. This way we avoid excessive fragmentation,
// especially when a multiple such resources are created at once.
@ -683,7 +687,8 @@ namespace dxvk {
if (likely(allocation && allocation->m_buffer))
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;
fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
@ -693,9 +698,21 @@ namespace dxvk {
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
// 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 ",
allocation->m_type->index, " without global buffer"));
}
@ -730,14 +747,15 @@ namespace dxvk {
|| (allocation->m_address & requirements.memoryRequirements.alignment))
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;
fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
allocation = allocateMemory(requirements.memoryRequirements, fallbackInfo);
}
if (!allocation) {
if (!allocation && allocationInfo.mode.isClear()) {
logMemoryError(requirements.memoryRequirements);
logMemoryStats();
}
@ -818,7 +836,8 @@ namespace dxvk {
if (!(createInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
// 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 };
dedicatedInfo.image = image;
@ -828,7 +847,8 @@ namespace dxvk {
// 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
&& (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
&& !allocationInfo.mode.test(DxvkAllocationMode::NoFallback)
&& (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
DxvkAllocationInfo fallbackInfo = allocationInfo;
fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
@ -848,7 +868,8 @@ namespace dxvk {
// Try to suballocate memory and fall back to system memory on error.
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;
fallbackInfo.properties &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
@ -888,8 +909,11 @@ namespace dxvk {
if (!allocation) {
vk->vkDestroyImage(vk->device(), image, nullptr);
logMemoryError(requirements.memoryRequirements);
logMemoryStats();
if (allocationInfo.mode.isClear()) {
logMemoryError(requirements.memoryRequirements);
logMemoryStats();
}
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
*/
@ -935,6 +952,8 @@ namespace dxvk {
uint64_t resourceCookie = 0u;
/// Desired memory property flags
VkMemoryPropertyFlags properties = 0u;
/// Allocation mode flags
DxvkAllocationModes mode = 0u;
};