1.內存
VulKan將內存分爲兩類:Host Memory 和 Device Memory.
Host是運行應用程序的處理器,在PC端上就是指CPU;Device是執行VulKan命令的處理器,也就是GPU.
Host memory指的是對Host可見的內存,Device memory指的是對Device可見的內存。 在使用Host Memory時,一定要注意內存對齊。不允許簡單的直接把malloc hook到Vulkan的內存分配函數上!
更詳細的,Vulkan系統中的內存有四種類型:
- Host Local Memory,只對Host可見的內存,通常稱之爲普通內存
- Device Local Memory,只對Device可見的內存,通常稱之爲顯存
- Host Local Device Memory,由Host管理的,對Device看見的內存
- Device Local Host Memory,由Device管理的,對Host可見的內存
其中,不同內存類型適用不同場景:
- Device Local Memory適合優先級最高的資源,通常是紋理等頻繁被使用的渲染數據。當內存空間不夠時我們纔會考慮是否將這些內存數據放到CPU端。
- Device Local Host Memory 適合CPU 到 GPU的數據傳遞,一些頂點數據等,可以通過這種方式傳遞。
- Host Local Device Memory 適合GPU 到 CPU的數據傳遞,截圖、回寫等操作可以使用這種內存。
並不是所有設備都支持這四種類型。一些嵌入式系統、移動設備甚至是筆記本電腦的GPU,可能與CPU共享內存控制器和內存子系統。這種情況它的內存只有一種類型,通常稱之爲unified memory architecture
(統一內存架構)。
1.1 Host Memory
Host Memory是CPU可以訪問的常規內存,一般是通過調用malloc或new分配。
Vulkan API創建的對象通常需要一定數量的Host Memory,用來儲存對象和數據結構。
Vulkan對Host Memory的要求就是內存地址是對齊的!
這是因爲某些高性能CPU指令在對齊的內存地址上效果最佳。通過假定存儲CPU端數據結構的分配是對齊的,Vulkan可以無條件使用這些高性能指令,從而提供顯著的性能優勢。
1.2 Device Memory
任何可以由Device訪問的內存,都被稱爲Device Memory(設備內存)。Device Memory距離Device更近,比Host Memory更有性能優勢。Image object、Buffer object、UBO(uniform buffer objec)都由Device Memory分配。Vulkan中的所有資源都由Device Memory支持。
1.3 內存池Pool
內存是一種昂貴的資源,分配操作通常會有間接的系統代價。
Vulkan中通過資源池來平攤成本,一些創建比較頻繁的資源都由資源池統一管理:
- Command Buffer Pool
- Descriptor Pool
- Query Pool
2. Buffer and Resources
內存的作用是給資源做底層支持,不同的資源對內存的要求並不一樣。
Vulkan有兩種基本資源類型:Buffer和Image。
Buffer 是最簡單的資源類型,可以用來儲存線性的結構化的數據,也可以儲存內存中原始字節。
從圖中我們可以看到,vulkan中使用的buffer類型主要有:
- indirect buffer
- index buffer
- vertex buffer
- uniform texel buffer
- uniform buffer
- storage texel buffer
- storage buffer
當使用vkCreateBuffer創建一個buffer對象的時候,在創建信息VkBufferCreateInfo中,就要指定這個buffer對象可能的使用場景。除了上述七種有着一一對應的使用掩碼位之外,還有額外的兩個,分別表示buffer是否可以作爲transfer的src或者dst。當創建好了一個buffer對象後,需要將它和一個memory對象關聯起來,這樣纔可以真正讓這個buffer對象擁有memory。關聯是通過vkBindBufferMemory來完成的,然而,直接binding可能會失敗,因爲創建的buffer可能會有一些額外的要求,例如對齊等,所以在此之前,需要使用vkGetBufferMemoryRequirements來獲取這個buffer對象對於memory等要求。要求被填入一個VkMemoryRequirements的對象中
Image 則相對比較複雜,具有特殊的佈局(layout)和格式(format),可用來做flitering,blending,depth 和 stencil testing等。 從vulkan pipeline中,可以看出,image主要是作爲shader resource的sampled image(即傳統意義上的texture),storage image,以及frame buffer中的input attachment, color attachment和depth/stencil attachment。
Image的佈局(layout)對內存有特殊需求,主要有兩種主要的平鋪模式(tiling modes):
- linear - 其中的圖像(Image)數據線性的排列在內存中。
- optimal - 其中的圖像(Image)數據以高度優化的模式進行佈局,可以有效利用設備的內存子系統。
線性佈局(linear layout)適合連續的單行的讀寫,但是大多數圖形操作都涉及到跨行讀寫紋理元素(比如在計算A時,需要參考ABCD四個紋理像素),如果圖像的寬度非常寬,相鄰行的訪問在線性佈局中會有非常大的跳轉。這可能會導致性能問題。
優化佈局(optimal layout)的好處是內存數據根據不同內存子系統進行優化,比如將所有的紋理像素都優化到一塊連續的內存區域中,加快內存處理速度。
GPU硬件通常傾向於使用優化佈局以實現更有效的渲染。但是優化佈局(optimal layout)通常是“不透明的”,這意味着優化佈局格式的詳細信息不會被其他需要讀取或寫入圖像數據的組件得知。
如果CPU如果想讀取生層的圖像信息,圖像在被讀取之前要進行佈局轉換,將optimal layout轉換爲普通佈局後,CPU才能正確識別圖像信息。
內存銷燬
一個memory對象在生命週期的盡頭,由vkFreeMemory釋放。 當釋放一個memory對象的時候,app應當保證此時device不再引用此memory對象上所關聯的image/buffer。 app可以使用vkMapMemory(3)來獲取cpu側的指針以訪問其中的內容,然後使用vkUnmapMemory(3)來釋放