We're hiring!
*

Mesa on Android: How we brought Turnip, SkiaVK, and Cuttlefish to CI

Valentine Burley avatar

Valentine Burley
September 10, 2026

Share this post:

Reading time:

Turnip is the open source Mesa Vulkan driver for Qualcomm Adreno GPUs targeting the Adreno 600, 700, and 800 series architectures. Originally developed as a reverse-engineered effort, Turnip has grown from its roots through close collaboration between Google, Valve, and Igalia, with Qualcomm engineers now contributing upstream as well. Today, Turnip ships in Google's Qualcomm-powered Chromebooks and will power upcoming gaming hardware like Valve's Steam Frame.

Turnip implements full Vulkan 1.3 support for Adreno 600 series GPUs and is Vulkan 1.4 conformant on Adreno 700 series hardware. Until recently, A6xx was only officially conformant against Vulkan 1.1. Earlier this year, we set out to push for official Vulkan 1.3 conformance on A6xx GPUs. As documented on Khronos' Conformant Products page, Turnip on A6xx is now officially Vulkan 1.3 conformant.

Crucially, one of the conformance runs was executed not on desktop Linux, but directly on the Android platform. This marks the first time any Mesa driver has achieved official Vulkan conformance on Android. Getting there required solving some unique challenges.

Mastering Android Memory: Aliased ANB and Deferred Image Creation

While Mesa has supported Android for years, most visibly in ChromeOS's ArcVM, modern Android platforms impose strict requirements on Vulkan drivers. Android graphics rely heavily on two core primitives: Android Native Buffers (ANB) via VK_ANDROID_native_buffer and Android Hardware Buffers (AHB) via VK_ANDROID_external_memory_android_hardware_buffer.

In modern Android (starting with ANB specification version 8 and VK_KHR_swapchain version 69+), Vulkan drivers are required to support aliased ANB images.

This introduces an architectural challenge for Vulkan drivers. In standard Vulkan, all image format properties, DRM modifiers, and memory requirements are determined when vkCreateImage is called. In the Android ecosystem, however:

  1. ANB Alias Images: When vkCreateImage is invoked, the backing gralloc buffer is not yet attached. The driver only learns the format modifiers and memory layout later during vkBindImageMemory2 when the native buffer handle arrives.
  2. AHB Images: The actual layout, stride, and dedicated memory properties are resolved at vkAllocateMemory when the AHardwareBuffer handle is imported.

If a driver attempts to calculate memory layouts immediately during vkCreateImage, it will produce incorrect assumptions for gralloc-backed images.

To solve this across Mesa, we built upon the deferred image creation logic originally developed for PanVK. We extracted and generalized this functionality into Mesa's common Vulkan runtime for Android.

The new vk_android_init_deferred_image() helper deep-copies and sanitizes the VkImageCreateInfo pNext chain at vkCreateImage time, deferring image initialization until memory binding.

With the new helpers in place, Turnip now allocates the image container upfront while delaying the rest of the image initialization until vkBindImageMemory2.

This shared infrastructure was promptly adopted across Turnip, PanVK, Venus, and V3DV. It paved the way for robust ANGLE-on-Turnip support, smooth swapchain recreation, and clean passes across Android CTS suites (CtsGraphicsTestCases, CtsNativeHardwareTestCases, and CtsOpenGLTestCases with ANGLE).

Powering SkiaVK: Common Multi-Queue Emulation

The next major obstacle was enabling SkiaVK, the Vulkan rendering backend for Android's Hardware UI framework (HWUI). When Android is configured to use SkiaVK instead of OpenGL ES for system rendering, it requires the Vulkan driver to expose multiple graphics queues.

SkiaVK uses distinct queues to serialize rendering between the application's main UI thread (RenderThread) and asynchronous components, such as Android WebView, preventing thread contention and render pipeline deadlocks.

Desktop games and applications rarely require more than one graphics queue, and as a consequence, many Mesa drivers historically exposed only a single queue. Implementing genuine hardware multi-queue support in Turnip would have been especially complex, as it supports three distinct kernel backends (upstream msm, downstream Android kgsl, and virtio) that would each require separate synchronization, scheduling, and preemption handling.

Taking inspiration from Venus, we resolved this by introducing a generic queue emulation mechanism into Mesa's common Vulkan runtime.

When a driver marks a queue as an emulated alias of another queue:

  1. Submissions to the emulated queue are redirected to the primary queue's driver_submit() callback.
  2. All command submissions across both queues are synchronized using a shared mutex.
  3. No additional kernel submitqueues or hardware execution contexts are allocated.

This lightweight solution allowed SkiaVK to work on Turnip without requiring invasive changes to its kernel backends. We also added automated test coverage across our Continuous Integration (CI) pipelines to ensure multi-queue emulation remains regression-free.

Bringing Android to Mesa CI: Cuttlefish & DRM Native Context

Developing these features is only half the battle; maintaining them without regressions requires continuous testing. Setting up automated Android testing in pre-merge CI is notoriously challenging: deploying and scaling bare-metal Android device farms upstream is difficult because of proprietary Board Support Packages (BSPs), custom flashing tools, and complex recovery mechanisms.

To bring reproducible Android test coverage directly into Mesa's pre-merge CI without the fragility of specialized physical Android test setups, Collabora has been collaborating with Google to integrate Cuttlefish, Google's reference virtual Android device. Cuttlefish boots standard Android virtual machines on top of Mesa's existing Linux host runners using CrosVM.

Over the past two years, we have developed three distinct GPU modes in Cuttlefish to validate Mesa drivers:

1. Lavapipe

Our first mode runs Lavapipe, Mesa's CPU-based Vulkan software rasterizer, inside the Android guest. Paired with ANGLE, it provides full Vulkan and OpenGL ES support without requiring host GPU hardware. We worked with Google to upstream this mode into AOSP and Cuttlefish (android-cuttlefish PR #2873).

2. Venus

The second mode uses Venus, Mesa's VirtIO-GPU Vulkan paravirtualization driver. In the guest, Android runs ANGLE on top of Venus alongside drm_hwcomposer and SkiaVK. On the host, virglrenderer translates guest Vulkan commands to the host's Vulkan driver. This enables testing modern Android graphical workloads against host Vulkan implementations.

3. Turnip via DRM Native Context

While Venus is great for paravirtualized testing, we wanted to test the real, native Turnip driver in Android CI on physical Qualcomm hardware. We achieved this using DRM Native Context.

Unlike API-level paravirtualization (Venus) or command stream translation (VirGL), a DRM native context bridges the Linux Direct Rendering Manager (DRM) UAPI directly across the VirtIO boundary. The Android guest runs native Turnip and ANGLE, while virglrenderer on the host forwards low-level ioctls directly to the host's Qualcomm msm kernel driver.

Leveraging Turnip's existing virtio backend, the driver running inside the Android guest communicates seamlessly with the host Adreno GPU.

This architecture allows us to run full Android CTS suites and Vulkan dEQP tests on real Adreno hardware (such as the Qualcomm Chromebooks) within Mesa's existing Linux CI infrastructure. Every merge request modifying Turnip or Mesa's common code for Vulkan drivers is now automatically tested against real Android environments before landing.

To enable testing EGL and Vulkan Window System Integration (WSI) in these CI runs, we also contributed headless WSI support using AImageReader to VK-GL-CTS. This provides an off-screen ANativeWindow fallback when running dEQP as a native binary on Android, unlocking full pre-merge WSI test coverage in CI.

The Road Ahead

This has been a landmark year for Mesa on Android so far. Between achieving official Vulkan 1.3 conformance on Adreno 6xx, unifying deferred image initialization and queue emulation in Mesa's common runtime, and standing up automated Android testing with Cuttlefish in Mesa CI, the open source graphics stack on Android is stronger than ever.

Looking ahead, Turnip will be included upstream in AOSP's external/mesa3d tree in upcoming Android releases. Enabling Turnip on supported Qualcomm devices running either msm or kgsl kernel drivers will be as simple as adding vulkan.freedreno to your board's device configuration. We look forward to seeing the community build on this foundation; try it out on your devices, run your favorite workloads, and share your feedback!

 

Search the newsroom

Latest News & Events

Mesa on Android: How we brought Turnip, SkiaVK, and Cuttlefish to CI

10/09/2026

Turnip is the first Mesa driver to achieve official Vulkan conformance on Android, with stronger Android integration, shared Vulkan runtime…

Building GPU Drivers in Rust: Tyr at RustConf 2026

08/09/2026

Join us in Montreal for the 10th edition of RustConf! Catch our talk on Tyr, the new Rust kernel driver for Arm Mali GPUs.

From AI video analytics to XR streaming at IBC 2026

08/09/2026

Collabora is heading to Amsterdam! Join us at Booth A63 in Hall 14 to see GStreamer Analytics with machine learning, standalone XR remote…

Open Since 2005 logo

Our website only uses a strictly necessary session cookie provided by our CMS system. To find out more please follow this link.

Collabora Limited © 2005-2026. All rights reserved. Privacy Notice. Sitemap.