Laszlo Agocs

Building the latest greatest for Android AArch64 (with Vulkan teaser)

Published Friday February 24th, 2017
Comments Off on Building the latest greatest for Android AArch64 (with Vulkan teaser)
Posted in Android, C++, Dev Loop, Graphics, Mobile, OpenGL, QPA, Qt

Let’s say you got a 64-bit ARM device running Android. For instance, the Tegra X1-based NVIDIA Shield TV. Now, let’s say you are also interested in the latest greatest content from the dev branch, for example to try out some upcoming Vulkan enablers from here and here, and want to see all this running on the big screen with Android TV. How do we get Qt, or at least the basic modules like QtGui, QtQuick, etc. up and running on there?

nv_shield_2017 Our test device.

In this little guide we are going to build qtbase for Android targeting AArch64 and will deploy some examples to the Android TV device. To make it more interesting, we will do this from Windows.


The Qt documentation and wiki pages document the process fairly well. One thing to note is that a sufficient MinGW toolchain is easily obtainable by installing the official 32-bit MinGW package from Qt 5.8. Visual Studio is not sufficient as of today.

Once MinGW, Perl, git, Java, Ant, the Android SDK, and the 32-bit Android NDK are installed, open a Qt MinGW command prompt and set some environment variables:

set PATH=c:\android\tools;c:\android\platform-tools;
  C:\Program Files\Java\jdk1.8.0_121\bin;
set ANDROID_API_VERSION=android-24
set ANDROID_SDK_ROOT=c:\android

Adapt the paths as necessary. Here we assume that the Android SDK is in c:\android, the NDK in android-ndk-r13b, qtbase/dev is checked out to c:\android\qtbase, etc.

The Shield TV has Android 7.0 and the API level is 24. This is great for trying out Vulkan in particular since the level 24 NDK comes with the Vulkan headers, unlike level 23.

Build qtbase

Now the fun part: configure. Note that architecture.

configure -developer-build -release -platform win32-g++
  -xplatform android-g++ -android-arch arm64-v8a
  -android-ndk c:/android/android-ndk-r13b -android-sdk c:/android
  -android-ndk-host windows -android-ndk-platform android-24
  -android-toolchain-version 4.9 -opensource -confirm-license
  -nomake tests -nomake examples -v

Once this succeeds, check the output to see if the necessary features (Vulkan in this case) are enabled.

Then build with mingw32-make -j8 or similar.


To get androiddeployqt, check out the qttools repo, go to src/androiddeployqt and do qmake and mingw32-make. The result is a host (x86) build of the tool in qtbase/bin.

For general information on androiddeployqt usage, check the documentation.

Here we will also rely on Ant. This means that Ant must either be in the PATH, as shown above, or the location must be provided to androiddeployqt via the –ant parameter.

Now, Qt 5.8.0 and earlier have a small issue with AArch64 Android deployments. Therefore, grab the patch from Gerrit and apply on top of your qtbase tree if it is not there already. (it may or may not have made its way to the dev branch via merges yet)

After this one can simply go to a Qt application, for instance qtbase/examples/opengl/qopenglwidget and do:

mingw32-make install INSTALL_ROOT=bld
androiddeployqt --output bld
adb install -r bld/bin/QtApp-debug.apk


Now that a Qt application is installed, let’s launch it.

Except that it does not show up in the Android TV launcher.

One easy workaround could be to adb shell and do something like the following:

am start -n org.qtproject.example.qopenglwidget/

Then again, it would be nice to get something like this:


Therefore, let’s edit bld/AndroidManifest.xml:

  <action android:name="android.intent.action.MAIN"/>
  <!--<category android:name="android.intent.category.LAUNCHER"/>-->
  <category android:name="android.intent.category.LEANBACK_LAUNCHER" />

and reinstall by running ant debug install. Changing the category name does the trick.

Note that rerunning androiddeployqt overwrites the manifest file. A more reusable alternative would be to make a copy of the template, change it, and use ANDROID_PACKAGE_SOURCE_DIR.

The result

Widget applications, including OpenGL, run fairly well:


Or something more exciting:


No, really. That clear to green is actually done via Vulkan.


And finally, the hellovulkantexture example using QVulkanWindow! (yeah, colors are a bit bad on these photos)

adb logcat is your friend, as usual. Let’s get some proof that our textured quad is indeed drawn via Vulkan:

qt.vulkan: Vulkan init (         
vulkan  : searching for layers in '/data/app/org.qtproject.example.hellovulkantexture-2/lib/arm64'     
qt.vulkan: Supported Vulkan instance layers: QVector()              
qt.vulkan: Supported Vulkan instance extensions: QVector(QVulkanExtension("VK_KHR_surface" 25), QVulkanExtension("VK_KHR_android_surface" 6), QVulkanExtension("VK_EXT_debug_report" 2))    
qt.vulkan: Enabling Vulkan instance layers: ()                                                                                            
qt.vulkan: Enabling Vulkan instance extensions: ("VK_EXT_debug_report", "VK_KHR_surface", "VK_KHR_android_surface")                     
qt.vulkan: QVulkanWindow init                                                                                                        
qt.vulkan: 1 physical devices                                                                                                              
qt.vulkan: Physical device [0]: name 'NVIDIA Tegra X1' version 361.0.0                                                                     
qt.vulkan: Using physical device [0]                                                                                                      
qt.vulkan: queue family 0: flags=0xf count=16                                                                                                               
qt.vulkan: Supported device layers: QVector()                                                                                      
qt.vulkan: Enabling device layers: QVector()                                                                                       
qt.vulkan: Supported device extensions: QVector(QVulkanExtension("VK_KHR_swapchain" 68), QVulkanExtension("VK_KHR_sampler_mirror_clamp_to_edge" 1), QVulkanExtension("VK_NV_dedicated_allocation" 1), QVulkanExtension("VK_NV_glsl_shader" 1))                                                                                
qt.vulkan: Enabling device extensions: QVector(VK_KHR_swapchain)                                                     
qt.vulkan: memtype 0: flags=0x1                                                 
qt.vulkan: memtype 1: flags=0x1                           
qt.vulkan: memtype 2: flags=0x7                             
qt.vulkan: memtype 3: flags=0xb                               
qt.vulkan: Picked memtype 2 for host visible memory             
qt.vulkan: Picked memtype 0 for device local memory     
uniform buffer offset alignment is 256        
qt.vulkan: Creating new swap chain of 2 buffers, size 1920x1080       
qt.vulkan: Actual swap chain buffer count: 2                
qt.vulkan: Allocating 8847360 bytes for depth-stencil        

Should you need validation layers, follow the instructions from the Android Vulkan docs and rebuild and redeploy the package after copying the libVkLayer* to the right location.

That’s all for now. Have fun experimenting. The basic Vulkan enablers, including QVulkanWindow are currently scheduled for Qt 5.10, with support for Windows, Linux/X11, and Android. (the list may grow later on)

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Android, C++, Dev Loop, Graphics, Mobile, OpenGL, QPA, Qt

Get started today with Qt Download now