Vulkan系列教程—VMA教程(九)—虚拟分配器

  • Post author:
  • Post category:其他





前言


本文为

Vulkan® Memory Allocator

系列系列教程,定时更新,请大家关注。如果需要深入学习Vulkan的同学,可以点击课程链接,学习链接


Vulkan学习群:594715138


CSDN课程链接



《Vulkan原理与实战—铸造渲染核武器—基石篇》




Virtual Allocator

VMA有一个额外的特性,其核心的分配算法通过一套叫做“Virtual Allocator”来导出给用户使用。这个功能是说,通常使用VMA我们都碰不到Pool当中的内存块儿(blocks),但是现在我们可以独立一块block进行操作了。当然,这样的内存块你可以拿来做各种需求,甚至跟Vulkan无关。



一、生成Virtual Block

为了使用这个功能,VMA并没有给到我们一个Allocator这样的对象。我们所需要做的就是创建一个单独的

VmaVirtualBlock

来代表(管理)我们想创建的每一个内存块(block)。

  1. 填写

    VmaVirtualBlockCreateInfo

    结构体。
  2. 调用

    vmaCreateVirtualBlock

    ()来创建新的

    VmaVirtualBlock

    对象。


代码如下(示例):

VmaVirtualBlockCreateInfo blockCreateInfo = {};
blockCreateInfo.size = 1048576; // 1 MB
 
VmaVirtualBlock block;
VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &block);



二、分配Virtual Allocation


VmaVirtualBlock

这个结构体,内部会追踪其分配出去的内存(Occupied Regions)与空闲的内存(Free Region),它与

VMA

核心的

Allocator

使用的是同一套分配代码。当你需要分配一个Allocation的时候,传入一个

VkDeviceSize

参数引用,这个量会被用作Offset(相对于当前这个Block)。

为了创建这样一个Allocation,我们需要:

  1. 填写

    VmaVirtualAllocationCreateInfo

    结构体。
  2. 调用

    vmaVirtualAllocate

    ()函数。从其中获得

    VkDeviceSize offset

    作为本Allocation的起点。


代码如下(示例):

VmaVirtualAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.size = 4096; // 4 KB
 
VkDeviceSize allocOffset;
res = vmaVirtualAllocate(block, &allocCreateInfo, &allocOffset);
if(res == VK_SUCCESS)
{
    // Use the 4 KB of your memory starting at allocOffset.
}
else
{
    // Allocation failed - no space for it could be found. Handle this error!
}



三、内存释放(Deallocation)

当Allocation不再需要的时候,我们可以调用

vmaVirtualFree

()来释放内存。你只能够将需要释放的Offset传入(这个Offset就代表了这块内存了)。

当整个Block都不再需要了,你可以通过调用

vmaDestroyVirtualBlock

()来释放整个Block。但是你必须在释放Block之前,先将每一个Allocation都释放掉。如果你不想一个个手动释放Allocation,那就需要调用

vmaClearVirtualBlock

()来释放本Block当中的所有Allocation(这个特性在普通的VMA分配器中是没有的)。


代码如下(示例):

vmaVirtualFree(block, allocOffset);
vmaDestroyVirtualBlock(block)



四、分配携带参数(Allocation parameters)

你可以使用

vmaSetVirtualAllocationUserData

()来向已经分配的Allocation中设置用户参数。其默认的参数是null。与之前讲过的用户参数相同,它可以被传入各种各样的用户信息。


代码如下(示例):

struct CustomAllocData
{
    std::string m_AllocName;
};
CustomAllocData* allocData = new CustomAllocData();
allocData->m_AllocName = "My allocation 1";
vmaSetVirtualAllocationUserData(block, allocOffset, allocData);

这个指针可以在后面被获取到,通过调用

vmaGetVirtualAllocationInfo

(),相关信息会被填写到

VmaVirtualAllocationInfo

这个结构当中。注意!当你新new了一个对象,把它传进去作为用户参数,可别忘了在Allocation被释放后,手动释放自己的这块对象内存哦。


代码如下(示例):

VmaVirtualAllocationInfo allocInfo;
vmaGetVirtualAllocationInfo(block, allocOffset, &allocInfo);
delete (CustomAllocData*)allocInfo.pUserData;
 
vmaVirtualFree(block, allocOffset);



五、内存对齐与单位(Alignment and units)

使用Bytes(字节)来作为Size跟Offset的单位,看上去很自然。如果有一个Allocation,需要被对齐到一个数字上(比如4Byte),你可以使用一个可选参数来设置,即

VmaVirtualAllocationCreateInfo::alignment


代码如下(示例):

VmaVirtualAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.size = 4096; // 4 KB
allocCreateInfo.alignment = 4; // Returned offset must be a multiply of 4 B
 
VkDeviceSize allocOffset;
res = vmaVirtualAllocate(block, &allocCreateInfo, &allocOffset);



六、静态信息(Statistics)

你可以通过

vmaCalculateVirtualBlockStats

()来获取一个Block的静态信息。这个函数会填充

VmaStatInfo

这个结构体—就像VMA通常使用的一样。


代码如下(示例):


VmaStatInfo statInfo;
vmaCalculateVirtualBlockStats(block, &statInfo);
printf("My virtual block has %llu bytes used by %u virtual allocations\n",
    statInfo.usedBytes, statInfo.allocationCount);

你也可以通过

vmaBuildVirtualBlockStatsString

()获取到一个Block的所有信息,并且以

JSON

形式给到。拿到的String必须在后面通过

vmaFreeVirtualBlockStatsString

()释放掉。



七、额外考量(Additional considerations)



Virtual Allocator

”这一组功能,是在一个单独的Block上操作的。用户需要自己维护所有的Blocks,当一个Block不足够分配的时候还需要做新的Block,删除空白的Block以及决策一个新的Allocation分配到底优先选取哪一个Block。

系统也给到了一些可选的分配算法,就好像用户自定义内存池里面讲述的。你可以在

VmaVirtualBlockCreateFlagBits

里面找到各种Flags。你可以在

Custom Memory Pool(用户自定义内存池)

这一章找到算法解释。



总结


以上就是今天的内容,大家对于vulkan的学习,也可以参考我出品的vulkan系列教程,下面给大家贴出链接。

请大家移步CSDN站内进行学习:


CSDN课程链接



《Vulkan原理与实战—铸造渲染核武器—基石篇》



版权声明:本文为weixin_50523841原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。