mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-11-26 22:10:05 +00:00
Add VMA_MEMORY_USAGE_CPU_COPY for memory that is preferably not DEVICE_LOCAL but not guaranteed to be HOST_VISIBLE
Also added test for memory types and usages.
This commit is contained in:
parent
a900b56aed
commit
efa88c4de0
197
src/Tests.cpp
197
src/Tests.cpp
@ -3870,6 +3870,202 @@ static inline bool MemoryRegionsOverlap(char* ptr1, size_t size1, char* ptr2, si
|
||||
return true;
|
||||
}
|
||||
|
||||
static void TestMemoryUsage()
|
||||
{
|
||||
wprintf(L"Testing memory usage:\n");
|
||||
|
||||
static const VmaMemoryUsage lastUsage = VMA_MEMORY_USAGE_CPU_COPY;
|
||||
for(uint32_t usage = 0; usage <= lastUsage; ++usage)
|
||||
{
|
||||
switch(usage)
|
||||
{
|
||||
case VMA_MEMORY_USAGE_UNKNOWN: printf(" VMA_MEMORY_USAGE_UNKNOWN:\n"); break;
|
||||
case VMA_MEMORY_USAGE_GPU_ONLY: printf(" VMA_MEMORY_USAGE_GPU_ONLY:\n"); break;
|
||||
case VMA_MEMORY_USAGE_CPU_ONLY: printf(" VMA_MEMORY_USAGE_CPU_ONLY:\n"); break;
|
||||
case VMA_MEMORY_USAGE_CPU_TO_GPU: printf(" VMA_MEMORY_USAGE_CPU_TO_GPU:\n"); break;
|
||||
case VMA_MEMORY_USAGE_GPU_TO_CPU: printf(" VMA_MEMORY_USAGE_GPU_TO_CPU:\n"); break;
|
||||
case VMA_MEMORY_USAGE_CPU_COPY: printf(" VMA_MEMORY_USAGE_CPU_COPY:\n"); break;
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
auto printResult = [](const char* testName, VkResult res, uint32_t memoryTypeBits, uint32_t memoryTypeIndex)
|
||||
{
|
||||
if(res == VK_SUCCESS)
|
||||
printf(" %s: memoryTypeBits=0x%X, memoryTypeIndex=%u\n", testName, memoryTypeBits, memoryTypeIndex);
|
||||
else
|
||||
printf(" %s: memoryTypeBits=0x%X, FAILED with res=%d\n", testName, memoryTypeBits, (int32_t)res);
|
||||
};
|
||||
|
||||
// 1: Buffer for copy
|
||||
{
|
||||
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bufCreateInfo.size = 65536;
|
||||
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
VkBuffer buf = VK_NULL_HANDLE;
|
||||
VkResult res = vkCreateBuffer(g_hDevice, &bufCreateInfo, g_Allocs, &buf);
|
||||
TEST(res == VK_SUCCESS && buf != VK_NULL_HANDLE);
|
||||
|
||||
VkMemoryRequirements memReq = {};
|
||||
vkGetBufferMemoryRequirements(g_hDevice, buf, &memReq);
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||
allocCreateInfo.usage = (VmaMemoryUsage)usage;
|
||||
VmaAllocation alloc = VK_NULL_HANDLE;
|
||||
VmaAllocationInfo allocInfo = {};
|
||||
res = vmaAllocateMemoryForBuffer(g_hAllocator, buf, &allocCreateInfo, &alloc, &allocInfo);
|
||||
if(res == VK_SUCCESS)
|
||||
{
|
||||
TEST((memReq.memoryTypeBits & (1u << allocInfo.memoryType)) != 0);
|
||||
res = vkBindBufferMemory(g_hDevice, buf, allocInfo.deviceMemory, allocInfo.offset);
|
||||
TEST(res == VK_SUCCESS);
|
||||
}
|
||||
printResult("Buffer TRANSFER_DST + TRANSFER_SRC", res, memReq.memoryTypeBits, allocInfo.memoryType);
|
||||
vmaDestroyBuffer(g_hAllocator, buf, alloc);
|
||||
}
|
||||
|
||||
// 2: Vertex buffer
|
||||
{
|
||||
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bufCreateInfo.size = 65536;
|
||||
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
|
||||
VkBuffer buf = VK_NULL_HANDLE;
|
||||
VkResult res = vkCreateBuffer(g_hDevice, &bufCreateInfo, g_Allocs, &buf);
|
||||
TEST(res == VK_SUCCESS && buf != VK_NULL_HANDLE);
|
||||
|
||||
VkMemoryRequirements memReq = {};
|
||||
vkGetBufferMemoryRequirements(g_hDevice, buf, &memReq);
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||
allocCreateInfo.usage = (VmaMemoryUsage)usage;
|
||||
VmaAllocation alloc = VK_NULL_HANDLE;
|
||||
VmaAllocationInfo allocInfo = {};
|
||||
res = vmaAllocateMemoryForBuffer(g_hAllocator, buf, &allocCreateInfo, &alloc, &allocInfo);
|
||||
if(res == VK_SUCCESS)
|
||||
{
|
||||
TEST((memReq.memoryTypeBits & (1u << allocInfo.memoryType)) != 0);
|
||||
res = vkBindBufferMemory(g_hDevice, buf, allocInfo.deviceMemory, allocInfo.offset);
|
||||
TEST(res == VK_SUCCESS);
|
||||
}
|
||||
printResult("Buffer TRANSFER_DST + VERTEX_BUFFER", res, memReq.memoryTypeBits, allocInfo.memoryType);
|
||||
vmaDestroyBuffer(g_hAllocator, buf, alloc);
|
||||
}
|
||||
|
||||
// 3: Image for copy, OPTIMAL
|
||||
{
|
||||
VkImageCreateInfo imgCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
imgCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imgCreateInfo.extent.width = 256;
|
||||
imgCreateInfo.extent.height = 256;
|
||||
imgCreateInfo.extent.depth = 1;
|
||||
imgCreateInfo.mipLevels = 1;
|
||||
imgCreateInfo.arrayLayers = 1;
|
||||
imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
imgCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imgCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkImage img = VK_NULL_HANDLE;
|
||||
VkResult res = vkCreateImage(g_hDevice, &imgCreateInfo, g_Allocs, &img);
|
||||
TEST(res == VK_SUCCESS && img != VK_NULL_HANDLE);
|
||||
|
||||
VkMemoryRequirements memReq = {};
|
||||
vkGetImageMemoryRequirements(g_hDevice, img, &memReq);
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||
allocCreateInfo.usage = (VmaMemoryUsage)usage;
|
||||
VmaAllocation alloc = VK_NULL_HANDLE;
|
||||
VmaAllocationInfo allocInfo = {};
|
||||
res = vmaAllocateMemoryForImage(g_hAllocator, img, &allocCreateInfo, &alloc, &allocInfo);
|
||||
if(res == VK_SUCCESS)
|
||||
{
|
||||
TEST((memReq.memoryTypeBits & (1u << allocInfo.memoryType)) != 0);
|
||||
res = vkBindImageMemory(g_hDevice, img, allocInfo.deviceMemory, allocInfo.offset);
|
||||
TEST(res == VK_SUCCESS);
|
||||
}
|
||||
printResult("Image OPTIMAL TRANSFER_DST + TRANSFER_SRC", res, memReq.memoryTypeBits, allocInfo.memoryType);
|
||||
|
||||
vmaDestroyImage(g_hAllocator, img, alloc);
|
||||
}
|
||||
|
||||
// 4: Image SAMPLED, OPTIMAL
|
||||
{
|
||||
VkImageCreateInfo imgCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
imgCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imgCreateInfo.extent.width = 256;
|
||||
imgCreateInfo.extent.height = 256;
|
||||
imgCreateInfo.extent.depth = 1;
|
||||
imgCreateInfo.mipLevels = 1;
|
||||
imgCreateInfo.arrayLayers = 1;
|
||||
imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
imgCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imgCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkImage img = VK_NULL_HANDLE;
|
||||
VkResult res = vkCreateImage(g_hDevice, &imgCreateInfo, g_Allocs, &img);
|
||||
TEST(res == VK_SUCCESS && img != VK_NULL_HANDLE);
|
||||
|
||||
VkMemoryRequirements memReq = {};
|
||||
vkGetImageMemoryRequirements(g_hDevice, img, &memReq);
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||
allocCreateInfo.usage = (VmaMemoryUsage)usage;
|
||||
VmaAllocation alloc = VK_NULL_HANDLE;
|
||||
VmaAllocationInfo allocInfo = {};
|
||||
res = vmaAllocateMemoryForImage(g_hAllocator, img, &allocCreateInfo, &alloc, &allocInfo);
|
||||
if(res == VK_SUCCESS)
|
||||
{
|
||||
TEST((memReq.memoryTypeBits & (1u << allocInfo.memoryType)) != 0);
|
||||
res = vkBindImageMemory(g_hDevice, img, allocInfo.deviceMemory, allocInfo.offset);
|
||||
TEST(res == VK_SUCCESS);
|
||||
}
|
||||
printResult("Image OPTIMAL TRANSFER_DST + SAMPLED", res, memReq.memoryTypeBits, allocInfo.memoryType);
|
||||
vmaDestroyImage(g_hAllocator, img, alloc);
|
||||
}
|
||||
|
||||
// 5: Image COLOR_ATTACHMENT, OPTIMAL
|
||||
{
|
||||
VkImageCreateInfo imgCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
imgCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imgCreateInfo.extent.width = 256;
|
||||
imgCreateInfo.extent.height = 256;
|
||||
imgCreateInfo.extent.depth = 1;
|
||||
imgCreateInfo.mipLevels = 1;
|
||||
imgCreateInfo.arrayLayers = 1;
|
||||
imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
imgCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imgCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkImage img = VK_NULL_HANDLE;
|
||||
VkResult res = vkCreateImage(g_hDevice, &imgCreateInfo, g_Allocs, &img);
|
||||
TEST(res == VK_SUCCESS && img != VK_NULL_HANDLE);
|
||||
|
||||
VkMemoryRequirements memReq = {};
|
||||
vkGetImageMemoryRequirements(g_hDevice, img, &memReq);
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||
allocCreateInfo.usage = (VmaMemoryUsage)usage;
|
||||
VmaAllocation alloc = VK_NULL_HANDLE;
|
||||
VmaAllocationInfo allocInfo = {};
|
||||
res = vmaAllocateMemoryForImage(g_hAllocator, img, &allocCreateInfo, &alloc, &allocInfo);
|
||||
if(res == VK_SUCCESS)
|
||||
{
|
||||
TEST((memReq.memoryTypeBits & (1u << allocInfo.memoryType)) != 0);
|
||||
res = vkBindImageMemory(g_hDevice, img, allocInfo.deviceMemory, allocInfo.offset);
|
||||
TEST(res == VK_SUCCESS);
|
||||
}
|
||||
printResult("Image OPTIMAL SAMPLED + COLOR_ATTACHMENT", res, memReq.memoryTypeBits, allocInfo.memoryType);
|
||||
vmaDestroyImage(g_hAllocator, img, alloc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void TestBudget()
|
||||
{
|
||||
wprintf(L"Testing budget...\n");
|
||||
@ -5200,6 +5396,7 @@ void Test()
|
||||
#if VMA_DEBUG_INITIALIZE_ALLOCATIONS
|
||||
TestAllocationsInitialization();
|
||||
#endif
|
||||
TestMemoryUsage();
|
||||
TestBudget();
|
||||
TestMapping();
|
||||
TestDeviceLocalMapped();
|
||||
|
@ -2278,6 +2278,13 @@ typedef enum VmaMemoryUsage
|
||||
- Any resources read or accessed randomly on host, e.g. CPU-side copy of vertex buffer used as source of transfer, but also used for collision detection.
|
||||
*/
|
||||
VMA_MEMORY_USAGE_GPU_TO_CPU = 4,
|
||||
/** CPU memory - memory that is preferably not `DEVICE_LOCAL`, but also not guaranteed to be `HOST_VISIBLE`.
|
||||
|
||||
Usage: Staging copy of resources moved from GPU memory to CPU memory as part
|
||||
of custom paging/residency mechanism, to be moved back to GPU memory when needed.
|
||||
*/
|
||||
VMA_MEMORY_USAGE_CPU_COPY = 5,
|
||||
|
||||
VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF
|
||||
} VmaMemoryUsage;
|
||||
|
||||
@ -16491,6 +16498,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
|
||||
|
||||
uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
|
||||
uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
|
||||
uint32_t notPreferredFlags = 0;
|
||||
|
||||
// Convert usage to requiredFlags and preferredFlags.
|
||||
switch(pAllocationCreateInfo->usage)
|
||||
@ -16517,7 +16525,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
|
||||
requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
|
||||
preferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
break;
|
||||
case VMA_MEMORY_USAGE_CPU_COPY:
|
||||
notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
break;
|
||||
default:
|
||||
VMA_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -16536,7 +16548,8 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
|
||||
if((requiredFlags & ~currFlags) == 0)
|
||||
{
|
||||
// Calculate cost as number of bits from preferredFlags not present in this memory type.
|
||||
uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags);
|
||||
uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags) +
|
||||
VmaCountBitsSet(currFlags & notPreferredFlags);
|
||||
// Remember memory type with lowest cost.
|
||||
if(currCost < minCost)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user