在 Vulkan 中,VkBuffer
和 VkDeviceMemory
是两个不同的概念,但它们通常是一起绑定在一起用的
-
VkBuffer
: 表示一个缓冲区对象。VkBuffer
本身只是逻辑上的概念,它不包含实际的数据存储,也不关心数据在内存中的具体位置。它是靠vkBindBufferMemory()
函数绑定VkDeviceMemory
,来关联具体显存资源的,也就是说,真正资源用VkDeviceMemory
存储的 -
VkDeviceMemory
: 设备内存对象(GPU显存),用于实际存储和管理 Vulkan 缓冲区对象的数据。一旦完成跟VkBuffer的绑定,它几乎就不太需要用到了,直接使用VkBuffer对象即可。但在后续资源销毁和释放的时候,需要调用vkDestroyBuffer()
和vkFreeMemory()
分别销毁VkBuffer对象和vkDeviceMemory
一般的分配显存流程是:
-
使用
vkCreateBuffer()
函数创建一个VkBuffer
对象,定义了缓冲区的大小、用途等属性。再次强调,它并不包含任何指向实际显存块的指针,只是一些信息VkBuffer vkBuffer; VkBufferCreateInfo bufferCreateInfo= {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = bufferSize; bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &vkBuffer);
-
使用
vkGetBufferMemoryRequirements()
函数从vkBuffer对象中获取缓冲区的内存需求信息,包括内存大小、对齐要求等。VkMemoryRequirements memoryRequirements; vkGetBufferMemoryRequirements(logicalDevice, vkBuffer, &memoryRequirements);
-
使用
vkAllocateMemory()
函数为缓冲区分配实际的设备内存(VkDeviceMemory
),并将该内存与缓冲区关联起来。VkMemoryAllocateInfo allocateInfo = {}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, properties); vkAllocateMemory(logicalDevice, &allocateInfo, nullptr, &vkDeviceMemory);
-
最后,使用
vkBindBufferMemory()
函数将缓冲区对象和分配的设备内存关联起来,使得vkBuffer
能够真的称为这块显存区域图像数据的handle。vkBindBufferMemory(device, vkBuffer, vkDeviceMemory, 0);
简化这个过程可以引入VMA(Vulkan Memory Allocator)
github地址:https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
简单用法:
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_AUTO;
VkBuffer buffer;
VmaAllocation allocation;
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
vmaCreateBuffer()
函数调用实际做的工作为:
- 创建 VkBuffer。
- 根据需要分配 VkDeviceMemory 块。
- 将内存块的未使用区域绑定到此缓冲区。
VmaAllocation
是一个表示绑定到vkBuffer的已分配的内存。可以被用来获取 VkDeviceMemory
句柄和偏移量等参数。