内存分类
Vulkan 的内存分为两类: 宿主机内存 和 设备内存。
两种内存的特点:
- 宿主机内存 访问速度慢 ,但可分配空间大。
- 设备内存 直接对设备可见的,可分配空间小,但访问速度快。
宿主机内存
Vulkan 通过宿主机内存来存储API 的内部数据结构, Vulkan 允许程序控制宿主机端的内存分配,宿主机的内存管理通过以下数据结构来完成:
typedef struct VkAllocationCallbacks {
Void* pUserData;
PFN_vkAllocationFunction pfnAllocation;
PFN_vkReallocationFunction pfnReallocation;
PFN_vkFreeFunction pfnFree;
PFN_vkInternalAllocationNotification pfnInternalAlloc;
PFN_vkInternalFreeNotification pfnInternalFree;
} VkAllocationCallbacks ;
设备内存
设备内存, 即GPU 内存,它对于物理设备是直接可见的, 物理设备可以直接读取其中的内存区块。图像对象,缓存对象,以及一致变量的缓存对象都是在设备内存端分配的。
单一设备可能有多种内存类型,根据堆类型以及属性的不同还可以进一步细分。
查询内存堆和属性的函数:
void vkGetPhysicalDeviceMemoryProperties(
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties* pMemoryProperties
);
typedef struct VkPhysicalDeviceMemoryProperties {
Uint32_t memoryTypeCount;
VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES];
Uint32_t memoryHeapCount;
VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS];
} VkPhysicalDeviceMemoryProperties;
- 内存类型
typedef struct VkMomoryType {
VkMemoryPropteryFlags propertyFlags; // 属性
uint32_t heapIndex; // 堆索引号
} VkMemoryType;
注意 HOST_COHERENT_BIT , HOST_CACHED_BIT 和 LAZILY_ALLOCATED_BIT 的用法。
LAZILY_ALLOCATED_BIT 只能被设备端访问,与HOST_PROPERTY_HOST_VISIBLE_BIT 和 HOST_COHERENT_BIT 条件排斥。
- 内存堆
typedef struct VkMemoryHeap {
VkDeviceSize size; //堆的大小
VkMemoryHeapFlags flags; //堆的属性
} VkMemoryHeap;
typedef enum VkMemoryHeapFlagBits {
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002,
VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT,
VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkMemoryHeapFlagBits;
分配内存
VkResult vkAllocateMemory (
VkDevice device;
const VkMemoryAllocateInfo* allocateInfo,
const VkAllocationCallbacks* allocator,
VkDeviceMemory* memory
);
typedef struct VkMemoryAllocateInfo {
VkStructureType type;
Const void* pNext;
VkDeviceSize allocationSize;
uint32_t momoryTypeIndex; // 内存类型索引
} VkMemoryAllocateInfo;
注意: 物理设备内存端的可分配对象的数量是有限的,可以通过 VkPhysicalDeviceLimits 成员的 maxMemoryAllocationCount 查询 (4096 )。
释放内存
Void VkFreeMemory (
VkDevice device,
VkDeviceMemory memory,
const VkAllocationCallbacks* allocator
);
从宿主机访问设备内存
宿主机只能访问那些支持映射的内存类型 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,通过 vkMapMemory() 来实现宿主机对设备内存的映射访问。
VkResult vkMapMemory (
VkDevice device;
VkDeviceMemory memory,
VkDeviceSize offset,
VkDeviceSize size,
VkMemoryMapFlags flags,
Void** ppData
);
注意 :函数 VkMapMemory 不会检查内存区域是否被映射过,应用程序需要管理映射内存对象,访问已经映射的内存可能会导致无法预测的行为,甚至导致驱动程序死机。
当更新完内容后,通过结束映射使设备修改的内容反射回设备端。
当更新完内容后,通过结束映射使设备修改的内容反射回设备端。
Void vkUnMapMemory( VkDevice device, VkDeviceMemory memory);
映射过的内存需不需要再次映射?