Google致力於提高黑人社區的種族平等。 怎麼看。
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

實施Vulkan

Vulkan是用於高性能3D圖形的低開銷,跨平台API。與OpenGL ES(GLES)一樣 ,Vulkan提供了用於在應用程序中創建高質量,實時圖形的工具。使用Vulkan的優點包括減少CPU開銷並支持SPIR-V Binary Intermediate語言。

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

  • Vulkan加載程序,由Android提供。
  • 由SoC(例如GPU IHV)提供的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庫導出的函數,以在加載程序中輸入蹦床函數,然後根據其第一個參數將其分配到適當的層或驅動程序。 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() ,加載程序可以找到所有其他VkInstance()VkPhysicalDevice()vkGetDeviceProcAddr()函數。

層發現和加載

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 9及更高版本支持Vulkan API版本1.1。 Android 7到Android 9支持Vulkan API版本1.0。有關Vulkan 1.1 API的更多信息,請參閱Vulkan 1.1 API規範

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 1.1

如果滿足以下條件,則Android設備應支持Vulkan 1.1:

  • 與Android 10一起啟動。
  • 支持64位ABI。
  • 內存不足。

其他設備可以選擇支持Vulkan 1.1。

要實現Vulkan 1.1:

  1. 添加支持Vulkan 1.1以及其他Android 1.1 CDD要求的Vulkan驅動程序,或更新現有的Vulkan 1.0驅動程序。
  2. 通過將以下規則添加至適當的device.mk文件PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000)確保PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000)返回true
    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
    

窗口系統集成(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版本實現

VkSurfaceKHRVkSwapchainKHRVkSurfaceKHR以及與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
);

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

Android 7.x調用了名為vkGetSwapchainGrallocUsageANDROID()VkSwapchainImageUsageFlagsANDROID()的早期版本。 Android的8.0和更高不贊成vkGetSwapchainGrallocUsageANDROID()但仍呼籲vkGetSwapchainGrallocUsageANDROID()如果vkGetSwapchainGrallocUsage2ANDROID()不是由驅動程序提供:

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

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

Gralloc支持的圖像

VkNativeBufferANDROIDvkCreateImage擴展結構,用於創建由Gralloc緩衝區支持的映像。 VkNativeBufferANDROID提供給VkImageCreateInfo結構鏈中的VkImageCreateInfo vkCreateImage() 。調用vkCreateImage()VkNativeBufferANDROID在第一次調用期間發生vkGetSwapChainInfoWSI(.. VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI ..) 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               = VkSwapChainCreateInfoWSI::imageUsageFlags
  .flags               = 0
  .sharingMode         = VkSwapChainCreateInfoWSI::sharingMode
  .queueFamilyCount    = VkSwapChainCreateInfoWSI::queueFamilyCount
  .pQueueFamilyIndices = VkSwapChainCreateInfoWSI::pQueueFamilyIndices

在Android中8.0和更高的,該平台提供了一種VkSwapchainImageCreateInfo在延伸結構VkImageCreateInfo提供給鏈vkCreateImage當需要用於swapchain任何swapchain圖像使用標誌。擴展結構包含交換鏈圖像使用標誌:

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,所以福爾康應用程序能夠創建一個VkImage背靠swapchain內存。該應用程序首先調用vkCreateImageVkImageSwapchainCreateInfoKHR鏈的結構VkImageCreateInfo結構。然後,應用程序調用vkBindImageMemory2(KHR)VkBindImageMemorySwapchainInfoKHR拴在結構VkBindImageMemoryInfo結構。 VkBindImageMemorySwapchainInfoKHR結構中指定的imageIndex必須是有效的交換鏈圖像索引。同時,平台提供了一個VkNativeBufferANDROID擴展結構以及對應的Gralloc緩衝區信息到VkBindImageMemoryInfo鏈,因此驅動程序知道將哪個Gralloc緩衝區與VkImage綁定。

獲取圖像

vkAcquireImageANDROID獲取交換鏈圖像的所有權,並將外部發出信號的本機柵欄導入到現有的VkSemaphore對象和現有的VkFence像中:

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

vkAcquireNextImageKHR期間調用vkAcquireImageANDROID() ,以將本機圍欄導入到應用程序提供的VkSemaphoreVkFenceVkSemaphore (但是,此調用中的semaphore和fence對像都是可選的)。驅動程序還可以利用此機會來識別和處理對Gralloc緩衝區狀態的任何外部更改;許多司機在這裡不需要做任何事情。這個調用把VkSemaphoreVkFence到同一掛起狀態vkQueueSignalSemaphorevkQueueSubmit分別,所以隊列可以等待信號量和應用程序可以等待觀望。

當基礎原生圍欄發出信號時,兩個對像都將發出信號。如果本機的籬笆已經發出信號,則此函數返回時,信號量處於已發出信號的狀態。驅動程序將擁有隔離文件描述符的所有權,並在不再需要時關閉隔離文件描述符。即使沒有提供信號量或籬笆對象,或者即使vkAcquireImageANDROID失敗並返回錯誤,驅動程序也必須這樣做。如果fenceFd為-1,則好像已經發出了本機籬笆的信號。

發布圖像

vkQueueSignalReleaseImageANDROID準備供外部使用的交換鏈映像,創建本機防護,並在輸入信號已發出信號後安排要發送本機防護的信號:

VkResult VKAPI vkQueueSignalReleaseImageANDROID(
    VkQueue             queue,
    uint32_t            waitSemaphoreCount,
    const VkSemaphore*  pWaitSemaphores,
    VkImage             image,
    int*                pNativeFenceFd
);

vkQueuePresentKHR()在提供的隊列上調用vkQueueSignalReleaseImageANDROID() 。驅動程序必須生成一個本機的柵欄,該柵欄直到waitSemaphoreCount中的所有waitSemaphoreCount信號都pWaitSemaphores信號,並且準備演示image所需的任何其他工作完成。

如果已經發出等待信號(如果有的話),並且queue已經空閒,則驅動程序可以將*pNativeFenceFd設置為-1而不是實際的本機fence文件描述符,表明沒有什麼可等待的。調用者擁有並關閉*pNativeFenceFd返回的*pNativeFenceFd

許多驅動程序可以忽略image參數,但是有些驅動程序可能需要準備與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擴展,則加載程序不會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的功能性API測試。
  • CtsGraphicsTestCases模塊,用於測試設備是否針對其支持的Vulkan功能進行了正確配置。