Vulkan Part 2

This year's Google IO had a lot of wonderful gems for Embedded Development including a release of the official Vulkan support libraries.  Those libraries require Android N and only on one of three specific devices:
  1. Nexus 6p
  2. Nexus 5x
  3. Nexus Player
In order to target the larger market, we're going to continue using Qualcomm's released Vulkan API and enable targeting any Qualcomm Snapdragon 820 or 821 device such as the very popular Samsung Note 5 and Samsung S7.  I'll also make the important note that both of these devices are among the current generation able to work in the Oculus Gear VR device.  That important note opens the intriguing possibility of doing Virtual Reality work in Vulkan to give much needed performance improvements.
Now that we have our motivation intact for using Qualcomm's Vulkan API, there is something very useful about Google's Vulkan effort that we can take advantage of the SPIR-V compiler (shaderc) included in the NDK in our project as well as the validator for our shaders.  The option I'm going to point out here is to runtime compile GLSL code into SPIR-V.
Let's take a quick look at how one would set this configuration up.  First, ensure that the NDKROOT environment variable is set.  Next, in a terminal window navigate to <ndk root>/sources/third_party/shaderc.  Now we need to run ndkbuild to get shaderc to give us a proper universal library we can use on an device along with the header files.  To do that run this command:

<ndk root>/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \
APP_STL:=<stl_version> APP_ABI=all libshaderc_combined

Now you'll find some new files in your ndk folder:  This should be your directory structure following the build command:
include/
    shaderc/shaderc.*
libs/
    <stl_version>/
          EntireListOfABIs/libshaderc.a

In the above command and directory path stl_version should be replaced by c++_static, c++_shared, gnustl_static, and gnustl_shared.  I must warn that you should pick the same stl version that will be used in your project.  C++ stl versions should be selected over gnustl if you will be working with clang instead of gcc4.9.  Mixing stl runtimes has been known to create subtle and difficult to find bugs.  Also, note that if you select static then the resulting library will be larger but you wont have to include an extra .so in your final apk.

But I digress, let's get into the meat of this post by talking about a promised simple triangle project done with Vulkan.  First, grab the project (it is based upon the triangle sample found in Qualcomm's SDK samples) from https://www.github.com/gpx1000/qualcommvulkantriangle  the notable changes I have made to it include updating the gradle to the latest version 0.8.0-alpha5 cleaned up the warnings and replaced the precompiled shader with a glsl shader that is runtime compiled using the above technique.
So let's take a look at some of the important changes:
1.) In order to utilize prebuilt libraries and make them available natively to any gradle project, there's a simple DSL to utilize for gradle-experimental:
model {
    repositories {
        libs(PrebuiltLibraries) {
            vulkan {
                headers.srcDir "../../../include"
                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file("../../../lib/libvulkan.so")
                }
            }
        }
    }

Then later in the build gradle you can place the dependencies in the sources closure.

android.sources.main.jni {
        dependencies {
            library "vulkan" linkage "shared"
        }
    }

This practice is favored over using CFlags.add(-I../../../include) and ldFlags.add(-L../../../lib) ldLibs.add(vulkan) as the Qualcomm sample suggests because it makes the library more modular and can be used in other modules easier by getting defined once at the project level.  It is also much cleaner to see what is going on in the project.

Note that this is also where I place the linkage for libshaderc.a as a staticLibraryFile. I also utilize this header/library method include DSL for all of the other Google supplied validation libraries as such:

model {
    repositories {
        libs(PrebuiltLibraries) {
            core_validation {
                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file("${ndkDir}/sources/third_party/vulkan/src/build-android/jniLibs/${targetPlatform.getName()}/libVkLayer_core_validation.so")
                }
            }
        }
    }

Then in my sources definition, I change main in android.sources.main.jni to reflect the product flavor I defined to use for vulkan validation.  Here's a list of the other Google provided libraries that one can include as needed to make working with Vulkan easier:
    libVkLayer_device_limits.so
    libVkLayer_image.so
    libVkLayer_object_tracker.so
    libVkLayer_parameter_validation.so
    libVkLayer_swapchain.so
    libVkLayer_threading.so
    libVkLayer_unique_objects.so

This is probably a great stopping point as this much covers how to create a vulkan build setup.  Next time I'll talk about getting into the Vulkan code.  For now, please review Google's tutorial about Validation Layer using Vulkan: https://developer.android.com/ndk/guides/graphics/validation-layer.html

Comments

Popular posts from this blog

Drone VR Software Architecture

Status of the blog

Build Snapdragon Flight Drone