1page.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> 19Most explicit graphics APIs do not perform error-checking, because doing so can result in a 20performance penalty. Vulkan provides error-checking in a manner that lets you use this feature at 21development time, but exclude it from the release build of your app, thus avoiding the penalty when 22it matters most. You do this by enabling <em>validation layers</em>. Validation layers intercept 23or hook Vulkan entry points for various debug and validation purposes. 24</p> 25 26<p> 27Each validation layer can contain definitions for one or more of these entry points, and 28intercepts the entry points for which it contains definitions. When a validation 29layer does not define an entry point, the system passes the entry point on to the next 30layer. Ultimately, an entry point not defined in any layer reaches the driver, the 31base level, unvalidated. 32</p> 33 34<p> 35The Android SDK, NDK, and Vulkan samples include Vulkan validation layers for 36use during development. You can hook these validation layers into the graphics stack, allowing 37them to report validation issues. This instrumentation allows you to catch and fix misuses 38during development. 39</p> 40 41<p> 42This 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"> 82sourceSets { 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"> 96sources { 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> 122If 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"> 124GitHub repository</a> and follow the build instructions there. 125</p> 126 127<h2 id="verifying">Verifying Layer Build</h2> 128 129<p> 130Regardless of whether you build with NDK's prebuilt layers or you build from the latest source code, 131the build process produces final file structure like the following: 132</p> 133 134<pre class="no-pretty-print"> 135src/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> 151The following example shows how to verify that your APK contains the validation layers 152as 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> 177A layer that can intercept Vulkan instance-level entry points is called an instance layer. 178Instance-level entry points are those with {@code VkInstance} or {@code VkPhysicalDevice} 179as the first parameter. 180</p> 181 182<p> 183You can call {@code vkEnumerateInstanceLayerProperties()} to list the available instance layers 184and their properties. The system enables instance layers when {@code vkCreateInstace()} executes. 185</p> 186 187<p> 188The following code snippet shows how an app can use the Vulkan API to programmatically enable and 189query an instance layer: 190</p> 191 192<pre> 193// Get instance layer count using null pointer as last parameter 194uint32_t instance_layer_present_count = 0; 195vkEnumerateInstanceLayerProperties(&instance_layer_present_count, nullptr); 196 197// Enumerate instance layers with valid pointer in last parameter 198VkLayerProperties* layer_props = 199 (VkLayerProperties*)malloc(instance_layer_present_count * sizeof(VkLayerProperties)); 200vkEnumerateInstanceLayerProperties(&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. 206const 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 217uint32_t instance_layer_request_count = 218 sizeof(instance_layers) / sizeof(instance_layers[0]); 219for (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 232VkInstanceCreateInfo instance_info = {}; 233instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 234instance_info.enabledLayerCount = instance_layer_request_count; 235instance_info.ppEnabledLayerNames = instance_layers; 236... 237</pre> 238 239<h3>Device layers</h3> 240 241<p> 242A layer that can intercept device-level entry points is called a device layer. Device-level entry 243points are those whose first parameter is {@code VkDevice}, {@code VkCommandBuffer}, 244or {@code VkQueue}. The list of 245device layers to enable is included in the {@code ppEnabledLayerNames} field of the 246{@code VkDeviceCreateInfo} 247struct that the app passes into {@code vkCreateDevice()}. 248</p> 249 250<p> 251You can call {@code vkEnumerateDeviceLayerProperties} to list the available layers 252and their properties. The system enables device layers when it calls {@code vkCreateDevice()}. 253</p> 254 255<p> 256The following code snippet shows how an app can use the Vulkan API to programmatically enable a 257device layer. 258</p> 259 260<pre> 261 262// Get device layer count using null as last parameter 263uint32_t device_layer_present_count = 0; 264vkEnumerateDeviceLayerProperties(&device_layer_present_count, nullptr); 265 266// Enumerate device layers with valid pointer in last parameter 267VkLayerProperties* layer_props = 268 (VkLayerProperties *)malloc(device_layer_present_count * sizeof(VkLayerProperties)); 269vkEnumerateDeviceLayerProperties(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! 273const 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 284uint32_t device_layer_request_count = 285 sizeof(device_layers) / sizeof(device_layers[0]); 286for (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 300VkDeviceCreateInfo device_info = {}; 301device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 302device_info.enabledLayerCount = device_layer_request_count; 303device_info.ppEnabledLayerNames = device_layers; 304... 305</pre> 306 307<h2 id="debug">Enabling the Debug Callback</h2> 308 309<p> 310The Debug Report extension {@code VK_EXT_debug_report} allows your application to control 311layer behavior when an event occurs.</p> 312 313<p> 314Before using this extension, you must first make sure that the platform supports it. 315The following example shows how to check for debug extension support and 316register a callback if the extension is supported. 317</p> 318 319<pre> 320// Get the instance extension count 321uint32_t inst_ext_count = 0; 322vkEnumerateInstanceExtensionProperties(nullptr, &inst_ext_count, nullptr); 323 324// Enumerate the instance extensions 325VkExtensionProperties* inst_exts = 326 (VkExtensionProperties *)malloc(inst_ext_count * sizeof(VkExtensionProperties)); 327vkEnumerateInstanceExtensionProperties(nullptr, &inst_ext_count, inst_exts); 328 329const char * enabled_inst_exts[16] = {}; 330uint32_t enabled_inst_ext_count = 0; 331 332// Make sure the debug report extension is available 333for (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 341if (enabled_inst_ext_count == 0) 342 return; 343 344// Pass the instance extensions into vkCreateInstance 345VkInstanceCreateInfo instance_info = {}; 346instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 347instance_info.enabledExtensionCount = enabled_inst_ext_count; 348instance_info.ppEnabledExtensionNames = enabled_inst_exts; 349 350PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; 351PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; 352 353vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT) 354 vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); 355vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT) 356 vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); 357 358assert(vkCreateDebugReportCallbackEXT); 359assert(vkDestroyDebugReportCallbackEXT); 360 361// Create the debug callback with desired settings 362VkDebugReportCallbackEXT debugReportCallback; 363if (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 379if (vkDestroyDebugReportCallbackEXT) { 380 vkDestroyDebugReportCallbackEXT(instance, debugReportCallback, nullptr); 381} 382 383</pre> 384 385<p> 386Once your app has registered and enabled the debug callback, the system routes debugging 387messages to a callback that you register. An example of such a callback appears below: 388</p> 389 390 391<pre> 392#include <android/log.h> 393 394static 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