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 &lt;android/log.h&gt;
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