Vulkan 基本原理,下面介紹Vulkan的基礎知識,涉及以下内容:
- Vulkan的執行模型
- Vulkan的隊列
- 對象模型
- 對象生命周期與指令文法
- 錯誤檢查與驗證
轉自https://www.coolcou.com/vulkan/vulkan-tutorials/basic-principle-of-vulkan.html
Vulkan的執行模型
支援Vulkan的系統可以直接查詢系統資訊,并傳回可用的實體裝置的數量。每個實體裝置可以支援一個或多個隊列。這些隊列被劃分到不同的族群中,每個族群有自己獨特的功能設定。例如,一個族群可能會支援諸如圖形、計算、資料傳輸,或者記憶體管理相關的功能。隊列族群中的每個成員可能包含了一個或者多個相似的隊列,是以它們互相之間是相容的。例如,某個具體的驅動實作中,可能在同一個隊列裡同時支援資料傳輸和圖形操作。
Vulkan允許使用者顯式地在應用程式中管理和控制記憶體。它暴露了裝置中支援的所有不同類型的記憶體堆(heap),每個堆屬于一個不同的記憶體區域。Vulkan的執行模型是非常簡單和直接的。在這裡,指令緩存會被發送到隊列中,後者将被實體裝置按順序依次執行和消耗。
Vulkan的應用程式負責控制一組Vulkan裝置,将一系列指令記錄到指令緩存中,并發送到隊列。驅動會讀取隊列并按照記錄的順序依次執行各個工作。指令隊列的建構是需要較大代價的,而建構一旦完成,它就可以被緩存和發送到隊列中,根據自己的需要多次執行。此外,有些指令緩存在應用程式中也可以以多線程的方式并行同步地建構。
如圖所示給出了一個簡化後的執行模型:
在這裡,應用程式記錄了兩個指令緩存,其中各包含了多個指令。這些指令随即按照作業性質的不同,被傳遞給一個或者多個隊列。隊列将這些緩存作業送出給裝置加以執行。最後,裝置處理得到結果,并将它們顯示到輸出裝置上,或者傳回給使用者程式做進一步的處理。
Vulkan中,使用者應用程式主要負責以下工作:
- 生産指令執行所必需的所有先決内容:
- 其中可能包括資源的準備、着色器的預編譯、将資源關聯到着色器、設定着色器的狀态、建構流水線,以及繪制調用。
- 記憶體管理。
- 同步。
- 宿主和裝置之間。
- 裝置上不同的隊列之間。
- 風險管理。
Vulkan的隊列
隊列是Vulkan的一種中間層機制,負責接收指令緩存并傳遞給裝置。指令緩存記錄了一個或者多個指令,并發送給相關的隊列。裝置則提供了多個可選的隊列,然後應用程式負責将指令緩存傳遞給正确的隊列。
指令緩存的發送可以按照以下兩種方式來完成:
- 單一隊列:
- 按照指令緩存發送的順序進行維護,以及執行或者回放。
- 指令緩存按照串行的方式執行。
- 多重隊列:
- 允許指令緩存以并行的方式在兩個或者更多隊列中執行。
- 除非特别指定,否則無法保證指令緩存發送和執行的順序不變。應用程式需要負責進行此類同步操作,否則實際的執行順序可能會完全與發送時的順序無關。
Vulkan提供了多種同步圖元,讓使用者可以相應地在單一隊列中,或者跨隊列地完成工作執行順序的管理。如下所示:
- 信号量(semaphore):這種同步機制可以跨隊列或在單一隊列中的粗粒度指令緩存中執行。
- 事件(event):事件控制細粒度同步,并應用于單個隊列,進而確定單一指令緩存中或者多個指令緩存之間的同步要求。宿主系統也可以參與到事件觸發的同步機制當中。
- 栅欄(fence):允許在宿主和裝置之間完成同步。
- 流水線屏障(pipeline barrier):流水線屏障是插入到指令緩存中的一種指令,它可以確定在它之前的指令始終優先執行,而在它之後的指令一定随後執行。
對象模型
在應用程式端,包括裝置、隊列、指令緩存、幀緩存、流水線等在内的所有對象,統稱為Vulkan對象。而在内部的API層面,這些Vulkan對象會被識别為不同的句柄。這些句柄可以分為兩種類型:可分發的以及不可分發的。
- 可分發的句柄:這類指針指向了一個不透明的内部圖形實體。不透明的資料類型不允許直接通路它的内部結構體成員。你隻能通過API函數來通路結構體的内部域。所有的可分發句柄都會關聯一個可分發的類型,這樣它就可以作為一個參數被傳遞給其他的API指令。一些典型的示例如下所示。
- 不可分發的句柄:這些64位整型類型的句柄通常不會指向一個結構體,而是直接包含了對象自身的資訊。一些典型的示例如表所示。
對象生命周期與指令文法
Vulkan當中的對象是根據應用程式的邏輯需求顯式地建立和銷毀的,應用程式需要自己管理這些對象。
Vulkan的對象需要使用Create指令建立,以及使用Destroy指令銷毀:
- Create文法:對象的建立需要通過
指令完成,它需要一個vkCreate*
結構體作為輸入參數。Vk*Createinfo
- Destroy文法:使用Create指令建立的對象總是需要使用
vkDestroy*
指令銷毀。
如果對象是作為已有的對象池或者堆的一部分建立的,那麼需要使用Allocate指令建立,并使用Free指令從池或者堆中銷毀。
- Allocate文法:一個對象如果是作為對象池的一部分建立,那麼需要使用
指令,并且需要一個vkAllocate*
作為輸入參數。Vk*AllocateInfo
- Free文法:已建立的對象需要使用
指令從對象池或者記憶體中釋放。vkFree*
上述所有的實作方法都可以通過
vkGet*
指令輕松擷取。而使用了
vkCmd*
形式的API接口主要用于把指令記錄到指令緩存當中。
錯誤檢查與驗證
Vulkan的設計在性能最大化的前提下提供了可選的錯誤檢查和驗證功能。在程式運作時,錯誤檢查和驗證的需求非常少,是以建構指令緩存和發送到裝置的效率很高。這類可選的功能可以在Vulkan的階層化結構中使用,進而在運作系統中實作多個層之間的動态注入(調試和驗證)。
- 第一個Vulkan程式
- Vulkan 使用LunarG SDK
- Vulkan 使用CMake建構工程
- Vulkan 擴充簡介
- 建立Vulkan執行個體