Vulkan 是一款低負載的跨平台 API,可用於製作高品質 3D 圖像。與 OpenGL ES (GLES) 類似,Vulkan 提供各項工具,可讓您在應用程式中製作高品質的即時圖形。使用 Vulkan 的優點包括降低 CPU 負擔,以及支援 SPIR-V 二進位中介語言。
如要成功實作 Vulkan,裝置必須包含:
- Android 提供的 Vulkan 載入器。
- Vulkan 驅動程式,由 GPU IHV 等 SoC 提供,可實作 Vulkan API。如要支援 Vulkan 功能,Android 裝置必須具備支援 Vulkan 的 GPU 硬體和相關聯的驅動程式。GPU 也必須支援 GLES 3.1 以上版本。請洽詢 SoC 供應商,要求提供驅動程式支援。
如果裝置包含 Vulkan 驅動程式,裝置必須宣告 FEATURE_VULKAN_HARDWARE_LEVEL
和 FEATURE_VULKAN_HARDWARE_VERSION
系統功能,且版本必須準確反映裝置的功能。這有助於確保裝置符合相容性定義說明文件 (CDD) 的規定。
Vulkan 載入器
Vulkan 載入器 platform/frameworks/native/vulkan
是 Vulkan 應用程式與裝置 Vulkan 驅動程式之間的主要介面。Vulkan 載入器安裝在 /system/lib[64]/libvulkan.so
。載入器提供核心 Vulkan API 進入點、Android CDD 要求的擴充功能進入點,以及許多額外的選用擴充功能。載入器會匯出 Window System Integration (WSI) 擴充功能,且主要是在載入器中實作,而非在驅動程式中實作。載入器也支援列舉和載入圖層,這些圖層可公開其他擴充功能,並攔截傳送至驅動程式的核心 API 呼叫。
NDK 包含用於連結的存根 libvulkan.so
程式庫。這個程式庫會匯出與載入器相同的符號。應用程式會呼叫從實際 libvulkan.so
程式庫匯出的函式,在載入器中輸入跳板函式,並根據第一個引數分派至適當的層或驅動程式。vkGet*ProcAddr()
呼叫會傳回函式指標,而這些指標會分派至跳板 (也就是直接呼叫核心 API 程式碼)。透過函式指標 (而非匯出的符號) 呼叫,可略過跳板和調度,因此效率更高。
列舉及載入驅動程式
建構系統映像檔時,Android 會預期系統知道可用的 GPU。載入器會使用現有的 HAL 機制,在 hardware.h
中探索及載入驅動程式。32 位元和 64 位元 Vulkan 驅動程式的偏好路徑如下:
/vendor/lib/hw/vulkan.<ro.hardware.vulkan>.so /vendor/lib/hw/vulkan.<ro.board.platform>.so /vendor/lib64/hw/vulkan.<ro.hardware.vulkan>.so /vendor/lib64/hw/vulkan.<ro.board.platform>.so
在 Android 7.0 以上版本中,Vulkan hw_module_t
衍生項目會包裝單一 hw_module_t
結構體;系統只支援一個驅動程式,且常數字串 HWVULKAN_DEVICE_0
會傳遞至 open()
。
Vulkan hw_device_t
衍生項目對應於單一驅動程式,可支援多個實體裝置。hw_device_t
結構可以擴充為匯出 vkGetGlobalExtensionProperties()
、vkCreateInstance()
和 vkGetInstanceProcAddr()
函式。載入器可以呼叫 hw_device_t
結構的 vkGetInstanceProcAddr()
,找出所有其他 VkInstance()
、VkPhysicalDevice()
和 vkGetDeviceProcAddr()
函式。
ro.vulkan.apex
設為 Vulkan APEX 的名稱,從 APEX 載入 Vulkan。
圖層探索與載入
Vulkan 載入器支援列舉及載入層,這些層可公開其他擴充功能,並攔截傳送至驅動程式的核心 API 呼叫。Android 系統映像檔不包含圖層,但應用程式可以在 APK 中加入圖層。
使用圖層時,請注意 Android 的安全性模型和政策與其他平台有很大差異。具體來說,Android 不允許將外部程式碼載入至正式版 (未取得根存取權) 裝置上無法偵錯的程序,也不允許外部程式碼檢查或控制程序的記憶體、狀態等。包括禁止將核心傾印、API 追蹤等項目儲存至磁碟,以供日後檢查。正式版裝置只會啟用隨不可偵錯應用程式提供的圖層,且驅動程式不得提供違反這些政策的功能。
圖層的用途包括:
- 開發階段層 - 驗證層和用於追蹤/剖析/偵錯工具的墊片不應安裝在正式版裝置的系統映像檔上。追蹤/剖析/偵錯工具的驗證層和墊片應可更新,不必使用系統映像檔。開發人員如要在開發期間使用其中一個圖層,可以修改應用程式套件,例如在原生程式庫目錄中新增檔案。如果 IHV 和 OEM 工程師想診斷運送不可修改應用程式時發生的故障,除非這些應用程式可供偵錯,否則他們應可存取系統映像檔的非正式 (已取得根存取權) 建構版本。詳情請參閱「Android 上的 Vulkan 驗證層」。
- 公用程式層:這些層會公開擴充功能,例如實作裝置記憶體記憶體管理員的層。開發人員可選擇要在應用程式中使用的圖層和圖層版本;使用相同圖層的不同應用程式仍可使用不同版本。開發人員可選擇要在應用程式套件中發布哪些圖層。
- 插入 (隱含) 圖層 - 包括使用者或某些其他應用程式提供的圖層,例如影格速率、社群網路和遊戲啟動器疊加層,但應用程式並不知情或未同意。這些做法違反 Android 安全性政策,因此不支援。
對於無法偵錯的應用程式,載入器只會在應用程式的原生程式庫目錄中搜尋圖層,並嘗試載入名稱符合特定模式的任何程式庫 (例如 libVKLayer_foo.so
)。
如果是可偵錯的應用程式,載入器會在 /data/local/debug/vulkan
中搜尋圖層,並嘗試載入符合特定模式的任何程式庫。
Android 可讓您在 Android 和其他平台之間,透過建構環境變更移植圖層。如要瞭解圖層和載入器之間的介面,請參閱「Vulkan 載入器介面架構」。Khronos 維護的驗證層會託管在 Vulkan 驗證層中。
Vulkan API 版本和功能
下表列出幾個 Android 版本適用的 Vulkan API 版本。Android 版本 | Vulkan 版本 |
---|---|
Android 13 | Vulkan 1.3 |
Android 9 | Vulkan 1.1 |
Android 7 | Vulkan 1.0 |
Vulkan 1.3 功能總覽
Vulkan 1.3 將先前多項選用擴充功能納入 Vulkan 核心功能。這類功能大多是為了提高對 Vulkan 程式設計介面的控制程度和精細度而納入。單次傳遞算繪傳遞執行個體不再需要算繪傳遞物件或影格緩衝區。可減少管道狀態物件總數,並徹底改造 API 內的同步作業。Vulkan 1.3 的硬體需求與 Vulkan 1.2、1.1 和 1.0 相同,且大部分實作項目都在 SoC 專屬的圖形驅動程式中,而非架構中。
Android 適用的 Vulkan 1.3 最重要功能包括:
- 支援單次算繪傳遞執行個體
- 支援立即終止著色器調用
- 更精細地控管管道的建立、共用和控制
Vulkan 1.3 也包含多項較小的功能,以及 API 可用性強化功能。如要查看 1.3 次要修訂版本對核心 Vulkan API 所做的所有變更,請參閱「核心修訂版本 (Vulkan 1.3)」。
Vulkan 1.2 功能總覽
Vulkan 1.2 新增了多項功能和擴充功能,可簡化 API 介面。包括統一的記憶體模型,以及可從裝置驅動程式查詢的其他資訊。Vulkan 1.2 的硬體需求與 Vulkan 1.0 和 1.1 相同;所有實作項目都位於 SoC 專屬的圖形驅動程式中,而非架構。
對 Android 而言,Vulkan 1.2 最重要的功能是支援 8 位元儲存空間。
Vulkan 1.2 也包含多項較小的功能,以及 API 可用性強化功能。如要瞭解 1.2 次要修訂版本對核心 Vulkan API 的所有變更,請參閱「核心修訂版本 (Vulkan 1.2)」。
Vulkan 1.1 功能總覽
Vulkan 1.1 支援記憶體/同步處理互通性,因此 OEM 可以在裝置上支援 Vulkan 1.1。此外,記憶體/同步互通性可讓開發人員判斷裝置是否支援 Vulkan 1.1,並在支援時有效使用。Vulkan 1.1 的硬體需求與 Vulkan 1.0 相同,但大部分實作作業都在 SOC 專屬的圖形驅動程式中,而非架構中。
Android 最重要的 Vulkan 1.1 功能包括:
- 支援從 Vulkan 外部匯入及匯出記憶體緩衝區和同步物件 (用於與攝影機、轉碼器和 GLES 互通)
- 支援 YCbCr 格式
Vulkan 1.1 也包含多項較小的功能,以及 API 可用性增強功能。如要查看 1.1 次要修訂版本對核心 Vulkan API 的所有變更,請參閱「核心修訂版本 (Vulkan 1.1)」。
選擇 Vulkan 支援
只要支援 64 位元 ABI 且並非低記憶體裝置,Android 裝置就應支援最先進的 Vulkan 功能組合。
搭載 Android 13 以上版本的裝置應支援 Vulkan 1.3。
透過 Android 10 推出的裝置應支援 Vulkan 1.1。
其他裝置則可選擇性支援 Vulkan 1.3、1.2 和 1.1。
支援 Vulkan 版本
如果 Android 裝置符合下列條件,即支援某個 Vulkan 版本:
- 除了 Android 版本的其他 CDD 需求,請一併新增支援感興趣 Vulkan 版本的 Vulkan 驅動程式 (必須是 Vulkan 1.3、1.1 或 1.0 版)。或者,更新現有的 Vulkan 驅動程式,使其 Vulkan 版本號碼較低。
- 如果是 Vulkan 1.3 或 1.1,請確保套件管理員傳回的系統功能會針對正確的 Vulkan 版本傳回
true
。- Vulkan 1.3 的功能為
PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x403000)
。 - 如果是 Vulkan 1.1,這項功能為
PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000)
。
device.mk
檔案,針對 Vulkan 1.3 和 Vulkan 1.1 回傳true
,如下所示:- 針對 Vulkan 1.3 新增下列項目:
PRODUCT_COPY_FILES += frameworks/native/data/etc/android.hardware.vulkan.version-1_3.xml: $(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml
- Vulkan 1.3 的功能為
- 針對 Vulkan 1.1 新增下列項目:
PRODUCT_COPY_FILES += frameworks/native/data/etc/android.hardware.vulkan.version-1_1.xml: $(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml
Android 基準設定檔 (ABP)
建議所有 Android 裝置都遵循 Android 基準設定檔指南,符合最新的 Android Baseline 2022 設定檔。
凡是支援 Android 14 以上版本和 Vulkan API 的裝置,都必須符合Android Baseline 2021 設定檔中定義的所有功能。Vulkan 設定檔 json
檔案中列出了完整的功能清單,但其中一項重要子集包括:
- 透過 ASTC 和 ETC 壓縮紋理。
- 透過
VK_EXT_swapchain_colorspace
設定可變色域。 - 透過
sampleRateShading
使用陰影取樣和插值多重取樣功能。
視窗系統整合 (WSI)
在 libvulkan.so
中,驅動程式會實作下列視窗系統整合 (WSI) 擴充功能:
VK_KHR_surface
VK_KHR_android_surface
VK_KHR_swapchain
VK_KHR_driver_properties
,僅在 Android 10 中為 Vulkan 1.1 實作VK_GOOGLE_display_timing
,適用於 Android 10 中的任何 Vulkan 版本
VkSurfaceKHR
和 VkSwapchainKHR
物件以及與 ANativeWindow
的所有互動,都由平台處理,不會向驅動程式公開。WSI 實作項目依賴 VK_ANDROID_native_buffer
擴充功能,而驅動程式必須支援這項擴充功能;這項擴充功能僅供 WSI 實作項目使用,不會向應用程式公開。
Gralloc 使用旗標
Vulkan 實作可能需要使用實作定義的私有 Gralloc 用途標記,分配交換鏈緩衝區。建立交換鏈時,Android 會呼叫下列函式,要求驅動程式將要求的格式和圖片使用情形標記轉換為 Gralloc 使用情形標記:
typedef enum VkSwapchainImageUsageFlagBitsANDROID { VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID = 0x00000001, VK_SWAPCHAIN_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSwapchainImageUsageFlagBitsANDROID; typedef VkFlags VkSwapchainImageUsageFlagsANDROID; VkResult VKAPI vkGetSwapchainGrallocUsage2ANDROID( VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage );
format
和 imageUsage
參數取自 VkSwapchainCreateInfoKHR
結構。驅動程式應填入 *grallocConsumerUsage
和 *grallocProducerUsage
,並使用格式和用途所需的 Gralloc 用途標記。驅動程式傳回的使用情形標記,會與交換鏈消費者在分配緩衝區時要求的使用情形標記合併。
Android 7.x 會呼叫較舊版本的 VkSwapchainImageUsageFlagsANDROID()
,
名為 vkGetSwapchainGrallocUsageANDROID()
。Android 8.0 以上版本會淘汰 vkGetSwapchainGrallocUsageANDROID()
,但如果驅動程式未提供 vkGetSwapchainGrallocUsage2ANDROID()
,仍會呼叫 vkGetSwapchainGrallocUsageANDROID()
:
VkResult VKAPI vkGetSwapchainGrallocUsageANDROID( VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage );
vkGetSwapchainGrallocUsageANDROID()
不支援交換鏈使用旗標或擴充的 Gralloc 使用旗標。
Gralloc 支援的圖片
VkNativeBufferANDROID
是 vkCreateImage
擴充功能結構,用於建立以 Gralloc 緩衝區為基礎的圖片。VkNativeBufferANDROID
會在 VkImageCreateInfo
結構鏈中提供給 vkCreateImage()
。在呼叫 vkCreateSwapchainKHR
時,會呼叫 vkCreateImage()
並傳遞 VkNativeBufferANDROID
。WSI 實作會分配交換鏈要求數量的原生緩衝區,然後為每個緩衝區建立 VkImage
:
typedef struct { VkStructureType sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID const void* pNext; // Buffer handle and stride returned from gralloc alloc() buffer_handle_t handle; int stride; // Gralloc format and usage requested when the buffer was allocated. int format; int usage; // Beginning in Android 8.0, the usage field above is deprecated and the // usage2 struct below was added. The usage field is still filled in for // compatibility with Android 7.0 drivers. Drivers for Android 8.0 // should prefer the usage2 struct, especially if the // android.hardware.graphics.allocator HAL uses the extended usage bits. struct { uint64_t consumer; uint64_t producer; } usage2; } VkNativeBufferANDROID;
建立 Gralloc 支援的圖片時,VkImageCreateInfo
具有下列資料:
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO .pNext = the above VkNativeBufferANDROID structure .imageType = VK_IMAGE_TYPE_2D .format = a VkFormat matching the format requested for the gralloc buffer .extent = the 2D dimensions requested for the gralloc buffer .mipLevels = 1 .arraySize = 1 .samples = 1 .tiling = VK_IMAGE_TILING_OPTIMAL .usage = VkSwapchainCreateInfoKHR::imageUsage .flags = 0 .sharingMode = VkSwapchainCreateInfoKHR::imageSharingMode .queueFamilyCount = VkSwapchainCreateInfoKHR::queueFamilyIndexCount .pQueueFamilyIndices = VkSwapchainCreateInfoKHR::pQueueFamilyIndices
在 Android 8.0 以上版本中,如果交換鏈需要任何交換鏈圖像使用情形標記,平台會在提供給 vkCreateImage
的 VkImageCreateInfo
鏈中提供 VkSwapchainImageCreateInfoKHR
擴充結構。擴充功能結構包含交換鏈結圖片使用旗標:
typedef struct { VkStructureType sType; // must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID const void* pNext; VkSwapchainImageUsageFlagsANDROID usage; } VkSwapchainImageCreateInfoANDROID;
在 Android 10 以上版本中,平台支援 VK_KHR_swapchain
v70,因此 Vulkan 應用程式可以建立由交換鏈記憶體支援的 VkImage
。應用程式會先呼叫 vkCreateImage
,並將 VkImageSwapchainCreateInfoKHR
結構體鏈結至 VkImageCreateInfo
結構體。接著,應用程式會呼叫 vkBindImageMemory2(KHR)
,並將 VkBindImageMemorySwapchainInfoKHR
結構體鏈結至 VkBindImageMemoryInfo
結構體。VkBindImageMemorySwapchainInfoKHR
結構中指定的 imageIndex
必須是有效的交換鏈結圖片索引。同時,平台會將相應的 Gralloc 緩衝區資訊提供給 VkBindImageMemoryInfo
鏈結,並提供 VkNativeBufferANDROID
擴充結構,讓驅動程式瞭解要將 VkImage
繫結至哪個 Gralloc 緩衝區。
取得圖片
vkAcquireImageANDROID
取得交換鏈結圖片的擁有權,並將外部發出信號的原生柵欄匯入現有的 VkSemaphore
物件和現有的 VkFence
物件:
VkResult VKAPI vkAcquireImageANDROID( VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence );
vkAcquireImageANDROID()
會在 vkAcquireNextImageKHR
期間呼叫,將原生柵欄匯入應用程式提供的 VkSemaphore
和 VkFence
物件 (不過,信號和柵欄物件在此呼叫中都是選用)。驅動程式也可以利用這個機會,辨識及處理 Gralloc 緩衝區狀態的任何外部變更;許多驅動程式不需要在此執行任何動作。這個呼叫會將 VkSemaphore
和 VkFence
設為與 vkQueueSubmit
發出信號時相同的待處理狀態,因此佇列可以等待信號燈,應用程式則可以等待柵欄。
當基礎原生柵欄發出信號時,這兩個物件都會收到信號;如果原生柵欄已發出信號,則當這個函式傳回時,信號燈會處於發出信號的狀態。驅動程式會取得柵欄檔案描述元的擁有權,並在不再需要時關閉柵欄檔案描述元。即使未提供信號或柵欄物件,或 vkAcquireImageANDROID
失敗並傳回錯誤,驅動程式也必須這麼做。如果 fenceFd
為 -1,就如同原生柵欄已發出信號。
發布圖片
vkQueueSignalReleaseImageANDROID
會準備用於外部用途的交換鏈結圖片、建立原生柵欄,並排定在輸入信號燈發出信號後,發出原生柵欄信號:
VkResult VKAPI vkQueueSignalReleaseImageANDROID( VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd );
在提供的佇列上呼叫 vkQueuePresentKHR()
vkQueueSignalReleaseImageANDROID()
。驅動程式必須產生原生柵欄,直到 pWaitSemaphores
中的所有 waitSemaphoreCount
號誌發出信號,以及準備 image
進行呈現所需的任何額外工作完成為止,才會發出信號。
如果等待信號 (如有) 已發出信號,且 queue
已處於閒置狀態,驅動程式可以將 *pNativeFenceFd
設為 -1
,而非實際的原生柵欄檔案描述元,表示沒有任何項目需要等待。呼叫端擁有並關閉 *pNativeFenceFd
中傳回的檔案描述元。
許多驅動程式可以忽略圖片參數,但有些可能需要準備與 Gralloc 緩衝區相關聯的 CPU 端資料結構,供外部圖片消費者使用。準備緩衝區內容供外部消費者使用時,應以非同步方式進行,做為將圖片轉換為 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
的一部分。
如果映像檔是使用 VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID
建立,則驅動程式必須允許重複呼叫 vkQueueSignalReleaseImageANDROID()
,且不得插入對 vkAcquireImageANDROID()
的呼叫。
支援共用可顯示圖片
部分裝置可在顯示管道和 Vulkan 實作之間共用單一圖片的擁有權,以盡量減少延遲。在 Android 9 以上版本中,載入器會根據驅動程式對 vkGetPhysicalDeviceProperties2
呼叫的回應,有條件地宣傳 VK_KHR_shared_presentable_image
擴充功能。
如果驅動程式不支援 Vulkan 1.1 或 VK_KHR_physical_device_properties2
擴充功能,載入器就不會宣傳支援共用可呈現的圖片。否則,載入器會呼叫 vkGetPhysicalDeviceProperties2()
並在 VkPhysicalDeviceProperties2::pNext
鏈結中加入下列結構,查詢驅動程式功能:
typedef struct { VkStructureType sType; // must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID const void* pNext; VkBool32 sharedImage; } VkPhysicalDevicePresentationPropertiesANDROID;
如果驅動程式可以與顯示系統共用圖片擁有權,則會將 sharedImage
成員設為 VK_TRUE
。
驗證
原始設備製造商 (OEM) 可以使用 CTS 測試 Vulkan 實作,包括:
- Khronos Vulkan 一致性測試 (位於
CtsDeqpTestCases
模組中),包括 Vulkan 1.0、1.1、1.2 和 1.3 的功能性 API 測試。 CtsGraphicsTestCases
模組,可測試裝置是否已正確設定,支援 Vulkan 功能。
Vulkan 功能旗標
裝置必須支援 Android 11 以上版本和 Vulkan API,才能公開功能旗標 android.software.vulkan.deqp.level
。這項功能旗標的值是日期,以整數值編碼。這個值會指定裝置聲稱通過的 Vulkan dEQP 測試相關聯日期。
YYYY-MM-DD 格式的日期會編碼為 32 位元整數,如下所示:
- 位元 0 到 15 儲存年份
- 位元 16 到 23 儲存月份
- 位元 24 到 31 儲存日期
功能旗標的最小值為 0x07E30301
,對應至 2019 年 3 月 1 日,也就是與 Android 10 的 Vulkan dEQP 測試相關聯的日期。如果功能標記至少是這個值,裝置就會聲稱通過所有 Android 10 Vulkan dEQP 測試。
值 0x07E40301
對應於 2020 年 3 月 1 日,這是與 Android 11 的 Vulkan dEQP 測試相關聯的日期。如果功能標記至少是這個值,裝置就會聲稱通過所有 Android 11 Vulkan dEQP 測試。
值 0x07E60301
對應於 2022 年 3 月 1 日,這是與 Android 13 的 Vulkan dEQP 測試相關聯的日期。如果功能旗標至少有這個值,裝置就會聲稱通過所有 Android 13 Vulkan dEQP 測試。
如果裝置公開特定功能標記 (即
0x07E30301
、0x07E40301
、0x07E60301
),就表示該裝置通過該功能標記的所有 Android Vulkan dEQP 測試 (分別為 Android 10、Android 11 和 Android 13)。這部裝置可能會通過後續 Android 版本的 Vulkan dEQP 測試。
Vulkan dEQP 是 Android CTS 的一部分。從 Android 11 開始,CTS 的 dEQP 測試執行器元件會留意 android.software.vulkan.deqp.level
功能旗標,並根據這個功能旗標,略過裝置聲稱不支援的任何 Vulkan dEQP 測試。這類測試會回報為輕鬆通過。