Overview
Vulkan
将内存管理的工作交给了开发者自己负责,如何分配内存,如何指定内存策略都是由开发者自己决定的,当然出了问题也是由开发者自己负责的
Vulkan
将内存划分为两大类:主机内存(Host Memory) 和设备内存(Device Memory)
在移动设备上,主机内存就是 CPU
内存,设备内存就是GPU
显存,在此基础上,每种内存类型还可以按照属性进一步划分
Vulkan
提供了一种透明的机制来显示内存的细节和相关属性,这样做在 opengl-es
中是完全不可能的,后者不允许应用程序显式的控制内存区域和布局
Vulkan
中系统的内存有四种类型(并不是所有设备都支持这个四种类型):
Host Local Memory
,只对Host
可见的内存,通常称之为普通内存(可以理解为操作系统的内存)Device Local Memory
,只对Device
可见的内存,通常称之为显存(可以理解为显卡上的显存)Host Local Device Memory
,由Host
管理的,对Device
可见的内存Device Local Host Memory
,由Device
管理的,对Host
可见的内存
对比这两种内存类型,主机内存(Host
)比设备内存(Device
)更慢,但是Host Memory
通常容量更大(也就是一般显存速度更快,但是容量更小)
设备内存,它对物理设备是直接可见的,物理设备可以直接读取其中的内存区块,设备内存和物理设备之间的关系十分紧密,因此它的性能比宿主机内存更高
VkImage
,VkBuffer
,以及一致性的缓存对象Uniform Buffer
都是从设备内存端分配的
单一的物理设备可能有多种类型的内存,根据它们的堆类型以及属性的不同还可能进一步细分
枚举内存信息
使用 vkGetPhysicalDeviceMemoryProperties
获取设备的内存信息,其函数定义如下:
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties(
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties* pMemoryProperties);
其中 physicalDevice
就是创建的物理设备,VkPhysicalDeviceMemoryProperties
定义如下:
typedef struct VkPhysicalDeviceMemoryProperties {
// 内存类型数量和信息
uint32_t memoryTypeCount;
VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES];
// 内存堆数量和信息
uint32_t memoryHeapCount;
VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS];
} VkPhysicalDeviceMemoryProperties;
memoryTypeCount
表示支持的内存类型数量memoryTypes
有效元素个数为memoryTypeCount
的内存类型信息数组memoryHeapCount
表示支持的内存堆数量memoryHeaps
有效元素是memoryHeapCount
内存堆信息数组
其中 VkMemoryType
类型定义:
typedef struct VkMemoryType {
VkMemoryPropertyFlags propertyFlags;
uint32_t heapIndex;
} VkMemoryType;
propertyFlags
内存类型标志位。heapIndex
对应的memoryHeaps
堆索引。
中 propertyFlags
有效值被定义在了 VkMemoryPropertyFlagBits
枚举中,其定义如下:
typedef enum VkMemoryPropertyFlagBits {
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004,
VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008,
VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,
VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020,
VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD = 0x00000040,
VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 0x00000080,
VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV = 0x00000100,
VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkMemoryPropertyFlagBits;
typedef VkFlags VkMemoryPropertyFlags;
-
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
表示该内存设备上分配的内存可以被物理设备高效访问,只有对应的堆为VK_MEMORY_HEAP_DEVICE_LOCAL_BIT
才会有该内存类型(Device
内存) -
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
表示该内存设备上分配的内存将自动进行同步,不需要手动调用vkFlushMappedMemoryRanges
和vkInvalidateMappedMemoryRanges
来进行内存同步 -
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
表示在此内存类型上分配的内存可被 Host 端通过vkMapMemory
函数进行映射,进而进行访问 -
VK_MEMORY_PROPERTY_HOST_CACHED_BIT
表示该内存类型上分配的内存为缓存类型,Host
端访问缓存的内存类型会比较快,但是非缓存内存总是同步内存(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
) -
VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
表示在此内存类型上分配的内存只有物理设备可访问
内存类型不能同时为VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
和VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
下图表示了 memory_type
和 相应的标志位之间的关系:
另外的 VkMemoryHeap
的类型定义如下图所示:
typedef struct VkMemoryHeap