mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-11-05 12:20:07 +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;
|
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()
|
static void TestBudget()
|
||||||
{
|
{
|
||||||
wprintf(L"Testing budget...\n");
|
wprintf(L"Testing budget...\n");
|
||||||
@ -5200,6 +5396,7 @@ void Test()
|
|||||||
#if VMA_DEBUG_INITIALIZE_ALLOCATIONS
|
#if VMA_DEBUG_INITIALIZE_ALLOCATIONS
|
||||||
TestAllocationsInitialization();
|
TestAllocationsInitialization();
|
||||||
#endif
|
#endif
|
||||||
|
TestMemoryUsage();
|
||||||
TestBudget();
|
TestBudget();
|
||||||
TestMapping();
|
TestMapping();
|
||||||
TestDeviceLocalMapped();
|
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.
|
- 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,
|
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
|
VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF
|
||||||
} VmaMemoryUsage;
|
} VmaMemoryUsage;
|
||||||
|
|
||||||
@ -16491,6 +16498,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
|
|||||||
|
|
||||||
uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
|
uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
|
||||||
uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
|
uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
|
||||||
|
uint32_t notPreferredFlags = 0;
|
||||||
|
|
||||||
// Convert usage to requiredFlags and preferredFlags.
|
// Convert usage to requiredFlags and preferredFlags.
|
||||||
switch(pAllocationCreateInfo->usage)
|
switch(pAllocationCreateInfo->usage)
|
||||||
@ -16517,7 +16525,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
|
|||||||
requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
|
requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
|
||||||
preferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
preferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||||
break;
|
break;
|
||||||
|
case VMA_MEMORY_USAGE_CPU_COPY:
|
||||||
|
notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
VMA_ASSERT(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16536,7 +16548,8 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
|
|||||||
if((requiredFlags & ~currFlags) == 0)
|
if((requiredFlags & ~currFlags) == 0)
|
||||||
{
|
{
|
||||||
// Calculate cost as number of bits from preferredFlags not present in this memory type.
|
// 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.
|
// Remember memory type with lowest cost.
|
||||||
if(currCost < minCost)
|
if(currCost < minCost)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user