Home | History | Annotate | Download | only in graphics
      1 page.title=Vulkan Validation Layers on Android
      2 @jd:body
      3 
      4 <div id="qv-wrapper">
      5     <div id="qv">
      6       <h2>On this page</h2>
      7 
      8       <ol>
      9         <li><a href="#ilp">Add Validation Layers to Project</a></li>
     10         <li><a href="#gls">Getting Layer Source</a></li>
     11         <li><a href="#verifying">Verifying Layer Build</a></li>
     12         <li><a href="#enabling">Enabling Layers</a></li>
     13         <li><a href="#debug">Enabling the Debug Callback</a></li>
     14       </ol>
     15     </div>
     16   </div>
     17 
     18 <p>
     19 Most explicit graphics APIs do not perform error-checking, because doing so can result in a
     20 performance penalty. Vulkan provides error-checking in a manner that lets you use this feature at
     21 development time, but exclude it from the release build of your app, thus avoiding the penalty when
     22 it matters most. You do this by enabling <em>validation layers</em>. Validation layers intercept
     23 or hook Vulkan entry points for various debug and validation purposes.
     24 </p>
     25 
     26 <p>
     27 Each validation layer can contain definitions for one or more of these entry points, and
     28 intercepts the entry points for which it contains definitions. When a validation
     29 layer does not define an entry point, the system passes the entry point on to the next
     30 layer. Ultimately, an entry point not defined in any layer reaches the driver, the
     31 base level, unvalidated.
     32 </p>
     33 
     34 <p>
     35 The Android SDK, NDK, and Vulkan samples include Vulkan validation layers for
     36 use during development. You can hook these validation layers into the graphics stack, allowing
     37 them to report validation issues.  This instrumentation allows you to catch and fix misuses
     38 during development.
     39 </p>
     40 
     41 <p>
     42 This page explains how to:
     43 <ul>
     44    <li>Integrate NDK's Layer Binaries.</li>
     45    <li>Get source code for validation layers.</li>
     46    <li>Verifying Layer Build.</li>
     47    <li>Enabling Layers in Vulkan Application.</li>
     48 
     49 </ul>
     50 </p>
     51 
     52 <h2 id="ilp">Add Validation Layers to Project</h2>
     53 
     54 <p>
     55   NDK release 12 and higher includes pre-built validation layer binaries. At
     56   instance and device creation time, when requested by your application, the
     57   Vulkan loader finds them in the APK installed location and loads them.
     58 </p>
     59 
     60 <p>
     61   To use the pre-built validation layer binaries, either modify the gradle build
     62   configuration of your project or manually add the binaries into the JNI
     63   libraries directory of your project.
     64 </p>
     65 
     66 
     67 <h3 id="vl-gradle">Adding validation layers with Gradle</h3>
     68 
     69 <p>
     70   You can add the validation layer your project using either Andorid Studio's
     71   support for CMake and Ndk-build, or using Studio's experimental plugin for
     72   Gradle. In general, you should use the CMake and Ndk-build configuration.
     73 </p>
     74 
     75 
     76 <p>
     77   To add the libraries using Android Studio's support for CMake/Ndk-build,
     78   add the following to your project's gradle configuration:
     79 </p>
     80 
     81 <pre class="no-pretty-print">
     82 sourceSets {
     83   main {
     84     jniLibs {
     85       srcDir "${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs"
     86     }
     87   }
     88 }</pre>
     89 
     90 <p>
     91   To add the libraries using Android Studio's experimental plugin for Gradle,
     92   add the following to your project's gradle configuration:
     93 </p>
     94 
     95 <pre class="no-pretty-print">
     96 sources {
     97   main {
     98     jniLibs {
     99       source.srcDir "${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs"
    100     }
    101   }
    102 }</pre>
    103 
    104 
    105 <h3 id="vl-jni-lib">Adding validation layers to JNI libraries</h3>
    106 
    107 <p>
    108   If configuring your project's gradle build file is not working, you can
    109   manually add the validation layer binaries to your project's JNI libraries
    110   directory by using the following command line options:
    111 </p>
    112 
    113 <pre class="no-pretty-print">
    114 $ cd ${your-app-project-root}
    115 $ mkdir -p app/src/main
    116 $ cp -fr ${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs app/src/main/
    117 </pre>
    118 
    119 
    120 <h2 id="gls">Getting Layer Source</h2>
    121 <p>
    122 If your app needs the latest validation layer, you can pull the latest source from the Khronos Group
    123 <a class="external-link" href="https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers">
    124 GitHub repository</a> and follow the build instructions there.
    125 </p>
    126 
    127 <h2 id="verifying">Verifying Layer Build</h2>
    128 
    129 <p>
    130 Regardless of whether you build with NDK's prebuilt layers or you build from the latest source code,
    131 the build process produces final file structure like the following:
    132 </p>
    133 
    134 <pre class="no-pretty-print">
    135 src/main/jniLibs/
    136   arm64-v8a/
    137     libVkLayer_core_validation.so
    138     libVkLayer_device_limits.so
    139     libVkLayer_image.so
    140     libVkLayer_object_tracker.so
    141     libVkLayer_parameter_validation.so
    142     libVkLayer_swapchain.so
    143     libVkLayer_threading.so
    144     libVkLayer_unique_objects.so
    145   armeabi-v7a/
    146     libVkLayer_core_validation.so
    147     ...
    148 </pre>
    149 
    150 <p>
    151 The following example shows how to verify that your APK contains the validation layers
    152 as expected:
    153 </p>
    154 
    155 <pre class="no-pretty-print">
    156 $ jar -xvf project.apk
    157  ...
    158  inflated: lib/arm64-v8a/libVkLayer_threading.so
    159  inflated: lib/arm64-v8a/libVkLayer_object_tracker.so
    160  inflated: lib/arm64-v8a/libVkLayer_swapchain.so
    161  inflated: lib/arm64-v8a/libVkLayer_unique_objects.so
    162  inflated: lib/arm64-v8a/libVkLayer_parameter_validation.so
    163  inflated: lib/arm64-v8a/libVkLayer_image.so
    164  inflated: lib/arm64-v8a/libVkLayer_core_validation.so
    165  inflated: lib/arm64-v8a/libVkLayer_device_limits.so
    166  ...
    167 </pre>
    168 
    169 
    170 <h2 id="enabling">Enabling Layers</h2>
    171 
    172 <p>The Vulkan API allows an app to enable both instance layers and device layers.</p>
    173 
    174 <h3>Instance layers</h3>
    175 
    176 <p>
    177 A layer that can intercept Vulkan instance-level entry points is called an instance layer.
    178 Instance-level entry points are those with {@code VkInstance} or {@code VkPhysicalDevice}
    179 as the first parameter.
    180 </p>
    181 
    182 <p>
    183 You can call {@code vkEnumerateInstanceLayerProperties()} to list the available instance layers
    184 and their properties. The system enables instance layers when {@code vkCreateInstace()} executes.
    185 </p>
    186 
    187 <p>
    188 The following code snippet shows how an app can use the Vulkan API to programmatically enable and
    189 query an instance layer:
    190 </p>
    191 
    192 <pre>
    193 // Get instance layer count using null pointer as last parameter
    194 uint32_t instance_layer_present_count = 0;
    195 vkEnumerateInstanceLayerProperties(&instance_layer_present_count, nullptr);
    196 
    197 // Enumerate instance layers with valid pointer in last parameter
    198 VkLayerProperties* layer_props =
    199     (VkLayerProperties*)malloc(instance_layer_present_count * sizeof(VkLayerProperties));
    200 vkEnumerateInstanceLayerProperties(&instance_layer_present_count, layer_props));
    201 
    202 // Make sure the desired instance validation layers are available
    203 // NOTE:  These are not listed in an arbitrary order.  Threading must be
    204 //        first, and unique_objects must be last.  This is the order they
    205 //        will be inserted by the loader.
    206 const char *instance_layers[] = {
    207     "VK_LAYER_GOOGLE_threading",
    208     "VK_LAYER_LUNARG_parameter_validation",
    209     "VK_LAYER_LUNARG_object_tracker",
    210     "VK_LAYER_LUNARG_core_validation",
    211     "VK_LAYER_LUNARG_device_limits",
    212     "VK_LAYER_LUNARG_image",
    213     "VK_LAYER_LUNARG_swapchain",
    214     "VK_LAYER_GOOGLE_unique_objects"
    215 };
    216 
    217 uint32_t instance_layer_request_count =
    218     sizeof(instance_layers) / sizeof(instance_layers[0]);
    219 for (uint32_t i = 0; i < instance_layer_request_count; i++) {
    220     bool found = false;
    221     for (uint32_t j = 0; j < instance_layer_present_count; j++) {
    222         if (strcmp(instance_layers[i], layer_props[j].layerName) == 0) {
    223             found = true;
    224         }
    225     }
    226     if (!found) {
    227         error();
    228     }
    229 }
    230 
    231 // Pass desired instance layers into vkCreateInstance
    232 VkInstanceCreateInfo instance_info = {};
    233 instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    234 instance_info.enabledLayerCount = instance_layer_request_count;
    235 instance_info.ppEnabledLayerNames = instance_layers;
    236 ...
    237 </pre>
    238 
    239 <h3>Device layers</h3>
    240 
    241 <p>
    242 A layer that can intercept device-level entry points is called a device layer. Device-level entry
    243 points are those whose first parameter is {@code VkDevice}, {@code VkCommandBuffer},
    244 or {@code VkQueue}. The list of
    245 device layers to enable is included in the {@code ppEnabledLayerNames} field of the
    246 {@code VkDeviceCreateInfo}
    247 struct that the app passes into {@code vkCreateDevice()}.
    248 </p>
    249 
    250 <p>
    251 You can call {@code vkEnumerateDeviceLayerProperties} to list the available layers
    252 and their properties. The system enables device layers when it calls {@code vkCreateDevice()}.
    253 </p>
    254 
    255 <p>
    256 The following code snippet shows how an app can use the Vulkan API to programmatically enable a
    257 device layer.
    258 </p>
    259 
    260 <pre>
    261 
    262 // Get device layer count using null as last parameter
    263 uint32_t device_layer_present_count = 0;
    264 vkEnumerateDeviceLayerProperties(&device_layer_present_count, nullptr);
    265 
    266 // Enumerate device layers with valid pointer in last parameter
    267 VkLayerProperties* layer_props =
    268    (VkLayerProperties *)malloc(device_layer_present_count * sizeof(VkLayerProperties));
    269 vkEnumerateDeviceLayerProperties(physical_device, device_layer_present_count, layer_props));
    270 
    271 // Make sure the desired device validation layers are available
    272 // Ensure threading is first and unique_objects is last!
    273 const char *device_layers[] = {
    274     "VK_LAYER_GOOGLE_threading",
    275     "VK_LAYER_LUNARG_parameter_validation",
    276     "VK_LAYER_LUNARG_object_tracker",
    277     "VK_LAYER_LUNARG_core_validation",
    278     "VK_LAYER_LUNARG_device_limits",
    279     "VK_LAYER_LUNARG_image",
    280     "VK_LAYER_LUNARG_swapchain",
    281     "VK_LAYER_GOOGLE_unique_objects"
    282 };
    283 
    284 uint32_t device_layer_request_count =
    285    sizeof(device_layers) / sizeof(device_layers[0]);
    286 for (uint32_t i = 0; i < device_layer_request_count; i++) {
    287     bool found = false;
    288     for (uint32_t j = 0; j < device_layer_present_count; j++) {
    289         if (strcmp(device_layers[i],
    290            layer_props[j].layerName) == 0) {
    291             found = true;
    292         }
    293     }
    294     if (!found) {
    295         error();
    296     }
    297 }
    298 
    299 // Pass desired device layers into vkCreateDevice
    300 VkDeviceCreateInfo device_info = {};
    301 device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    302 device_info.enabledLayerCount = device_layer_request_count;
    303 device_info.ppEnabledLayerNames = device_layers;
    304 ...
    305 </pre>
    306 
    307 <h2 id="debug">Enabling the Debug Callback</h2>
    308 
    309 <p>
    310 The Debug Report extension {@code VK_EXT_debug_report} allows your application to control
    311 layer behavior when an event occurs.</p>
    312 
    313 <p>
    314 Before using this extension, you must first make sure that the platform supports it.
    315 The following example shows how to check for debug extension support and
    316 register a callback if the extension is supported.
    317 </p>
    318 
    319 <pre>
    320 // Get the instance extension count
    321 uint32_t inst_ext_count = 0;
    322 vkEnumerateInstanceExtensionProperties(nullptr, &inst_ext_count, nullptr);
    323 
    324 // Enumerate the instance extensions
    325 VkExtensionProperties* inst_exts =
    326     (VkExtensionProperties *)malloc(inst_ext_count * sizeof(VkExtensionProperties));
    327 vkEnumerateInstanceExtensionProperties(nullptr, &inst_ext_count, inst_exts);
    328 
    329 const char * enabled_inst_exts[16] = {};
    330 uint32_t enabled_inst_ext_count = 0;
    331 
    332 // Make sure the debug report extension is available
    333 for (uint32_t i = 0; i < inst_ext_count; i++) {
    334     if (strcmp(inst_exts[i].extensionName,
    335     VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
    336         enabled_inst_exts[enabled_inst_ext_count++] =
    337             VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
    338     }
    339 }
    340 
    341 if (enabled_inst_ext_count == 0)
    342     return;
    343 
    344 // Pass the instance extensions into vkCreateInstance
    345 VkInstanceCreateInfo instance_info = {};
    346 instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    347 instance_info.enabledExtensionCount = enabled_inst_ext_count;
    348 instance_info.ppEnabledExtensionNames = enabled_inst_exts;
    349 
    350 PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
    351 PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
    352 
    353 vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)
    354     vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
    355 vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)
    356     vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
    357 
    358 assert(vkCreateDebugReportCallbackEXT);
    359 assert(vkDestroyDebugReportCallbackEXT);
    360 
    361 // Create the debug callback with desired settings
    362 VkDebugReportCallbackEXT debugReportCallback;
    363 if (vkCreateDebugReportCallbackEXT) {
    364     VkDebugReportCallbackCreateInfoEXT debugReportCallbackCreateInfo;
    365     debugReportCallbackCreateInfo.sType =
    366         VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
    367     debugReportCallbackCreateInfo.pNext = NULL;
    368     debugReportCallbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
    369                                           VK_DEBUG_REPORT_WARNING_BIT_EXT |
    370                                           VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
    371     debugReportCallbackCreateInfo.pfnCallback = DebugReportCallback;
    372     debugReportCallbackCreateInfo.pUserData = NULL;
    373 
    374     vkCreateDebugReportCallbackEXT(instance, &debugReportCallbackCreateInfo,
    375                                    nullptr, &debugReportCallback);
    376 }
    377 
    378 // Later, when shutting down Vulkan, call the following
    379 if (vkDestroyDebugReportCallbackEXT) {
    380    vkDestroyDebugReportCallbackEXT(instance, debugReportCallback, nullptr);
    381 }
    382 
    383 </pre>
    384 
    385 <p>
    386 Once your app has registered and enabled the debug callback, the system routes debugging
    387 messages to a callback that you register. An example of such a callback appears below:
    388 </p>
    389 
    390 
    391 <pre>
    392 #include &lt;android/log.h&gt;
    393 
    394 static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(
    395                                    VkDebugReportFlagsEXT msgFlags,
    396                                    VkDebugReportObjectTypeEXT objType,
    397                                    uint64_t srcObject, size_t location,
    398                                    int32_t msgCode, const char * pLayerPrefix,
    399                                    const char * pMsg, void * pUserData )
    400 {
    401    if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
    402        __android_log_print(ANDROID_LOG_ERROR,
    403                            "AppName",
    404                            "ERROR: [%s] Code %i : %s",
    405                            pLayerPrefix, msgCode, pMsg);
    406    } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
    407        __android_log_print(ANDROID_LOG_WARN,
    408                            "AppName",
    409                            "WARNING: [%s] Code %i : %s",
    410                            pLayerPrefix, msgCode, pMsg);
    411    } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
    412        __android_log_print(ANDROID_LOG_WARN,
    413                            "AppName",
    414                            "PERFORMANCE WARNING: [%s] Code %i : %s",
    415                            pLayerPrefix, msgCode, pMsg);
    416    } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
    417        __android_log_print(ANDROID_LOG_INFO,
    418                            "AppName", "INFO: [%s] Code %i : %s",
    419                            pLayerPrefix, msgCode, pMsg);
    420    } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
    421        __android_log_print(ANDROID_LOG_VERBOSE,
    422                            "AppName", "DEBUG: [%s] Code %i : %s",
    423                            pLayerPrefix, msgCode, pMsg);
    424    }
    425 
    426    // Returning false tells the layer not to stop when the event occurs, so
    427    // they see the same behavior with and without validation layers enabled.
    428    return VK_FALSE;
    429 }
    430 </pre>
    431 
    432 
    433 
    434