實施Vulkan

Vulkan是一種低開銷、跨平台的 API,用於高效能 3D 圖形。與OpenGL ES (GLES)一樣,Vulkan 提供了在應用程式中創建高品質即時圖形的工具。使用 Vulkan 的優點包括減少 CPU 開銷以及支援SPIR-V 二進位中間語言。

要成功實施 Vulkan,設備必須包括:

  • Vulkan 載入器,由 Android 提供。
  • 由 GPU IHV 等 SoC 提供的 Vulkan 驅動程序,用於實作Vulkan API 。為了支援 Vulkan 功能,Android 裝置需要支援 Vulkan 的 GPU 硬體和相關驅動程式。 GPU 也必須支援 GLES 3.1 及更高版本。請諮詢您的 SoC 供應商以請求驅動程式支援。

如果裝置包含 Vulkan 驅動程序,則裝置需要宣告FEATURE_VULKAN_HARDWARE_LEVELFEATURE_VULKAN_HARDWARE_VERSION系統功能,以及準確反映裝置功能的版本。這有助於確保設備符合相容性定義文件(CDD)。

Vulkan裝載機

Vulkan 載入程式platform/frameworks/native/vulkan是 Vulkan 應用程式和裝置的 Vulkan 驅動程式之間的主要介面。 Vulkan 載入程式安裝在/system/lib[64]/libvulkan.so 。該載入器提供核心 Vulkan API 入口點、Android CDD 所需的擴充入口點以及許多其他可選擴充。視窗系統整合 (WSI) 擴充功能由載入程式匯出,並且主要在載入程式而不是驅動程式中實作。載入程式還支援枚舉和載入層,這些層可以公開其他擴充功能並在通往驅動程式的途中攔截核心 API 呼叫。

NDK 包含一個用於連結的存根libvulkan.so函式庫。該庫導出與載入程式相同的符號。應用程式呼叫從真實libvulkan.so庫導出的函數,以在載入器中輸入 Trampoline 函數,這些函數根據第一個參數分派到適當的層或驅動程式。 vkGet*ProcAddr()呼叫傳回彈翻床調度到的函數指標(即,它直接呼叫核心 API 程式碼)。透過函數指標而不是導出的符號進行呼叫更有效,因為它跳過了彈翻床和調度。

驅動程式枚舉和加載

當建置系統映像時,Android 希望系統知道哪些 GPU 可用。載入器使用hardware.h中現有的HAL機制來發現並載入驅動程式。 32 位元和 64 位元 Vulkan 驅動程式的首選路徑是:

/vendor/lib/hw/vulkan.<ro.hardware.vulkan>.so
/vendor/lib/hw/vulkan.<ro.product.platform>.so
/vendor/lib64/hw/vulkan.<ro.hardware.vulkan>.so
/vendor/lib64/hw/vulkan.<ro.product.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( vkGetInstanceProcAddr()來找到所有其他VkInstance()VkPhysicalDevice()vkGetDeviceProcAddr()函數。

圖層發現和載入

Vulkan 載入器支援枚舉和載入層,這些層可以公開其他擴充並在通往驅動程式的途中攔截核心 API 呼叫。 Android 不包含系統映像上的圖層;但是,應用程式可能會在其 APK 中包含層。

使用層時,請記住 Android 的安全模型和策略與其他平台有很大不同。特別是,Android 不允許將外部程式碼載入到生產(非 root)裝置上的不可偵錯進程中,也不允許外部程式碼檢查或控制進程的記憶體、狀態等。這包括禁止將核心轉儲、API 追蹤等保存到磁碟以供以後檢查。僅在生產設備上啟用作為不可調試應用程式一部分提供的層,且驅動程式不得提供違反這些策略的功能。

層的用例包括:

  • 開發時層- 用於追蹤/分析/調試工具的驗證層和墊片不應安裝在生產設備的系統映像上。用於追蹤/分析/調試工具的驗證層和墊片應該可以在沒有系統映像的情況下進行更新。想要在開發過程中使用這些層之一的開發人員可以修改應用程式包,例如,透過將檔案新增至其本機庫目錄。假設想要診斷交付不可修改應用程式中的故障的 IHV 和 OEM 工程師可以存取系統映像的非生產(root)版本,除非這些應用程式是可偵錯的。有關更多信息,請參閱Android 上的 Vulkan 驗證層
  • 實用程式層-這些層公開擴展,例如為裝置記憶體實現記憶體管理器的層。開發人員選擇要在他們的應用程式中使用的圖層以及這些圖層的版本;使用同一層的不同應用程式可能仍使用不同的版本。開發人員選擇在他們的應用程式包中發布這些層中的哪一個。
  • 注入(隱式)層- 包括用戶或其他應用程式在不知情或未同意的情況下提供的幀速率、社交網路和遊戲啟動器覆蓋層等層。這些違反了 Android 的安全策略並且不受支援。

對於不可調試的應用程序,加載程序僅在應用程式的本機庫目錄中搜尋層,並嘗試加載名稱與特定模式匹配的任何庫(例如libVKLayer_foo.so )。

對於可調試應用程序,載入程式會在/data/local/debug/vulkan中搜尋層,並嘗試載入與特定模式匹配的任何程式庫。

Android 允許透過 Android 和其他平台之間的建置環境變更來移植層。有關層和載入器之間的介面的詳細信息,請參閱Vulkan 載入器介面的架構。 Khronos 維護的驗證層託管在Vulkan 驗證層中。

Vulkan API 版本和功能

下表列出了多個 Android 版本的 Vulkan API 版本。
安卓版本Vulkan版本
安卓13伏爾甘1.3
安卓9伏爾甘1.1
安卓7伏爾甘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 可用性增強。對核心 Vulkan API 進行次要修訂 1.3 所做的所有更改都可以在核心修訂 (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 可用性增強。對核心 Vulkan API 進行次要修訂 1.2 所做的所有更改都可以在核心修訂 (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 可用性增強。對核心 Vulkan API 進行次要修訂 1.1 所做的所有更改都可以在核心修訂 (Vulkan 1.1)中找到。

選擇 Vulkan 支持

Android 裝置應該支援最先進的 Vulkan 功能集,前提是它們支援 64 位元 ABI 並且記憶體不低。

搭載 Android 13 及更高版本的裝置應支援 Vulkan 1.3。

透過 Android 10 啟動的裝置應支援 Vulkan 1.1。

其他設備可以選擇支援 Vulkan 1.3、1.2 和 1.1。

支援Vulkan版本

如果符合以下條件,Android 設備支援 Vulkan 版本:

  1. 新增支援感興趣的 Vulkan 版本的 Vulkan 驅動程式(必須是 Vulkan 版本 1.3、1.1 或 1.0 之一)以及 Android 版本的附加CDD 要求。或者,更新現有 Vulkan 版本號的現有 Vulkan 驅動程式。
  2. 對於 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.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 基線 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 版本實現

VkSurfaceKHRVkSwapchainKHR物件以及與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
);

formatimageUsage參數取自VkSwapchainCreateInfoKHR結構。驅動程式應使用格式和用法所需的 Gralloc 使用標誌填入*grallocConsumerUsage*grallocProducerUsage 。分配緩衝區時,驅動程式傳回的使用標誌與交換鏈使用者請求的使用標誌結合。

Android 7.x 呼叫早期版本的VkSwapchainImageUsageFlagsANDROID() ,名稱為vkGetSwapchainGrallocUsageANDROID() 。 Android 8.0 及更高版本已棄用vkGetSwapchainGrallocUsageANDROID() ,但如果驅動程式未提供vkGetSwapchainGrallocUsage2ANDROID() () ,但如果驅動程式未提供vkGetSwapchainGrallocUsage2ANDROID vkGetSwapchainGrallocUsageANDROID()則仍會呼叫 vkGetSwapchainGrallocUsageANDROID():

VkResult VKAPI vkGetSwapchainGrallocUsageANDROID(
    VkDevice            device,
    VkFormat            format,
    VkImageUsageFlags   imageUsage,
    int*                grallocUsage
);

vkGetSwapchainGrallocUsageANDROID()不支援交換鏈使用標誌或擴展 Gralloc 使用標誌。

Gralloc 支援的圖像

VkNativeBufferANDROID是一個vkCreateImage擴充結構,用於建立由 Gralloc 緩衝區支援的影像。 VkNativeBufferANDROID被提供給VkImageCreateInfo結構鏈中的vkCreateImage() 。在呼叫vkCreateSwapchainKHR期間,會使用VkNativeBufferANDROID來呼叫vkCreateImage() 。 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 及更高版本中,平台在VkImageCreateInfo鏈中提供VkSwapchainImageCreateInfoKHR擴充結構,當交換鏈需要任何交換鏈影像使用標誌時,該結構會提供給vkCreateImage 。擴展結構包含交換鍊圖像使用標誌:

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 。應用程式首先使用連結到VkImageCreateInfo結構的VkImageSwapchainCreateInfoKHR結構呼叫vkCreateImage 。然後,應用程式使用連結到VkBindImageMemoryInfo結構的VkBindImageMemorySwapchainInfoKHR結構呼叫vkBindImageMemory2(KHR)VkBindImageMemorySwapchainInfoKHR結構中指定的imageIndex必須是有效的交換鏈影像索引。同時,平台向VkBindImageMemoryInfo鏈提供了一個VkNativeBufferANDROID擴展結構以及相應的Gralloc緩衝區信息,因此驅動程式知道將VkImage綁定到哪個Gralloc緩衝區。

取得影像

vkAcquireImageANDROID取得交換鏈影像的所有權,並將外部訊號化的本機柵欄匯入到現有的VkSemaphore物件和現有的VkFence物件:

VkResult VKAPI vkAcquireImageANDROID(
    VkDevice            device,
    VkImage             image,
    int                 nativeFenceFd,
    VkSemaphore         semaphore,
    VkFence             fence
);

vkAcquireImageANDROID()vkAcquireNextImageKHR期間調用,將本機柵欄匯入到應用程式提供的VkSemaphoreVkFence物件中(但是,訊號量和柵欄物件在此調用中都是可選的)。驅動程式還可以利用此機會識別和處理 Gralloc 緩衝區狀態的任何外部變更;許多司機不需要在這裡做任何事情。此呼叫將VkSemaphoreVkFence置於相同的掛起狀態,就像由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 實施,其中包括以下內容:

  • CtsDeqpTestCases模組中的Khronos Vulkan 一致性測試,其中包括 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-03-01,這是與 Android 10 的 Vulkan dEQP 測試關聯的日期。如果功能標誌至少為該值,則裝置聲稱通過所有 Android 10 Vulkan dEQP 測試。

0x07E40301對應於日期 2020-03-01,這是與 Android 11 的 Vulkan dEQP 測試關聯的日期。如果功能標誌至少為該值,則設備聲稱通過了所有 Android 11 Vulkan dEQP 測試。

0x07E60301對應於日期 2022-03-01,這是與 Android 13 的 Vulkan dEQP 測試關聯的日期。如果功能標誌至少為該值,則設備聲稱通過了所有 Android 13 Vulkan dEQP 測試。

公開特定功能標誌(0x07E303010x07E403010x07E60301 )的裝置聲稱通過了該功能標誌的所有 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 測試。據報告,此類測試基本通過。