天天看點

Vulkan 基本原理

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的一種中間層機制,負責接收指令緩存并傳遞給裝置。指令緩存記錄了一個或者多個指令,并發送給相關的隊列。裝置則提供了多個可選的隊列,然後應用程式負責将指令緩存傳遞給正确的隊列。

指令緩存的發送可以按照以下兩種方式來完成:

  • 單一隊列:
  • 按照指令緩存發送的順序進行維護,以及執行或者回放。
  • 指令緩存按照串行的方式執行。
  • 多重隊列:
  • 允許指令緩存以并行的方式在兩個或者更多隊列中執行。
  • 除非特别指定,否則無法保證指令緩存發送和執行的順序不變。應用程式需要負責進行此類同步操作,否則實際的執行順序可能會完全與發送時的順序無關。

Vulkan提供了多種同步圖元,讓使用者可以相應地在單一隊列中,或者跨隊列地完成工作執行順序的管理。如下所示:

  • 信号量(semaphore):這種同步機制可以跨隊列或在單一隊列中的粗粒度指令緩存中執行。
  • 事件(event):事件控制細粒度同步,并應用于單個隊列,進而確定單一指令緩存中或者多個指令緩存之間的同步要求。宿主系統也可以參與到事件觸發的同步機制當中。
  • 栅欄(fence):允許在宿主和裝置之間完成同步。
  • 流水線屏障(pipeline barrier):流水線屏障是插入到指令緩存中的一種指令,它可以確定在它之前的指令始終優先執行,而在它之後的指令一定随後執行。

對象模型

在應用程式端,包括裝置、隊列、指令緩存、幀緩存、流水線等在内的所有對象,統稱為Vulkan對象。而在内部的API層面,這些Vulkan對象會被識别為不同的句柄。這些句柄可以分為兩種類型:可分發的以及不可分發的。

  • 可分發的句柄:這類指針指向了一個不透明的内部圖形實體。不透明的資料類型不允許直接通路它的内部結構體成員。你隻能通過API函數來通路結構體的内部域。所有的可分發句柄都會關聯一個可分發的類型,這樣它就可以作為一個參數被傳遞給其他的API指令。一些典型的示例如下所示。
Vulkan 基本原理
  • 不可分發的句柄:這些64位整型類型的句柄通常不會指向一個結構體,而是直接包含了對象自身的資訊。一些典型的示例如表所示。
Vulkan 基本原理

對象生命周期與指令文法

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執行個體