diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index 8678532..fa9f76c 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -961,6 +961,12 @@ typedef enum VmaAllocationCreateFlagBits { memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. */ VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, + /** \brief Set this flag if the allocated memory will have aliasing resources. + * + Usage of this flag prevents supplying `VkMemoryDedicatedAllocateInfoKHR` when VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT is specified. + Otherwise created dedicated memory will not be suitable for aliasing resources, resulting in Vulkan Validation Layer errors. + */ + VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT = 0x00000200, /** Allocation strategy that chooses smallest possible free range for the allocation. @@ -6877,6 +6883,7 @@ private: bool withinBudget, bool map, bool isUserDataString, + bool canAliasMemory, void* pUserData, float priority, VkBuffer dedicatedBuffer, @@ -15152,6 +15159,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0, (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0, finalCreateInfo.pUserData, finalCreateInfo.priority, dedicatedBuffer, @@ -15197,6 +15205,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0, (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0, finalCreateInfo.pUserData, finalCreateInfo.priority, dedicatedBuffer, @@ -15226,6 +15235,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( bool withinBudget, bool map, bool isUserDataString, + bool canAliasMemory, void* pUserData, float priority, VkBuffer dedicatedBuffer, @@ -15252,19 +15262,22 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( allocInfo.allocationSize = size; #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; - if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(!canAliasMemory) { - if(dedicatedBuffer != VK_NULL_HANDLE) + VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE); - dedicatedAllocInfo.buffer = dedicatedBuffer; - VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); - } - else if(dedicatedImage != VK_NULL_HANDLE) - { - dedicatedAllocInfo.image = dedicatedImage; - VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); + if(dedicatedBuffer != VK_NULL_HANDLE) + { + VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE); + dedicatedAllocInfo.buffer = dedicatedBuffer; + VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); + } + else if(dedicatedImage != VK_NULL_HANDLE) + { + dedicatedAllocInfo.image = dedicatedImage; + VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); + } } } #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 diff --git a/src/Tests.cpp b/src/Tests.cpp index 34bbd26..44efe30 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -5627,6 +5627,77 @@ static void TestAliasing() vkDestroyImage(g_hDevice, img1, g_Allocs); } +static void TestAllocationAliasing() +{ + wprintf(L"Testing allocation aliasing...\n"); + + /* + * Test whether using VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT suppress validation layer error + * by don't supplying VkMemoryDedicatedAllocateInfoKHR to creation of dedicated memory + * that will be used to alias with some other textures. + */ + + VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + + VmaAllocationCreateInfo allocationCreateInfo = {}; + allocationCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + + // Bind 2 textures together into same memory without VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT and then with flag set + /* + { + VkImage originalImage; + VmaAllocation allocation; + imageInfo.extent.width = 640; + imageInfo.extent.height = 480; + VkResult res = vmaCreateImage(g_hAllocator, &imageInfo, &allocationCreateInfo, &originalImage, &allocation, nullptr); + TEST(res == VK_SUCCESS); + + VkImage aliasingImage; + imageInfo.extent.width = 480; + imageInfo.extent.height = 256; + res = vkCreateImage(g_hDevice, &imageInfo, nullptr, &aliasingImage); + TEST(res == VK_SUCCESS); + // After binding there should be inevitable validation layer error VUID-vkBindImageMemory-memory-01509 + res = vmaBindImageMemory(g_hAllocator, allocation, aliasingImage); + TEST(res == VK_SUCCESS); + + vkDestroyImage(g_hDevice, aliasingImage, nullptr); + vmaDestroyImage(g_hAllocator, originalImage, allocation); + } + */ + allocationCreateInfo.flags |= VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT; + { + VkImage originalImage; + VmaAllocation allocation; + imageInfo.extent.width = 640; + imageInfo.extent.height = 480; + VkResult res = vmaCreateImage(g_hAllocator, &imageInfo, &allocationCreateInfo, &originalImage, &allocation, nullptr); + TEST(res == VK_SUCCESS); + + VkImage aliasingImage; + imageInfo.extent.width = 480; + imageInfo.extent.height = 256; + res = vkCreateImage(g_hDevice, &imageInfo, nullptr, &aliasingImage); + TEST(res == VK_SUCCESS); + // Now with VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT flag validation error is no more + res = vmaBindImageMemory(g_hAllocator, allocation, aliasingImage); + TEST(res == VK_SUCCESS); + + vkDestroyImage(g_hDevice, aliasingImage, nullptr); + vmaDestroyImage(g_hAllocator, originalImage, allocation); + } +} + static void TestMapping() { wprintf(L"Testing mapping...\n"); @@ -6885,6 +6956,7 @@ void Test() TestDeviceCoherentMemory(); TestBudget(); TestAliasing(); + TestAllocationAliasing(); TestMapping(); TestDeviceLocalMapped(); TestMappingMultithreaded(); @@ -6908,12 +6980,15 @@ void Test() fclose(file); } - TestDefragmentationSimple(); - TestDefragmentationFull(); - TestDefragmentationWholePool(); - TestDefragmentationGpu(); - TestDefragmentationIncrementalBasic(); - TestDefragmentationIncrementalComplex(); + if(ConfigType >= CONFIG_TYPE_AVERAGE) + { + TestDefragmentationSimple(); + TestDefragmentationFull(); + TestDefragmentationWholePool(); + TestDefragmentationGpu(); + TestDefragmentationIncrementalBasic(); + TestDefragmentationIncrementalComplex(); + } // # Detailed tests FILE* file;