Menerapkan Vulkan

Vulkan adalah API lintas platform dengan overhead rendah untuk grafis 3D berperforma tinggi. Seperti OpenGL ES (GLES) , Vulkan menyediakan alat untuk membuat grafik real-time berkualitas tinggi dalam aplikasi. Keuntungan menggunakan Vulkan termasuk pengurangan overhead CPU dan dukungan untuk bahasa SPIR-V Binary Intermediate .

Agar berhasil mengimplementasikan Vulkan, perangkat harus menyertakan:

  • Pemuat Vulkan, disediakan oleh Android.
  • Driver Vulkan, yang disediakan oleh SoC seperti GPU IHV, yang mengimplementasikan Vulkan API . Untuk mendukung fungsionalitas Vulkan, perangkat Android memerlukan perangkat keras GPU berkemampuan Vulkan dan driver terkait. GPU juga harus mendukung GLES 3.1 dan yang lebih tinggi. Konsultasikan dengan vendor SoC Anda untuk meminta dukungan driver.

Jika perangkat menyertakan driver Vulkan, perangkat perlu mendeklarasikan fitur sistem FEATURE_VULKAN_HARDWARE_LEVEL dan FEATURE_VULKAN_HARDWARE_VERSION , dengan versi yang secara akurat mencerminkan kemampuan perangkat. Ini membantu memastikan bahwa perangkat sesuai dengan Compatibility Definition Document (CDD).

Pemuat Vulkan

platform/frameworks/native/vulkan pemuat Vulkan adalah antarmuka utama antara aplikasi Vulkan dan driver Vulkan perangkat. Pemuat Vulkan dipasang di /system/lib[64]/libvulkan.so . Loader menyediakan titik masuk API Vulkan inti, serta titik masuk ekstensi yang diperlukan oleh CDD Android. Ekstensi Integrasi Sistem Jendela (WSI) diekspor oleh loader dan terutama diimplementasikan di loader daripada di driver. Loader juga mendukung enumerasi dan memuat lapisan yang dapat mengekspos ekstensi tambahan dan mencegat panggilan API inti dalam perjalanannya ke driver.

NDK menyertakan pustaka stub libvulkan.so untuk penautan. Pustaka mengekspor simbol yang sama dengan pemuat. Aplikasi memanggil fungsi yang diekspor dari pustaka libvulkan.so asli untuk memasukkan fungsi trampolin di pemuat, yang mengirimkan ke lapisan atau driver yang sesuai berdasarkan argumen pertama mereka. vkGet*ProcAddr() mengembalikan pointer fungsi yang dikirim oleh trampolin (yaitu, panggilan langsung ke kode API inti). Memanggil melalui penunjuk fungsi, daripada simbol yang diekspor, lebih efisien karena melewatkan trampolin dan pengiriman.

Pencacahan dan pemuatan driver

Saat citra sistem dibuat, Android mengharapkan sistem mengetahui GPU mana yang tersedia. Loader menggunakan mekanisme HAL yang ada di hardware.h untuk menemukan dan memuat driver. Jalur yang dipilih untuk driver Vulkan 32-bit dan 64-bit adalah:

/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

Di Android 7.0 dan yang lebih tinggi, turunan hw_module_t Vulkan membungkus satu struct hw_module_t ; hanya satu driver yang didukung dan string konstan HWVULKAN_DEVICE_0 diteruskan ke open() .

Turunan hw_device_t Vulkan sesuai dengan driver tunggal yang dapat mendukung beberapa perangkat fisik. Struktur hw_device_t dapat diperluas untuk mengekspor vkGetGlobalExtensionProperties() , vkCreateInstance() , dan vkGetInstanceProcAddr() . Loader dapat menemukan semua VkInstance() , VkPhysicalDevice() , dan vkGetDeviceProcAddr() lainnya dengan memanggil struktur hw_device_t vkGetInstanceProcAddr() .

Penemuan dan pemuatan lapisan

Pemuat Vulkan mendukung enumerasi dan memuat lapisan yang dapat mengekspos ekstensi tambahan dan mencegat panggilan API inti dalam perjalanannya ke driver. Android tidak menyertakan lapisan pada citra sistem; namun, aplikasi mungkin menyertakan lapisan dalam APK-nya.

Saat menggunakan lapisan, perlu diingat bahwa model dan kebijakan keamanan Android berbeda secara signifikan dari platform lain. Secara khusus, Android tidak mengizinkan pemuatan kode eksternal ke dalam proses yang tidak dapat di-debug pada perangkat produksi (tidak di-root), juga tidak mengizinkan kode eksternal untuk memeriksa atau mengontrol memori, status, dan sebagainya proses tersebut. Ini termasuk larangan menyimpan dump inti, jejak API, dan sebagainya ke disk untuk pemeriksaan nanti. Hanya lapisan yang dikirimkan sebagai bagian dari aplikasi yang tidak dapat di-debug yang diaktifkan pada perangkat produksi, dan driver tidak boleh menyediakan fungsionalitas yang melanggar kebijakan ini.

Kasus penggunaan untuk lapisan meliputi:

  • Lapisan waktu pengembangan — Lapisan validasi dan shim untuk alat tracing/profiling/debugging tidak boleh dipasang pada citra sistem perangkat produksi. Lapisan validasi dan shim untuk alat tracing/profiling/debugging harus dapat diperbarui tanpa citra sistem. Pengembang yang ingin menggunakan salah satu lapisan ini selama pengembangan dapat memodifikasi paket aplikasi, misalnya, dengan menambahkan file ke direktori pustaka asli mereka. Insinyur IHV dan OEM yang ingin mendiagnosis kegagalan dalam mengirimkan aplikasi yang tidak dapat dimodifikasi dianggap memiliki akses ke build nonproduksi (berakar) dari citra sistem, kecuali aplikasi tersebut dapat di-debug. Untuk informasi lebih lanjut, lihat lapisan validasi Vulkan di Android .
  • Lapisan utilitas — Lapisan ini mengekspos ekstensi, seperti lapisan yang mengimplementasikan manajer memori untuk memori perangkat. Pengembang memilih lapisan, dan versi lapisan tersebut, untuk digunakan dalam aplikasi mereka; aplikasi yang berbeda menggunakan lapisan yang sama mungkin masih menggunakan versi yang berbeda. Pengembang memilih lapisan mana yang akan dikirim dalam paket aplikasi mereka.
  • Lapisan yang disuntikkan (implisit) — Mencakup lapisan seperti kecepatan bingkai, jaringan sosial, dan lapisan peluncur game yang disediakan oleh pengguna atau aplikasi lain tanpa sepengetahuan atau persetujuan aplikasi. Ini melanggar kebijakan keamanan Android dan tidak didukung.

Untuk aplikasi yang tidak dapat di-debug, pemuat mencari lapisan hanya di direktori pustaka asli aplikasi dan mencoba memuat pustaka apa pun dengan nama yang cocok dengan pola tertentu (misalnya, libVKLayer_foo.so ).

Untuk aplikasi yang dapat di-debug, pemuat mencari lapisan di /data/local/debug/vulkan dan mencoba memuat pustaka apa pun yang cocok dengan pola tertentu.

Android memungkinkan lapisan untuk di-porting dengan perubahan build-environment antara Android dan platform lainnya. Untuk detail tentang antarmuka antara lapisan dan pemuat, lihat Arsitektur Antarmuka Pemuat Vulkan . Lapisan validasi yang dikelola Khronos dihosting di Lapisan Validasi Vulkan .

Versi dan kemampuan Vulkan API

Android 9 dan yang lebih tinggi mendukung Vulkan API versi 1.1. Android 7 hingga Android 9 mendukung Vulkan API versi 1.0. Untuk informasi selengkapnya tentang Vulkan 1.1 API, lihat spesifikasi Vulkan 1.1 API .

Ikhtisar dukungan Vulkan 1.1

Vulkan 1.1 menyertakan dukungan untuk memori/sinkronisasi interop, yang memungkinkan OEM untuk mendukung Vulkan 1.1 pada perangkat. Selain itu, interop memori/sinkronisasi memungkinkan pengembang untuk menentukan apakah Vulkan 1.1 didukung pada perangkat, dan menggunakannya secara efektif saat itu. Vulkan 1.1 memiliki persyaratan perangkat keras yang sama dengan Vulkan 1.0, tetapi sebagian besar implementasinya ada di driver grafis khusus SOC, bukan di framework.

Fitur Vulkan 1.1 yang paling penting untuk Android adalah:

  • Dukungan untuk mengimpor dan mengekspor buffer memori dan objek sinkronisasi dari luar Vulkan (untuk interop dengan kamera, codec, dan GLES)
  • Dukungan untuk format YCbCr

Vulkan 1.1 juga menyertakan beberapa fitur yang lebih kecil dan peningkatan kegunaan API.

Menerapkan Vulkan 1.1

Perangkat Android harus mendukung Vulkan 1.1 jika:

  • Luncurkan dengan Android 10.
  • Mendukung ABI 64-bit.
  • Bukan memori rendah.

Perangkat lain secara opsional dapat mendukung Vulkan 1.1.

Untuk mengimplementasikan Vulkan 1.1:

  1. Tambahkan driver Vulkan yang mendukung Vulkan 1.1 plus persyaratan CDD Android 1.1 tambahan , atau perbarui driver Vulkan 1.0 yang ada.
  2. Pastikan PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000) mengembalikan nilai true dengan menambahkan aturan seperti berikut ke file device.mk yang sesuai: l10n
    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
    

Integrasi Sistem Jendela (WSI)

Di libvulkan.so , driver mengimplementasikan ekstensi Integrasi Sistem Jendela (WSI) berikut:

  • VK_KHR_surface
  • VK_KHR_android_surface
  • VK_KHR_swapchain
  • VK_KHR_driver_properties , diimplementasikan untuk Vulkan 1.1 hanya di Android 10
  • VK_GOOGLE_display_timing , diimplementasikan untuk versi Vulkan apa pun di Android 10

VkSurfaceKHR dan VkSwapchainKHR dan semua interaksi dengan ANativeWindow ditangani oleh platform dan tidak diekspos ke driver. Implementasi WSI bergantung pada ekstensi VK_ANDROID_native_buffer , yang harus didukung oleh driver; ekstensi ini hanya digunakan oleh implementasi WSI dan tidak diekspos ke aplikasi.

Bendera penggunaan Gralloc

Implementasi Vulkan mungkin memerlukan buffer swapchain untuk dialokasikan dengan flag penggunaan Gralloc pribadi yang ditentukan implementasi. Saat membuat swapchain, Android meminta driver untuk menerjemahkan format yang diminta dan flag penggunaan gambar ke flag penggunaan Gralloc dengan memanggil:

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
);

Parameter format dan imageUsage diambil dari struktur VkSwapchainCreateInfoKHR . Pengemudi harus mengisi *grallocConsumerUsage dan *grallocProducerUsage dengan flag penggunaan Gralloc yang diperlukan untuk format dan penggunaan. Flag penggunaan yang dikembalikan oleh driver digabungkan dengan flag penggunaan yang diminta oleh konsumen swapchain saat mengalokasikan buffer.

Android 7.x memanggil versi sebelumnya dari VkSwapchainImageUsageFlagsANDROID() , bernama vkGetSwapchainGrallocUsageANDROID() . Android 8.0 dan yang lebih tinggi tidak lagi vkGetSwapchainGrallocUsageANDROID() tetapi masih memanggil vkGetSwapchainGrallocUsageANDROID() jika vkGetSwapchainGrallocUsage2ANDROID() tidak disediakan oleh driver:

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

vkGetSwapchainGrallocUsageANDROID() tidak mendukung flag penggunaan swapchain atau flag penggunaan Gralloc yang diperluas.

Gambar yang didukung Gralloc

VkNativeBufferANDROID adalah struktur ekstensi vkCreateImage untuk membuat gambar yang didukung oleh buffer Gralloc. VkNativeBufferANDROID disediakan untuk vkCreateImage() dalam rantai struktur VkImageCreateInfo . Panggilan ke vkCreateImage() dengan VkNativeBufferANDROID terjadi selama panggilan ke vkCreateSwapchainKHR . Implementasi WSI mengalokasikan jumlah buffer asli yang diminta untuk swapchain, lalu membuat VkImage untuk masing-masing buffer:

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;

Saat membuat gambar yang didukung Gralloc, VkImageCreateInfo memiliki data berikut:

  .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

Di Android 8.0 dan yang lebih tinggi, platform menyediakan struktur ekstensi VkSwapchainImageCreateInfoKHR dalam rantai VkImageCreateInfo yang disediakan untuk vkCreateImage saat flag penggunaan gambar swapchain diperlukan untuk swapchain. Struktur ekstensi berisi flag penggunaan gambar swapchain:

typedef struct {
    VkStructureType                        sType; // must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID
    const void*                            pNext;

    VkSwapchainImageUsageFlagsANDROID      usage;
} VkSwapchainImageCreateInfoANDROID;

Di Android 10 dan yang lebih tinggi, platform mendukung VK_KHR_swapchain v70, sehingga aplikasi Vulkan dapat membuat VkImage yang didukung oleh memori swapchain. Aplikasi pertama-tama memanggil vkCreateImage dengan struktur VkImageSwapchainCreateInfoKHR yang dirantai ke struktur VkImageCreateInfo . Kemudian aplikasi memanggil vkBindImageMemory2(KHR) dengan struktur VkBindImageMemorySwapchainInfoKHR yang dirantai ke struktur VkBindImageMemoryInfo . imageIndex ditentukan dalam struktur VkBindImageMemorySwapchainInfoKHR harus berupa indeks gambar swapchain yang valid. Sementara itu, platform menyediakan struktur ekstensi VkNativeBufferANDROID dengan informasi buffer Gralloc yang sesuai ke rantai VkBindImageMemoryInfo , sehingga pengemudi mengetahui buffer Gralloc mana yang akan digunakan untuk mengikat VkImage .

Mendapatkan gambar

vkAcquireImageANDROID memperoleh kepemilikan gambar swapchain dan mengimpor pagar asli bersinyal eksternal ke objek VkFence yang ada dan objek VkSemaphore yang ada:

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

vkAcquireImageANDROID() dipanggil selama vkAcquireNextImageKHR untuk mengimpor pagar asli ke objek VkSemaphore dan VkFence yang disediakan oleh aplikasi (namun, objek semafor dan pagar adalah opsional dalam panggilan ini). Pengemudi juga dapat menggunakan kesempatan ini untuk mengenali dan menangani setiap perubahan eksternal pada status buffer Gralloc; banyak pengemudi tidak perlu melakukan apa pun di sini. Panggilan ini menempatkan VkSemaphore dan VkFence ke status tertunda yang sama seperti jika diberi tanda oleh vkQueueSubmit , sehingga antrian dapat menunggu di semaphore dan aplikasi dapat menunggu di pagar.

Kedua objek menjadi diberi sinyal ketika pagar asli yang mendasarinya memberi sinyal; jika pagar asli sudah memberi sinyal, maka semaphore berada dalam status sinyal saat fungsi ini kembali. Pengemudi mengambil kepemilikan deskriptor file pagar dan menutup deskriptor file pagar saat tidak lagi diperlukan. Pengemudi harus melakukannya meskipun tidak ada objek semaphore atau pagar yang disediakan, atau bahkan jika vkAcquireImageANDROID gagal dan mengembalikan kesalahan. Jika fenceFd adalah -1, seolah-olah pagar asli sudah diberi sinyal.

Melepaskan gambar

vkQueueSignalReleaseImageANDROID menyiapkan gambar swapchain untuk penggunaan eksternal, membuat pagar asli, dan menjadwalkan pagar asli untuk diberi sinyal setelah semafor input memberi sinyal:

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

vkQueuePresentKHR() memanggil vkQueueSignalReleaseImageANDROID() pada antrean yang disediakan. Pengemudi harus menghasilkan pagar asli yang tidak memberi sinyal sampai semua semaphore waitSemaphoreCount dalam sinyal pWaitSemaphores , dan pekerjaan tambahan apa pun yang diperlukan untuk menyiapkan image untuk presentasi selesai.

Jika semafor tunggu (jika ada) sudah ditandai, dan queue sudah tidak digunakan, driver dapat mengatur *pNativeFenceFd ke -1 alih-alih deskriptor file pagar asli yang sebenarnya, yang menunjukkan bahwa tidak ada yang perlu ditunggu. Pemanggil memiliki dan menutup deskriptor file yang dikembalikan dalam *pNativeFenceFd .

Banyak driver dapat mengabaikan parameter gambar, tetapi beberapa mungkin perlu menyiapkan struktur data sisi CPU yang terkait dengan buffer Gralloc untuk digunakan oleh konsumen gambar eksternal. Menyiapkan konten buffer untuk digunakan oleh konsumen eksternal harus dilakukan secara asinkron sebagai bagian dari transisi gambar ke VK_IMAGE_LAYOUT_PRESENT_SRC_KHR .

Jika gambar dibuat dengan VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID , maka driver harus mengizinkan vkQueueSignalReleaseImageANDROID() dipanggil berulang kali tanpa mengganggu panggilan ke vkAcquireImageANDROID() .

Berbagi dukungan gambar yang rapi

Beberapa perangkat dapat berbagi kepemilikan satu gambar antara saluran tampilan dan implementasi Vulkan untuk meminimalkan latensi. Di Android 9 dan yang lebih tinggi, loader secara kondisional mengiklankan ekstensi VK_KHR_shared_presentable_image berdasarkan respons pengemudi terhadap panggilan ke vkGetPhysicalDeviceProperties2 .

Jika driver tidak mendukung ekstensi Vulkan 1.1 atau VK_KHR_physical_device_properties2 , loader tidak mengiklankan dukungan untuk gambar yang dapat dibagikan. Jika tidak, loader akan menanyakan kemampuan driver dengan memanggil vkGetPhysicalDeviceProperties2() dan menyertakan struktur berikut dalam rantai VkPhysicalDeviceProperties2::pNext :

typedef struct {
    VkStructureType sType; // must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID
    const void*     pNext;
    VkBool32        sharedImage;
} VkPhysicalDevicePresentationPropertiesANDROID;

Jika pengemudi dapat berbagi kepemilikan gambar dengan sistem tampilan, itu menyetel anggota sharedImage ke VK_TRUE .

Validasi

OEM dapat menguji implementasi Vulkan mereka menggunakan CTS, yang meliputi:

  • Pengujian Kesesuaian Khronos Vulkan dalam modul CtsDeqpTestCases , yang mencakup pengujian API fungsional untuk Vulkan 1.0 dan 1.1.
  • Modul CtsGraphicsTestCases , yang menguji apakah perangkat dikonfigurasi dengan benar untuk kemampuan Vulkan yang didukungnya.

Bendera fitur Vulkan

Perangkat yang mendukung Android 11 atau lebih tinggi dan yang mendukung Vulkan API diperlukan untuk mengekspos tanda fitur, android.software.vulkan.deqp.level . Nilai dari tanda fitur ini adalah tanggal, dikodekan sebagai nilai integer. Ini menentukan tanggal yang terkait dengan tes Vulkan dEQP yang diklaim perangkat untuk lulus.

Tanggal dalam bentuk YYYY-MM-DD dikodekan sebagai bilangan bulat 32-bit sebagai berikut:

  • Bit 0-15 menyimpan tahun
  • Bit 16-23 menyimpan bulan
  • Bit 24-31 menyimpan hari ini

Nilai minimum yang diizinkan untuk tanda fitur adalah 0x07E30301 , yang sesuai dengan tanggal 03-01-2019, yang merupakan tanggal yang terkait dengan pengujian Vulkan dEQP untuk Android 10. Jika tanda fitur setidaknya bernilai ini, perangkat akan mengklaim lulus semua tes dEQP Android 10 Vulkan.

Nilai 0x07E40301 sesuai dengan tanggal 03-01-2020, yang merupakan tanggal yang terkait dengan pengujian dEQP Vulkan untuk Android 11. Jika tanda fitur setidaknya memiliki nilai ini, perangkat mengklaim lulus semua pengujian dEQP Android 11 Vulkan.

Jika nilai tanda fitur setidaknya 0x07E30301 tetapi kurang dari 0x07E40301 , ini berarti perangkat mengklaim lulus semua pengujian dEQP Android 10 Vulkan tetapi tidak dijamin lulus pengujian Vulkan dEQP yang ditambahkan untuk Android 11.

Vulkan dEQP merupakan bagian dari Android CTS. Dari Android 11, komponen runner pengujian dEQP dari CTS mengetahui tanda fitur android.software.vulkan.deqp.level , dan melewati semua pengujian dEQP Vulkan yang - menurut tanda fitur ini - tidak diklaim oleh perangkat untuk didukung. Tes semacam itu dilaporkan lulus sepele.