1. Pengantar
Mengapa perlu menggunakan Vulkan dalam game saya?
Vulkan adalah API grafis tingkat rendah utama di Android. Vulkan memungkinkan performa yang lebih tinggi untuk game yang mengimplementasikan game engine dan perendernya sendiri.
Vulkan tersedia di Android mulai Android 7.0 (level API 24). Mulai Android 10.0, dukungan Vulkan 1.1 merupakan persyaratan untuk perangkat Android 64-bit baru. Profil Dasar Pengukuran Android 2022 juga menetapkan versi Vulkan API minimum 1.1.
Game yang memiliki banyak panggilan gambar dan yang menggunakan OpenGL ES dapat mengalami overhead driver yang signifikan karena tingginya biaya pembuatan panggilan gambar dalam OpenGL ES. Game ini dapat terikat dengan CPU karena menghabiskan sebagian besar waktu render frame-nya dalam driver grafis. Game tersebut juga dapat mengalami pengurangan penggunaan CPU dan daya yang signifikan dengan beralih dari OpenGL ES ke Vulkan. Hal ini terutama berlaku jika game memiliki scene kompleks yang tidak dapat menggunakan instance secara efektif untuk mengurangi panggilan gambar.
Yang akan Anda bangun
Dalam codelab ini, Anda akan menggunakan Aplikasi Android C++ dasar dan menambahkan kode untuk menyiapkan pipeline rendering Vulkan. Kemudian, Anda akan mengimplementasikan kode yang menggunakan Vulkan untuk merender segitiga berputar yang bertekstur di layar.
Yang akan Anda butuhkan
- Android Studio Iguana atau yang lebih baru.
- Perangkat Android yang menjalankan Android 10.0 atau yang lebih baru, terhubung ke komputer Anda, dan mengaktifkan Opsi developer dan Proses debug USB.
2. Mempersiapkan
Menyiapkan lingkungan pengembangan Anda
Jika belum pernah menggunakan project native di Android Studio, Anda mungkin perlu menginstal Android NDK dan CMake. Jika Anda sudah menginstalnya, lanjutkan ke Menyiapkan project.
Memastikan SDK, NDK, dan CMake telah diinstal
Luncurkan Android Studio. Saat jendela Welcome to Android Studio ditampilkan, buka menu dropdown Configure lalu pilih opsi SDK Manager.

Jika sudah membuka project, Anda dapat membuka SDK Manager melalui menu Tools. Klik menu Tools lalu pilih SDK Manager. Jendela SDK Manager akan terbuka.
Pada sidebar, pilih secara berurutan: Appearance & Behavior > System Settings > Android SDK. Pilih tab SDK Platforms di panel Android SDK untuk menampilkan daftar opsi alat yang terinstal. Pastikan Android SDK 12.0 atau yang lebih baru telah diinstal.

Selanjutnya, pilih tab SDK Tools, lalu pastikan NDK dan CMake telah diinstal.
Catatan: Versi tepatnya tidak terlalu penting selama versi tersebut cukup baru, tetapi saat ini kita menggunakan NDK 26.1.10909125 dan CMake 3.22.1. Seiring waktu, versi NDK yang terinstal akan berubah secara default dengan rilis NDK berikutnya. Jika Anda perlu menginstal versi NDK tertentu, ikuti petunjuk dalam referensi Android Studio untuk menginstal NDK di bagian "Menginstal versi NDK tertentu".

Setelah semua alat yang diperlukan dicentang, klik tombol Apply di bagian bawah jendela untuk menginstalnya. Anda dapat menutup jendela Android SDK dengan mengklik tombol OK.
Menyiapkan project
Project awal yang berasal dari template C++ telah disiapkan untuk Anda di repositori git. Project awal mengimplementasikan inisialisasi aplikasi dan penanganan peristiwa, tetapi belum melakukan penyiapan atau rendering grafis apa pun.
Meng-clone repo
Dari command line, ubah ke direktori yang ingin Anda sertakan direktori proyek root-nya, lalu clone dari GitHub:
git clone -b codelab/start https://github.com/android/getting-started-with-vulkan-on-android-codelab.git --recurse-submodules
Pastikan Anda memulai dari commit awal repo yang bernama [codelab] start: empty app.
Buka project dengan Android Studio, buat project, lalu jalankan di perangkat yang terpasang. Project akan diluncurkan dengan layar hitam kosong, Anda akan menambahkan rendering grafis di bagian berikutnya.
3. Membuat instance dan perangkat Vulkan
Langkah pertama untuk menginisialisasi penggunaan Vulkan API adalah membuat objek instance Vulkan (VkInstance).
Objek VkInstance mewakili instance aplikasi runtime Vulkan. Objek ini adalah objek root Vulkan API dan digunakan untuk mengambil informasi dan membuat instance objek perangkat Vulkan serta lapisan apa pun yang ingin diaktifkan.
Saat membuat VkInstance, aplikasi harus memberikan informasi tentang aplikasi itu sendiri, seperti nama, versi, dan ekstensi instance Vulkan yang diperlukan.
Desain Vulkan API mencakup sistem lapisan yang menyediakan mekanisme untuk menangkap dan memproses panggilan API sebelum mencapai driver GPU. Aplikasi dapat menetapkan lapisan yang akan diaktifkan saat membuat VkInstance. Lapisan yang paling umum digunakan adalah lapisan validasi Vulkan, yang menyediakan analisis runtime penggunaan API untuk error atau praktik performa yang kurang optimal.
Setelah VkInstance dibuat, aplikasi dapat menggunakannya untuk membuat kueri ke perangkat fisik yang tersedia di sistem, membuat perangkat logis, dan membuat tujuan render platform.
VkInstance biasanya dibuat satu kali di awal aplikasi dan dihancurkan di akhir. Namun, beberapa VkInstance dapat dibuat dalam aplikasi yang sama, misalnya jika aplikasi perlu menggunakan beberapa GPU untuk membuat beberapa jendela.
// CODELAB: hellovk.h
void HelloVK::createInstance() {
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledExtensionCount = (uint32_t)requiredExtensions.size();
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledLayerCount = 0;
createInfo.pNext = nullptr;
VK_CHECK(vkCreateInstance(&createInfo, nullptr, &instance));
}
}
VkPhysicalDevice adalah objek Vulkan yang merepresentasikan perangkat Vulkan fisik di sistem. Sebagian besar perangkat Android hanya akan menampilkan satu VkPhysicalDevice yang merepresentasikan GPU. Namun, PC atau perangkat Android dapat mengenumerasi beberapa perangkat fisik. Misalnya, komputer yang memiliki GPU diskret dan GPU terintegrasi.
Properti VkPhysicalDevice dapat dikueri, seperti nama, vendor, versi driver, dan fitur yang didukung. Informasi ini dapat digunakan untuk memilih perangkat fisik terbaik bagi aplikasi tertentu.
Setelah VkPhysicalDevice dipilih, aplikasi dapat membuat perangkat logis dari objek tersebut. Perangkat logis adalah representasi perangkat fisik yang spesifik untuk aplikasi tersebut. Perangkat ini memiliki status dan resource sendiri dan terpisah dari perangkat logis lain yang mungkin dibuat dari perangkat fisik yang sama.
Ada beragam jenis antrean yang berasal dari berbagai Kelompok Antrean dan setiap kelompok antrean hanya mengizinkan satu subset perintah. Misalnya, mungkin ada kelompok antrean yang hanya mengizinkan pemrosesan perintah komputasi atau yang hanya mengizinkan perintah terkait transfer memori.
VkPhysicalDevice dapat mengenumerasi semua jenis Kelompok Antrean yang tersedia. Kita hanya melihat antrean grafis di sini, tetapi mungkin juga ada antrean tambahan yang hanya mendukung COMPUTE atau TRANSFER. Kelompok Antrean tidak memiliki jenisnya sendiri. Sebagai gantinya, Kelompok Antrean diwakili oleh jenis indeks numerik uint32_t di dalam objek induknya (VkPhysicalDevice).
VkPhysicalDevice dapat membuat beberapa perangkat logis. Hal ini berguna untuk aplikasi yang perlu menggunakan beberapa GPU atau membuat beberapa jendela.
VkDevice adalah objek Vulkan yang mewakili perangkat Vulkan logis. Objek ini adalah abstraksi tipis pada perangkat fisik, dan menyediakan semua fungsi yang diperlukan untuk membuat dan mengelola resource Vulkan, seperti buffer, gambar, dan shader.
VkDevice dibuat dari VkPhysicalDevice dan spesifik untuk aplikasi yang membuatnya. Perangkat ini memiliki status dan resource sendiri dan terpisah dari perangkat logis lain yang mungkin dibuat dari perangkat fisik yang sama.
Objek VkSurfaceKHR merepresentasikan platform yang dapat menjadi target operasi rendering. Untuk menampilkan grafis pada layar perangkat, Anda akan membuat platform menggunakan referensi ke objek jendela aplikasi. Setelah objek VkSurfaceKHR dibuat, aplikasi dapat menggunakannya untuk membuat objek VkSwapchainKHR.
Objek VkSwapchainKHR merepresentasikan infrastruktur yang memiliki buffer yang menjadi tujuan render sebelum memvisualisasikannya di layar. Pada dasarnya, objek ini adalah antrean gambar yang menunggu untuk ditampilkan ke layar. Kita akan memperoleh gambar tersebut untuk digambar, kemudian mengembalikannya ke antrean. Cara kerja antrean dan kondisi untuk menampilkan gambar dari antrean bergantung pada konfigurasi swap chain, tetapi tujuan umum swap chain adalah menyinkronkan tampilan gambar dengan kecepatan refresh layar.
// CODELAB: hellovk.h - Data Types
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool isComplete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
struct ANativeWindowDeleter {
void operator()(ANativeWindow *window) { ANativeWindow_release(window); }
};
Anda dapat menyiapkan dukungan lapisan validasi jika perlu men-debug aplikasi. Anda juga dapat memeriksa ekstensi tertentu yang mungkin diperlukan game.
// CODELAB: hellovk.h
bool HelloVK::checkValidationLayerSupport() {
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for (const char *layerName : validationLayers) {
bool layerFound = false;
for (const auto &layerProperties : availableLayers) {
if (strcmp(layerName, layerProperties.layerName) == 0) {
layerFound = true;
break;
}
}
if (!layerFound) {
return false;
}
}
return true;
}
std::vector<const char *> HelloVK::getRequiredExtensions(
bool enableValidationLayers) {
std::vector<const char *> extensions;
extensions.push_back("VK_KHR_surface");
extensions.push_back("VK_KHR_android_surface");
if (enableValidationLayers) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
return extensions;
}
Setelah menemukan penyiapan yang sesuai dan membuat VkInstance, buat VkSurface yang merepresentasikan jendela yang akan dirender.
// CODELAB: hellovk.h
void HelloVK::createSurface() {
assert(window != nullptr); // window not initialized
const VkAndroidSurfaceCreateInfoKHR create_info{
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
.window = window.get()};
VK_CHECK(vkCreateAndroidSurfaceKHR(instance, &create_info,
nullptr /* pAllocator */, &surface));
}
Enumerasi perangkat fisik (GPU) yang tersedia dan pilih perangkat pertama yang sesuai yang tersedia.
// CODELAB: hellovk.h
void HelloVK::pickPhysicalDevice() {
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
assert(deviceCount > 0); // failed to find GPUs with Vulkan support!
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
for (const auto &device : devices) {