天天看點

Vulkan 記憶體

記憶體分類

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
); 
           
Vulkan 記憶體
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;
           
Vulkan 記憶體

注意 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;
           
Vulkan 記憶體

 注意: 實體裝置記憶體端的可配置設定對象的數量是有限的,可以通過 VkPhysicalDeviceLimits 成員的   maxMemoryAllocationCount  查詢 (4096 )。

釋放記憶體

Void VkFreeMemory (
	VkDevice          device,
    VkDeviceMemory    memory,
    const VkAllocationCallbacks* allocator
);
           
Vulkan 記憶體

從主控端通路裝置記憶體

主控端隻能通路那些支援映射的記憶體類型 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);
           

映射過的記憶體需不需要再次映射? 

Vulkan 記憶體
Vulkan 記憶體