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