## Get started with Vulkan on Android

Vulkan is the primary low-level graphics API on Android. Vulkan provides optimal
performance for games that implement their own game engine and renderer.

To successfully implement Vulkan in your game engine you must:

- Identify which Android devices to use with Vulkan
- Understand the tradeoffs of supporting older Android devices
- Add Vulkan to your Android build target
- Choose a shader compiler to create SPIR-V for Vulkan
- Determine the available Vulkan API version at runtime
- Learn how to optimize your Vulkan rendering operations with Vulkan profiles, frame pacing, and pre-rotation
- Select graphics tools for debugging and performance analysis

<!-- -->

**Note:** For information on using Vulkan on Android with the Unity or Unreal game engines, see:
- [Vulkan on Unity](https://developer.android.com/games/develop/vulkan/game-engine-support#unity)
- [Vulkan on Unreal](https://developer.android.com/games/develop/vulkan/game-engine-support#unreal)

## Choose minimum device specifications for Vulkan

Vulkan is available on Android beginning with Android 7.0 (API level 24). Not
all Android devices running Android 7.0 or higher support Vulkan. You need to
determine which Vulkan-capable Android devices your game supports.

### Recommendations

Use the following specifications as minimum requirements for Vulkan support:

- Device is running Android 10.0 (API level 29) or higher
- Device supports Vulkan API version 1.1 or higher
- Device has hardware capabilities and features compatible with the 2022 [Android Baseline profile](https://developer.android.com/ndk/guides/graphics/android-baseline-profile)

| **Note:** Vulkan 1.1 support is a requirement for *new* 64-bit Android devices beginning with Android 10.0. The 2022 Android Baseline profile also sets a minimum Vulkan API version of 1.1. Most, but not all, Vulkan 1.1--capable devices are compatible with the 2022 Android Baseline profile. For compatibility statistics, visit the [Distribution dashboard](https://developer.android.com/about/dashboards#Vulkan).

### Older device support

If your game is designed to run on a wide range of devices with varying levels
of graphics capabilities, you may need to support devices older than those
recommended in [Choose minimum devices specifications for Vulkan](https://developer.android.com/games/develop/vulkan/native-engine-support#choose-minimum).
Before building support for older devices, evaluate whether Vulkan provides
benefits to your game. Games that have lots of draw calls and that use OpenGL ES
can see significant driver overhead due to the high cost of making draw calls
within OpenGL ES. These games can become CPU bound from spending large portions
of their frame time in the graphics driver. The games can also see significant
reductions in CPU and power use by switching from OpenGL ES to Vulkan. This is
especially applicable if your game has complex scenes that can't effectively use
instancing to reduce draw calls. When targeting older devices, include OpenGL ES
rendering support as a fallback, as some devices in your target device list may
have Vulkan implementations that can't run your game reliably.

You may not want to support older Vulkan-capable devices because they lack
performance and features or have stability issues.

#### Performance and Features

Older Vulkan-capable Android devices may not have the rendering performance or
hardware support for features needed to run your game. This is especially likely
if your game has high-fidelity graphics and Vulkan is the only API you are
targeting on Android. Many older devices are limited to version 1.0.3 of the
Vulkan API and are often missing widely used Vulkan extensions available on more
modern hardware.

#### Stability

Older Android devices could be using out-of-date Vulkan drivers. These driver
versions might include bugs that can affect the stability of your game. Working
around driver bugs can involve significant amounts of testing and engineering
time.

## Add Vulkan to your project

To add Vulkan to your project you need to:

- Include Vulkan API headers
- Compile shader code to SPIR-V
- Call the Vulkan API at runtime

### Include Vulkan API headers

Your game needs to include the Vulkan API header files to compile code that uses
Vulkan. You can find a copy of the Vulkan headers in the [Android NDK](https://developer.android.com/ndk) or
packaged in [Vulkan SDK releases](https://www.vulkan.org/tools#download-these-essential-development-tools). Any particular NDK version
only includes Vulkan headers available at the time of the NDK release. If you
use Vulkan headers from the NDK, use NDK version 25 or higher, which includes
header files that support Vulkan version 1.3. The Vulkan SDK has the most
current version of the headers.

### Compile shader code to SPIR-V

The Vulkan API expects shader programs to be provided in the SPIR-V binary
intermediate format. This convention is different from OpenGL ES, where you
could submit source code written in the
[OpenGL Shading Language](https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language) (GLSL) as text
strings. Use a shader compiler to take code written in a shader
language such as GLSL or the [High-level Shader Language](https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl) (HLSL)
and compile it into SPIR-V modules for use with Vulkan.

The [shaderc](https://github.com/google/shaderc) compiler can be used to compile shader programs
written in GLSL into SPIR-V. If your game uses HLSL, the
[DirectXShaderCompiler](https://github.com/microsoft/DirectXShaderCompiler) supports SPIR-V output. Typically, you
compile shader programs offline as part of the asset build process for
your game and include the SPIR-V modules as part of your runtime assets.

### Call the Vulkan API at runtime

To call the Vulkan API, your game needs to obtain function pointers to Vulkan
API calls. The most straightforward way to do this is to link against the
`libvulkan.so` shared library, which is included in the Android NDK. Linking
against the library has two shortcomings: additional function dispatch overhead
and limitations on which Vulkan API function pointers are automatically
resolved.

When you call a Vulkan API function, control passes through a [dispatch
table](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderInterfaceArchitecture.md#dispatch-tables-and-call-chains) managed by a construct called the Vulkan loader. Android
uses its own [Vulkan loader](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/native/vulkan/libvulkan/) implementation and not the LunarG
loader. This loader system is part of the layer architecture of the Vulkan API.
Linking to the system library at build time results in an additional dispatch
level for a given API call. While the overhead is small, it can be noticeable
for games that perform high volumes of Vulkan calls.

The system library generally only resolves pointers to Vulkan functions that are
considered part of the core API. Vulkan has a large number of extensions, which
define additional Vulkan functions, many of which are not automatically resolved
by the system library. You need to manually resolve pointers to these Vulkan
functions before using them.

To mitigate these issues, dynamically resolve pointers to all Vulkan functions
you intend to use at runtime. One way to accomplish this is by using an
open source meta-loader library such as [volk](https://github.com/zeux/volk). The
[AGDKTunnel](https://github.com/android/games-samples/tree/main/agdk/agdktunnel) sample game integrates volk for this purpose. If
you are using a meta-loader library, don't link against the `libvulkan.so`
shared library in your build scripts.

## Determine the available Vulkan API version

Android supports the following Vulkan API versions:

- 1.0.3
- 1.1
- 1.3

The highest Vulkan API version number available on a given device is determined
by Android version and Vulkan driver support.

### Android version

Platform support for a Vulkan API version is dependent on a minimum Android
version (API level):

- 1.3 --- Android 13.0 (API level 33) and higher
- 1.1 --- Android 10.0 (API level 29) and higher
- 1.0.3 --- Android 7.0 (API level 24) and higher

### Vulkan driver support

Android platform support for a Vulkan API version does not guarantee the API
version is supported by the device's Vulkan driver. A device running Android 13
might only support version 1.1 of the Vulkan API.

When initializing Vulkan, don't request an API version greater than:

- The maximum Vulkan API version for the version of Android running on the device
- The Vulkan API version reported by [vkEnumerateInstanceVersion](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceVersion.html)
- The Vulkan API version reported by the `apiVersion` property of the [VkPhysicalDeviceProperties](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html) structure

An example of determining the highest supported Vulkan API version follows:  

    // Minimum Android API levels for Vulkan 1.3/1.1 version support
    static constexpr int kMinimum_vk13_api_level = 33;
    static constexpr int kMinimum_vk11_api_level = 29;

    uint32_t GetHighestSupportedVulkanVersion(VkPhysicalDevice physical_device) {
      uint32_t instance_api_version = 0;
      vkEnumerateInstanceVersion(&instance_api_version);

      VkPhysicalDeviceProperties device_properties;
      vkGetPhysicalDeviceProperties(physical_device, &device_properties);

      // Instance and device versions don't have to match, use the lowest version
      // number for API support if they don't.
      const uint32_t driver_api_version =
          (instance_api_version < device_properties.apiVersion) ?
          instance_api_version : device_properties.apiVersion;

      const int device_api_level = android_get_device_api_level();
      if (device_api_level >= kMinimum_vk13_api_level &&
          driver_api_version >= VK_API_VERSION_1_3) {
        return VK_API_VERSION_1_3;
      } else if (device_api_level >= kMinimum_vk11_api_level &&
                 driver_api_version >= VK_API_VERSION_1_1) {
        return VK_API_VERSION_1_1;
      }
      return VK_API_VERSION_1_0;
    }

## Determine Vulkan profile compatibility

Vulkan profiles are JSON files that define a set of required features,
extensions, capabilities, and minimum parameter limits that a Vulkan device must
support to be compatible with the profile. To determine if a device is
compatible with a specific Vulkan profile, such as the 2022 [Android Baseline
profile](https://developer.android.com/ndk/guides/graphics/android-baseline-profile), use the open source [Vulkan Profiles API library](https://github.com/KhronosGroup/Vulkan-Profiles/blob/main/OVERVIEW.md).
You can also parse the profile JSON file yourself and query device capabilities
using the relevant Vulkan APIs to determine profile compatibility.

### Vulkan Profiles

Android is using [Vulkan Profiles](https://vulkan.lunarg.com/doc/sdk/1.3.280.0/windows/profiles_definitions.html)
which defines which features and extensions are available for each of the
devices running Android.

Android Baseline Profile (ABP) is the first attempt at building Vulkan Profile.
[ABP2021](https://github.com/KhronosGroup/Vulkan-Profiles/blob/main/profiles/VP_ANDROID_baseline_2021.json) and [ABP2022](https://github.com/KhronosGroup/Vulkan-Profiles/blob/main/profiles/VP_ANDROID_baseline_2022.json)
are backward looking profiles aimed to cover \> 85% of active devices at that
time. There will be no new ABP going forward.

Vulkan Profiles for Android (VPA) is the new forward looking profile aimed to
reflect the needs of software developers and drive consistent features as soon
as hardware developers can deliver them.
[VPA15_minimums](https://github.com/KhronosGroup/Vulkan-Profiles/blob/main/profiles/VP_ANDROID_15_minimums.json)
is the first profile for Android 15 and there will be a new VPA every year to
cover each major Android release.

## Implement frame pacing

Proper frame pacing is an essential part of delivering a high-quality gameplay
experience. The Android Game Development Kit includes the [Frame Pacing
library](https://developer.android.com/games/sdk/frame-pacing) to help your game achieve optimal frame pacing. For more
implementation details, see
[Integrate Android Frame Pacing into your Vulkan renderer](https://developer.android.com/games/sdk/frame-pacing/vulkan).

## Don't rely on implicit synchronization and frame pacing

[vkAcquireNextImageKHR](https://registry.khronos.org/vulkan/specs/latest/man/html/vkAcquireNextImageKHR.html) and [vkQueuePresentKHR](https://registry.khronos.org/vulkan/specs/latest/man/html/vkQueuePresentKHR.html)
are used to manage the swapchain. Avoid relying on their potential blocking
behavior for general application or GPU synchronization.

The precise blocking behavior of these functions can differ substantially
across:

- Android devices
- GPU drivers
- Presentation engine states ([VkPresentModeKHR](https://registry.khronos.org/vulkan/specs/latest/man/html/VkPresentModeKHR.html))

The sole purpose of [vkAcquireNextImageKHR](https://registry.khronos.org/vulkan/specs/latest/man/html/vkAcquireNextImageKHR.html) is to acquire
an available presentable image and it may or may not block.
Similarly, [vkQueuePresentKHR](https://registry.khronos.org/vulkan/specs/latest/man/html/vkQueuePresentKHR.html) queues a request to display an
image and also may or may not block.

Neither function provides reliable guarantees for synchronizing unrelated
CPU tasks or GPU operations.

For robust synchronization, always employ explicit Vulkan primitives like
semaphores for GPU-GPU dependencies (e.g., render-to-present),
fences for GPU-CPU synchronization (e.g., knowing when rendering is finished on
the CPU), and pipeline barriers or events for finer-grained GPU execution and
memory dependencies. Using explicit synchronization ensures predictable behavior
and avoids subtle bugs caused by implementation-specific timing variations
inherent in Android's diverse hardware ecosystem.

## Implement pre-rotation

Android devices can display in multiple orientations. The device orientation can
be different from the orientation of the render surface. Unlike OpenGL ES on
Android, Vulkan does not handle discrepancies between the two. To understand how
the orientation process works and the optimal method of handling orientation
differences when using Vulkan, see [Handle device rotation with Vulkan
pre-rotation](https://developer.android.com/games/optimize/vulkan-prerotation).

## Troubleshoot and profile Vulkan rendering

Multiple tools are available to help you diagnose rendering issues and
performance problems with Vulkan rendering code.

For more information on Vulkan's debugging and profiling tools, checkout the
[Tools \& advanced features](https://developer.android.com/games/develop/vulkan/tools-and-advanced-features)
section.

### Vulkan validation layers

Vulkan validation layers are runtime libraries that can be enabled to inspect
your calls to the Vulkan API and provide warnings or errors about incorrect or
nonoptimal use. These validation layers are not active by default, as the
validation process adds runtime overhead and impacts the performance of your
game. For information on how to use validation layers with your game, see
[Debugging with validation layer](https://developer.android.com/games/develop/vulkan/tools-and-advanced-features#debugging-with-validation-layer).
| **Note:** Some GPU vendors offer validation layer libraries specific to their GPUs in addition to the standard Vulkan validation layers. Use the GPU-specific validation layers to receive targeted feedback about particular GPUs. These layers can be downloaded from the developer website of the GPU vendor.

### Frame capture tools

Use frame capture tools to record and replay the Vulkan API calls made during a
game frame. These tools let you:

- View information about and visualizations of active graphic resources
- See the sequence of API calls made by your game and see the API parameters
- Explore the state of the graphics pipeline at the time of a draw call
- Visualize the results of rendering up to a specific draw call in the frame

Use the open source [RenderDoc](https://developer.android.com/games/develop/vulkan/tools-and-advanced-features#renderdoc) tool to capture frames from
games running on Android. RenderDoc supports frame capture of both Vulkan and
OpenGL ES.

The [Android GPU Inspector (AGI)](https://developer.android.com/agi) can also be used to capture Vulkan frames.

### Performance analysis tools

Use performance analysis tools to investigate rendering issues in your game that
cause suboptimal frame rates. Individual GPU vendors provide tools designed to
profile your game and provide performance data specific to their GPU
architectures. The performance characteristics and bottlenecks of your game can
vary significantly when rendering on GPUs from different vendors or even on
different GPU generations from the same vendor.

You can also use the Android GPU Inspector to gather and analyze
performance data. Unlike the vendor tools, Android GPU Inspector is compatible
with multiple GPUs from different vendors. However, Android GPU Inspector does
not support older Android devices and may not be compatible with all new
devices.

## Improve Vulkan testing with CTS-D

Android-powered device manufacturers use Compatibility Test Suite (CTS) to help
ensure that their devices are compatible. [Developer-Powered CTS (CTS-D)](https://source.android.com/docs/compatibility/cts/develop-cts-d) are
tests submitted by Android application developers to make sure that future
Android devices satisfy their use cases and are able to run their applications
smoothly and without bugs.

If you manage to trigger a new bug with your Vulkan application that affects any
specific Android-powered device, you can submit a new test proposal, describing
your issue and ways to check for it. This ensures that the issue is fixed in
a future update for the device, and also ensures that the same bug won't happen
to any other devices.

Check out the [CTS submission process](https://source.android.com/docs/compatibility/cts/develop-cts-d#submission-process)
for step-by-step instructions on how to submit
the test proposal.