Vulkan系列教程—VMA教程(一)—快速上手VMA
  PnX1wBG0sNlo 2023年11月02日 154 0

前言

VMA(Vulkan Memory Allocator),是AMD提供的Vulkan内存分配管理器,那么Vulkan的内存分配为何要使用VMA这种内存分配器呢?原因就在于其显存的分配次数是有限的(比如4096次),那么我们就需要分配一整块显存,然后自己使用offset以及size来进行分割使用,这个过程冗长繁杂,而且容易出错,那么VMA就成为了我们管理Vulkan内存的首要选择

一、工程安装

Vulkan Memory Allocator属于单头文件的“stb-style”风格库。你不需要单独去构建它,只需要把头文件加入到工程里就好了。

Single Header”并不意味着所有功能都已经作为了inline函数,而是说需要用预编译宏来导出这些函数,如果你不使用宏来导出函数就会遇到链接错误。

引入方法

1 包含“ vk_mem_alloc.h ”头文件到任何一个用得到vma的cpp文件当中,这样vma的各种成员声明就可以完成了。

2 在其中一个cpp文件当中,开启如下的宏定义。

#define VMA_IMPLEMENTATION
#include "vk_mem_alloc.h"

对于使用者而言,可能单独创建一个cpp文件,专门用来书写上述代码,即专门用来导出VMA的成员实现(比如命名为vmaExporter.cpp)。

这个库的头文件里面已经包含了<vulkan/vulkan.h>,因此也间接包含了<windows.h>,在这两个头文件之前如果你需要定义一些宏来启用/关闭特性,那么请在vma头文件引入之前来定义。

对于VMA而言,库内部肯定会调用vulkan的函数,那么你的工程对于vulkan方面的配置就可以如下灵活处理:

1 默认情况下(推荐):

vma是认为你链接了vulkan的静态库(lib),则直接就调用vulkan函数,随后在编译期间就顺利链接(link),即无脑模式。

如果你不是用的vulkan静态库,就可以在vma头文件引入之前,做一个声明

#define VMA_STATIC_VULKAN_FUNCTIONS 0

然后就可以开启下面的引入方法了。

2 自动获取Vulkan函数:

你可以定义:

#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1:

然后使用VmaAllocatorCreateinfo当中的pVulkanFunction这个成员变量,这个变量其实指向的是一个结构体:

typedef struct VmaVulkanFunctions
{
/// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS.
PFN_vkGetInstanceProcAddr VMA_NULLABLE vkGetInstanceProcAddr;
/// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS.
PFN_vkGetDeviceProcAddr VMA_NULLABLE vkGetDeviceProcAddr;
PFN_vkGetPhysicalDeviceProperties VMA_NULLABLE vkGetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceMemoryProperties VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties;
PFN_vkAllocateMemory VMA_NULLABLE vkAllocateMemory;
PFN_vkFreeMemory VMA_NULLABLE vkFreeMemory;
PFN_vkMapMemory VMA_NULLABLE vkMapMemory;
//以下省略---------------------------------
}

这是vma定义的结构体,用来规定每一个Vulkan函数对应的函数指针,在其中,指定下vkGetInstanceProcAddrvkGetDeviceProcAddr两个函数,vma就会自动把其他的vulkan函数给获取出来了。

3 全面赋值:

你甚至可以自己手动去填写上方的哪个结构体,直接为每一个vulkan的函数指定其函数指针。

二、初始化

在程序开始的时候:

1 初始化vulkan,生成VkPhysicalDevice,VkDevice与VkInstance等对象。

2 填写VmaAllocatorCreateInfo,随后使用vmaCreateAllocator创建一个VmaAllocator

VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;

allocatorInfo.physicalDevice = physicalDevice;
allocatorInfo.device = device;
allocatorInfo.instance = instance;

VmaAllocator allocator;
vmaCreateAllocator(&allocatorInfo, &allocator);

如上所示,你需要指定你使用的vulkan版本,当然你也可以通过VmaAllocatorCreateInfo::flags 指定你要开启的vma扩展(这个我们后面详细讲解),否则vma会默认使用vulkan的1.0内核并且无扩展开启。

三、资源分配小案例

当你想生成一个buffer或者image

  • 填写VkBufferCreateInfo/VkImageCreateInfo结构体;
  • 填写VmaAllocationCreateInfo结构体。
  • 调用vmaCreateBuffer/vmaCreateImage来获取内存,并且完成vkImage/vkBuffer与相应内存的绑定操作(Bind):
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferInfo.size = 65536;
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;

VmaAllocationCreateInfo allocInfo = {};
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;

VkBuffer buffer;
VmaAllocation allocation;
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);

别忘了在你不需要这块内存的时候,对它进行回收哦:

vmaDestroyBuffer(allocator, buffer, allocation);
vmaDestroyAllocator(allocator);

总结

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

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

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

PnX1wBG0sNlo