Vulkan is a low-overhead, cross-platform API for high-performance 3D graphics. Like OpenGL ES (GLES), Vulkan provides tools for creating high-quality, real-time graphics in apps. Advantages of using Vulkan include reductions in CPU overhead and support for the SPIR-V Binary Intermediate language.
To implement Vulkan successfully, a device must include:
- The Vulkan loader, provided by Android.
- A Vulkan driver, provided by SoCs such as GPU IHVs, that implements the Vulkan API. To support Vulkan functionality, the Android device needs Vulkan-capable GPU hardware and the associated driver. The GPU must also support GLES 3.1 and higher. Consult your SoC vendor to request driver support.
If a device includes a Vulkan driver, the device needs to declare
FEATURE_VULKAN_HARDWARE_LEVEL
and
FEATURE_VULKAN_HARDWARE_VERSION
system features, with versions that
accurately reflect the capabilities of the device. This helps ensure that the
device is in compliance with
the Compatibility Definition Document (CDD).
Vulkan loader
The Vulkan loader platform/frameworks/native/vulkan
is the
primary interface between Vulkan apps and a device's Vulkan driver. The Vulkan
loader is installed at /system/lib[64]/libvulkan.so
. The loader
provides the core Vulkan API entry points, the entry points of extensions
required by the Android CDD, and many additional optional extensions. Window
System Integration (WSI) extensions are exported by the loader and primarily
implemented in the loader rather than in the driver. The loader also supports
enumerating and loading layers that can expose additional extensions and intercept
core API calls on their way to the driver.
The NDK includes a stub libvulkan.so
library for
linking. The library exports the same symbols as the loader. Apps call the functions
exported from the real libvulkan.so
library to
enter trampoline functions in the loader, which dispatch to the appropriate
layer or driver based on their first argument. The vkGet*ProcAddr()
call returns the function pointers to which the trampolines dispatch (that is,
it calls directly into the core API code). Calling through the function
pointers, rather than the exported symbols, is more efficient as it
skips the trampoline and dispatch.
Driver enumeration and loading
When the system image is built, Android expects the system to know which GPUs
are available. The loader uses the existing HAL mechanism in
hardware.h
to discover and load the driver. Preferred paths for 32-bit and 64-bit Vulkan drivers are:
/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
In Android 7.0 and higher, the Vulkan hw_module_t
derivative
wraps a single hw_module_t
struct; only one driver is supported and the constant string
HWVULKAN_DEVICE_0
is passed to open()
.
The Vulkan hw_device_t
derivative corresponds to a single
driver that can support multiple physical devices. The
hw_device_t
structure can extend to export
vkGetGlobalExtensionProperties()
, vkCreateInstance()
, and
vkGetInstanceProcAddr()
functions. The loader can find all other
VkInstance()
, VkPhysicalDevice()
, and
vkGetDeviceProcAddr()
functions by calling
the hw_device_t
structure's vkGetInstanceProcAddr()
.
Layer discovery and loading
The Vulkan loader supports enumerating and loading layers that can expose additional extensions and intercept core API calls on their way to the driver. Android doesn't include layers on the system image; however, apps may include layers in their APK.
When using layers, keep in mind that Android's security model and policies differ significantly from other platforms. In particular, Android doesn't allow loading external code into a nondebuggable process on production (nonrooted) devices, nor does it allow external code to inspect or control the process's memory, state, and so on. This includes a prohibition on saving core dumps, API traces, and so on to disk for later inspection. Only layers delivered as part of nondebuggable apps are enabled on production devices, and drivers must not provide functionality that violates these policies.
Use cases for layers include:
- Development-time layers — Validation layers and shims for tracing/profiling/debugging tools shouldn't be installed on the system image of production devices. Validation layers and shims for tracing/profiling/debugging tools should be updatable without a system image. Developers who want to use one of these layers during development can modify the app package, for example, by adding a file to their native libraries directory. IHV and OEM engineers who want to diagnose failures in shipping unmodifiable apps are assumed to have access to nonproduction (rooted) builds of the system image, unless those apps are debuggable. For more information see Vulkan validation layers on Android.
- Utility layers — These layers expose extensions, such as a layer that implements a memory manager for device memory. Developers choose layers, and versions of those layers, to use in their app; different apps using the same layer may still use different versions. Developers choose which of these layers to ship in their app package.
- Injected (implicit) layers — Includes layers such as frame rate, social network, and game launcher overlays provided by the user or some other app without the app's knowledge or consent. These violate Android's security policies and aren't supported.
For nondebuggable apps, the loader searches for layers only in the
app's native library directory and attempts to load any library with a name
matching a particular pattern (for example, libVKLayer_foo.so
).
For debuggable apps, the loader searches for layers in
/data/local/debug/vulkan
and attempts to load any library matching
a particular pattern.
Android enables layers to be ported with build-environment changes between Android and other platforms. For details on the interface between layers and the loader, see Architecture of the Vulkan Loader Interfaces. The Khronos-maintained validation layers are hosted in Vulkan Validation Layers.
Vulkan API versions and capabilities
The following table lists Vulkan API versions for several Android releases.Android Version | Vulkan Version |
---|---|
Android 13 | Vulkan 1.3 |
Android 9 | Vulkan 1.1 |
Android 7 | Vulkan 1.0 |
Vulkan 1.3 functionality overview
Vulkan 1.3 canonizes a number of previously optional extensions into the Vulkan core functionality. Much of this functionality is included with the intent of increasing control and granularity over the Vulkan programming interface. Single-pass render pass instances no longer need render pass objects or framebuffers. The total number of pipeline state objects can be reduced, and synchronization within the API is overhauled. Vulkan 1.3 has the same hardware requirements as Vulkan 1.2, 1.1, and 1.0, with most of the implementation in the SoC-specific graphics driver, not in the framework.
The most important Vulkan 1.3 features for Android are:
- Support for single-pass render pass instances
- Support for immediately terminating a shader invocation
- Finer granularity over pipeline creation, sharing, and control
Vulkan 1.3 also includes several smaller features and API usability enhancements. All changes made to the core Vulkan API with minor revision 1.3 can be found at Core Revisions (Vulkan 1.3).
Vulkan 1.2 functionality overview
Vulkan 1.2 adds a number of features and extensions that simplifies the API surface. This includes a unified Memory Model and additional information that can be queried from a device driver. Vulkan 1.2 has the same hardware requirements as Vulkan 1.0 and 1.1; all of the implementation is in the SoC-specific graphics driver, not the framework.
The most important Vulkan 1.2 feature for Android is support for 8-bit storage.
Vulkan 1.2 also includes several smaller features and API usability enhancements. All changes made to the core Vulkan API with minor revision 1.2 can be found at Core Revisions (Vulkan 1.2).
Vulkan 1.1 functionality overview
Vulkan 1.1 includes support for memory/synchronization interop, which enables OEMs to support Vulkan 1.1 on devices. Additionally, memory/synchronization interop enables developers to determine whether Vulkan 1.1 is supported on a device, and use it effectively when it is. Vulkan 1.1 has the same hardware requirements as Vulkan 1.0, but most of the implementation is in the SOC-specific graphics driver, not in the framework.
The most important Vulkan 1.1 features for Android are:
- Support for importing and exporting memory buffers and synchronization objects from outside Vulkan (for interop with camera, codecs, and GLES)
- Support for YCbCr formats
Vulkan 1.1 also includes several smaller features and API usability enhancements. All changes made to the core Vulkan API with minor revision 1.1 can be found at Core Revisions (Vulkan 1.1).
Choose Vulkan support
Android devices should support the most advanced Vulkan feature set available, provided they support a 64-bit ABI and are not low memory.
Devices that launch with Android 13 and above should support Vulkan 1.3.
Devices that launch through Android 10 should support Vulkan 1.1.
Other devices can optionally support Vulkan 1.3, 1.2, and 1.1.
Support a Vulkan version
An Android device supports a Vulkan version if the following conditions are satisfied:
- Add a Vulkan driver that supports the Vulkan version of interest (this must be one of Vulkan version 1.3, 1.1, or 1.0) alongside the additional CDD requirements of the Android version. Alternatively, update an existing Vulkan driver of a lower Vulkan version number.
- For Vulkan 1.3 or 1.1, Ensure that the system feature returned by the package manager returns
true
for the correct vulkan version.- For Vulkan 1.3 the feature is
PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x403000)
. - For Vulkan 1.1 the feature is
PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000)
.
true
for Vulkan 1.3 and Vulkan 1.1 by adding a rule, shown as follows, to an appropriatedevice.mk
file.- Add the following for Vulkan 1.3:
PRODUCT_COPY_FILES += frameworks/native/data/etc/android.hardware.vulkan.version-1_3.xml: $(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml
- Add the following for Vulkan 1.1:
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
- For Vulkan 1.3 the feature is
Android Baseline profile (ABP)
We encourage all Android devices to conform to the latest Android Baseline 2022 profile as outlined in the Android Baseline profile guide.
Any device that supports Android 14 or higher and the Vulkan API, must
fulfill all functionality defined in the
Android Baseline 2021 profile. The full list of required functionality is
enumerated in the Vulkan profile json
file, but a key subset of the required
functionality includes:
- Compressed textures through ASTC and ETC.
- Variable colorspaces through
VK_EXT_swapchain_colorspace
. - Sample shading and multisample interpolation through
sampleRateShading
.
Window system integration (WSI)
In libvulkan.so
, the driver implements the following
window system integration (WSI) extensions:
VK_KHR_surface
VK_KHR_android_surface
VK_KHR_swapchain
VK_KHR_driver_properties
, implemented for Vulkan 1.1 in Android 10 onlyVK_GOOGLE_display_timing
, implemented for any Vulkan version in Android 10
The VkSurfaceKHR
and VkSwapchainKHR
objects and all
interactions with ANativeWindow
are handled by the platform and aren't
exposed to drivers. The WSI implementation relies on the
VK_ANDROID_native_buffer
extension, which must be
supported by the driver; this extension is used only by the WSI implementation
and isn't exposed to apps.
Gralloc usage flags
Vulkan implementations may need swapchain buffers to be allocated with implementation-defined private Gralloc usage flags. When creating a swapchain, Android asks the driver to translate the requested format and image usage flags into Gralloc usage flags by calling:
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 );
The format
and imageUsage
parameters are taken from
the VkSwapchainCreateInfoKHR
structure. The driver should fill
*grallocConsumerUsage
and *grallocProducerUsage
with
the Gralloc usage flags required for the format
and usage. The usage flags returned by the driver are combined with the usage
flags requested by the swapchain consumer when allocating buffers.
Android 7.x calls an earlier version of VkSwapchainImageUsageFlagsANDROID()
,
named vkGetSwapchainGrallocUsageANDROID()
. Android 8.0 and higher deprecates
vkGetSwapchainGrallocUsageANDROID()
but still calls
vkGetSwapchainGrallocUsageANDROID()
if
vkGetSwapchainGrallocUsage2ANDROID()
isn't provided by the driver:
VkResult VKAPI vkGetSwapchainGrallocUsageANDROID( VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage );
vkGetSwapchainGrallocUsageANDROID()
doesn't support swapchain usage
flags or extended Gralloc usage flags.
Gralloc-backed images
VkNativeBufferANDROID
is a vkCreateImage
extension
structure for creating an image backed by a Gralloc buffer. VkNativeBufferANDROID
is
provided to vkCreateImage()
in the VkImageCreateInfo
structure chain. Calls to vkCreateImage()
with VkNativeBufferANDROID
happen
during the call to vkCreateSwapchainKHR
. The WSI implementation allocates
the number of native buffers requested for the swapchain, then creates a
VkImage
for each one:
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;
When creating a Gralloc-backed image, VkImageCreateInfo
has
the following data:
.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
In Android 8.0 and higher, the platform provides a
VkSwapchainImageCreateInfoKHR
extension structure in the
VkImageCreateInfo
chain provided to vkCreateImage
when any swapchain image usage flags are required for the swapchain.
The extension structure contains the swapchain image usage flags:
typedef struct { VkStructureType sType; // must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID const void* pNext; VkSwapchainImageUsageFlagsANDROID usage; } VkSwapchainImageCreateInfoANDROID;
In Android 10 and higher, the platform supports
VK_KHR_swapchain
v70, so the Vulkan app is able to create a
VkImage
backed by swapchain memory. The app first calls
vkCreateImage
with a VkImageSwapchainCreateInfoKHR
structure chained to the VkImageCreateInfo
structure. Then the
app calls vkBindImageMemory2(KHR)
with a
VkBindImageMemorySwapchainInfoKHR
structure chained to the
VkBindImageMemoryInfo
structure. The imageIndex
specified in the VkBindImageMemorySwapchainInfoKHR
structure must
be a valid swapchain image index. Meanwhile, the platform provides a
VkNativeBufferANDROID
extension structure with the corresponding
Gralloc buffer information to the VkBindImageMemoryInfo
chain, so
the driver knows which Gralloc buffer to bind the VkImage
with.
Acquire images
vkAcquireImageANDROID
acquires ownership of a swapchain image
and imports an externally signaled native fence into both an existing
VkSemaphore
object and an existing VkFence
object:
VkResult VKAPI vkAcquireImageANDROID( VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence );
vkAcquireImageANDROID()
is called during
vkAcquireNextImageKHR
to import a
native fence into the VkSemaphore
and VkFence
objects
provided by the app (however, both semaphore and fence objects are
optional in this call). The driver may also use this opportunity to recognize
and handle any external changes to the Gralloc buffer state; many drivers won't
need to do anything here. This call puts the VkSemaphore
and
VkFence
into the same pending state as if signaled by vkQueueSubmit
,
so queues can wait on the semaphore and the app can wait on the fence.
Both objects become signaled when the underlying native fence signals; if
the native fence has already signaled, then the semaphore is in the signaled
state when this function returns. The driver takes ownership of the fence file
descriptor and closes the fence file descriptor when no longer needed. The driver
must do so even if neither a semaphore or fence object is provided, or even if
vkAcquireImageANDROID
fails and returns an error. If
fenceFd
is -1, it's as if the native fence was already
signaled.
Release images
vkQueueSignalReleaseImageANDROID
prepares a swapchain image for
external use, creates a native fence, and schedules the native fence to be signaled after
the input semaphores have signaled:
VkResult VKAPI vkQueueSignalReleaseImageANDROID( VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd );
vkQueuePresentKHR()
calls vkQueueSignalReleaseImageANDROID()
on the provided queue. The driver must produce a native fence that doesn't signal
until all waitSemaphoreCount
semaphores in
pWaitSemaphores
signal, and any additional work required to
prepare image
for presentation completes.
If the wait semaphores (if any) already signaled, and queue
is
already idle, the driver can set *pNativeFenceFd
to -1
instead of an actual native fence file descriptor, indicating that
there's nothing to wait for. The caller owns and closes the file descriptor
returned in *pNativeFenceFd
.
Many drivers can ignore the image parameter, but some may need to prepare
CPU-side data structures associated with a Gralloc buffer for use by external
image consumers. Preparing buffer contents for use by external consumers should
be done asynchronously as part of transitioning the image to
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
.
If the image was created with
VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID
, then the driver must
allow vkQueueSignalReleaseImageANDROID()
to be called repeatedly
without intervening calls to vkAcquireImageANDROID()
.
Shared presentable image support
Some devices can share ownership of a single image between
the display pipeline and the Vulkan implementation to minimize latency.
In Android 9 and higher, the loader conditionally advertises the
VK_KHR_shared_presentable_image
extension based on the driver's
response to a call to vkGetPhysicalDeviceProperties2
.
If the driver doesn't support either Vulkan 1.1 or the
VK_KHR_physical_device_properties2
extension, the loader doesn't
advertise support for shared presentable images. Otherwise, the loader queries
the driver capabilities by calling vkGetPhysicalDeviceProperties2()
and including the following structure in the
VkPhysicalDeviceProperties2::pNext
chain:
typedef struct { VkStructureType sType; // must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID const void* pNext; VkBool32 sharedImage; } VkPhysicalDevicePresentationPropertiesANDROID;
If the driver can share ownership of an image with the display
system, it sets the sharedImage
member to VK_TRUE
.
Validation
OEMs can test their Vulkan implementation using CTS, which includes the following:
- Khronos Vulkan Conformance tests
in the
CtsDeqpTestCases
module, which include functional API tests for Vulkan 1.0, 1.1, 1.2, and 1.3. - The
CtsGraphicsTestCases
module, which tests that the device is configured correctly for the Vulkan capabilities it supports.
Vulkan feature flag
A device that supports Android 11 or higher and that supports the Vulkan API
is required to expose a feature flag,
android.software.vulkan.deqp.level
. The value of this feature flag
is a date, encoded as an integer value. It specifies the date associated with
the Vulkan dEQP tests that the device claims to pass.
A date of the form YYYY-MM-DD is encoded as a 32-bit integer as follows:
- Bits 0-15 store the year
- Bits 16-23 store the month
- Bits 24-31 store the day
The minimum allowed value for the feature flag is 0x07E30301
,
which corresponds to the date 2019-03-01, which is the date associated with the
Vulkan dEQP tests for Android 10. If the feature flag is at least this value,
the device claims to pass all of the Android 10 Vulkan dEQP tests.
Value 0x07E40301
corresponds to the date 2020-03-01, which is
the date associated with the Vulkan dEQP tests for Android 11. If the feature
flag is at least this value, the device claims to pass all of the Android 11
Vulkan dEQP tests.
Value 0x07E60301
corresponds to the date 2022-03-01, which is
the date associated with the Vulkan dEQP tests for
Android 13. If the feature flag is at least this value,
the device claims to pass all of the Android 13 Vulkan
dEQP tests.
A device that exposes a specific feature flag (i.e
0x07E30301
, 0x07E40301
, 0x07E60301
)
claims to pass all Android Vulkan dEQP tests of that feature flag (Android 10,
Android 11, Android 13 respectively). This device
may pass Vulkan dEQP tests from a later Android release.
Vulkan dEQP forms part of Android CTS. From Android 11, the dEQP test runner
component of CTS is aware of the android.software.vulkan.deqp.level
feature flag, and skips any Vulkan dEQP tests that - according to this
feature flag - the device doesn't claim to support. Such tests are
reported as trivially passing.