1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
2  * Copyright (c) 2015-2016 Valve Corporation
3  * Copyright (c) 2015-2016 LunarG, Inc.
4  * Copyright (C) 2015-2016 Google Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * Author: Dustin Graves <dustin@lunarg.com>
19  */
20 
21 #ifndef PARAMETER_VALIDATION_UTILS_H
22 #define PARAMETER_VALIDATION_UTILS_H
23 
24 #include <algorithm>
25 #include <cstdlib>
26 #include <string>
27 #include <sstream>
28 #include <bitset>
29 #include <mutex>
30 #include <unordered_map>
31 #include <unordered_set>
32 
33 #include "vulkan/vulkan.h"
34 #include "vk_enum_string_helper.h"
35 #include "vk_layer_logging.h"
36 #include "vk_validation_error_messages.h"
37 #include "vk_extension_helper.h"
38 
39 #include "parameter_name.h"
40 
41 namespace parameter_validation {
42 
43 extern const uint32_t GeneratedHeaderVersion;
44 extern const std::unordered_map<std::string, void *> name_to_funcptr_map;
45 
46 extern const VkQueryPipelineStatisticFlags AllVkQueryPipelineStatisticFlagBits;
47 extern const VkColorComponentFlags AllVkColorComponentFlagBits;
48 extern const VkShaderStageFlags AllVkShaderStageFlagBits;
49 extern const VkQueryControlFlags AllVkQueryControlFlagBits;
50 
51 extern const std::vector<VkCompareOp> AllVkCompareOpEnums;
52 extern const std::vector<VkStencilOp> AllVkStencilOpEnums;
53 extern const std::vector<VkBlendFactor> AllVkBlendFactorEnums;
54 extern const std::vector<VkBlendOp> AllVkBlendOpEnums;
55 extern const std::vector<VkLogicOp> AllVkLogicOpEnums;
56 extern const std::vector<VkBorderColor> AllVkBorderColorEnums;
57 extern const std::vector<VkImageLayout> AllVkImageLayoutEnums;
58 
59 struct instance_layer_data {
60     VkInstance instance = VK_NULL_HANDLE;
61 
62     debug_report_data *report_data = nullptr;
63     std::vector<VkDebugReportCallbackEXT> logging_callback;
64 
65     // The following are for keeping track of the temporary callbacks that can
66     // be used in vkCreateInstance and vkDestroyInstance:
67     uint32_t num_tmp_callbacks = 0;
68     VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos = nullptr;
69     VkDebugReportCallbackEXT *tmp_callbacks = nullptr;
70     InstanceExtensions extensions = {};
71     VkLayerInstanceDispatchTable dispatch_table = {};
72 };
73 
74 struct layer_data {
75     debug_report_data *report_data = nullptr;
76     // Map for queue family index to queue count
77     std::unordered_map<uint32_t, uint32_t> queueFamilyIndexMap;
78     VkPhysicalDeviceLimits device_limits = {};
79     VkPhysicalDeviceFeatures physical_device_features = {};
80     VkPhysicalDevice physical_device = VK_NULL_HANDLE;
81     VkDevice device = VK_NULL_HANDLE;
82     DeviceExtensions extensions;
83 
84     struct SubpassesUsageStates {
85         std::unordered_set<uint32_t> subpasses_using_color_attachment;
86         std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
87     };
88 
89     std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
90 
91     VkLayerDispatchTable dispatch_table = {};
92 };
93 
94 enum ErrorCode {
95     NONE,                   // Used for INFO & other non-error messages
96     INVALID_USAGE,          // The value of a parameter is not consistent
97                             // with the valid usage criteria defined in
98                             // the Vulkan specification.
99     INVALID_STRUCT_STYPE,   // The sType field of a Vulkan structure does
100                             // not contain the value expected for a structure
101                             // of that type.
102     INVALID_STRUCT_PNEXT,   // The pNext field of a Vulkan structure references
103                             // a value that is not compatible with a structure of
104                             // that type or is not NULL when a structure of that
105                             // type has no compatible pNext values.
106     REQUIRED_PARAMETER,     // A required parameter was specified as 0 or NULL.
107     RESERVED_PARAMETER,     // A parameter reserved for future use was not
108                             // specified as 0 or NULL.
109     UNRECOGNIZED_VALUE,     // A Vulkan enumeration, VkFlags, or VkBool32 parameter
110                             // contains a value that is not recognized as valid for
111                             // that type.
112     DEVICE_LIMIT,           // A specified parameter exceeds the limits returned
113                             // by the physical device
114     DEVICE_FEATURE,         // Use of a requested feature is not supported by
115                             // the device
116     FAILURE_RETURN_CODE,    // A Vulkan return code indicating a failure condition
117                             // was encountered.
118     EXTENSION_NOT_ENABLED,  // An extension entrypoint was called, but the required
119                             // extension was not enabled at CreateInstance or
120                             // CreateDevice time.
121 };
122 
123 struct GenericHeader {
124     VkStructureType sType;
125     const void *pNext;
126 };
127 
128 // Layer name string to be logged with validation messages.
129 const char LayerName[] = "ParameterValidation";
130 
131 // String returned by string_VkStructureType for an unrecognized type.
132 const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
133 
134 // String returned by string_VkResult for an unrecognized type.
135 const std::string UnsupportedResultString = "Unhandled VkResult";
136 
137 // The base value used when computing the offset for an enumeration token value that is added by an extension.
138 // When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
139 // See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
140 const uint32_t ExtEnumBaseValue = 1000000000;
141 
142 // The value of all VK_xxx_MAX_ENUM tokens
143 const uint32_t MaxEnumValue = 0x7FFFFFFF;
144 
145 // Misc parameters of log_msg that are likely constant per command (or low frequency change)
146 struct LogMiscParams {
147     const debug_report_data *debug_data;
148     VkDebugReportObjectTypeEXT objectType;
149     uint64_t srcObject;
150     const char *pLayerPrefix;
151     const char *api_name;
152 };
153 
154 /**
155  * Validate a minimum value.
156  *
157  * Verify that the specified value is greater than the specified lower bound.
158  *
159  * @param report_data debug_report_data object for routing validation messages.
160  * @param api_name Name of API call being validated.
161  * @param parameter_name Name of parameter being validated.
162  * @param value Value to validate.
163  * @param lower_bound Lower bound value to use for validation.
164  * @return Boolean value indicating that the call should be skipped.
165  */
166 template <typename T>
ValidateGreaterThan(const T value,const T lower_bound,const ParameterName & parameter_name,const UNIQUE_VALIDATION_ERROR_CODE vuid,const LogMiscParams & misc)167 bool ValidateGreaterThan(const T value, const T lower_bound, const ParameterName &parameter_name,
168                          const UNIQUE_VALIDATION_ERROR_CODE vuid, const LogMiscParams &misc) {
169     bool skip_call = false;
170 
171     if (value <= lower_bound) {
172         std::ostringstream ss;
173         ss << misc.api_name << ": parameter " << parameter_name.get_name() << " (= " << value << ") is greater than " << lower_bound
174            << ". " << validation_error_map[vuid];
175         skip_call |= log_msg(misc.debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, misc.objectType, misc.srcObject, __LINE__, vuid,
176                              misc.pLayerPrefix, "%s", ss.str().c_str());
177     }
178 
179     return skip_call;
180 }
181 
182 template <typename T>
ValidateGreaterThanZero(const T value,const ParameterName & parameter_name,const UNIQUE_VALIDATION_ERROR_CODE vuid,const LogMiscParams & misc)183 bool ValidateGreaterThanZero(const T value, const ParameterName &parameter_name, const UNIQUE_VALIDATION_ERROR_CODE vuid,
184                              const LogMiscParams &misc) {
185     return ValidateGreaterThan(value, T{0}, parameter_name, vuid, misc);
186 }
187 /**
188  * Validate a required pointer.
189  *
190  * Verify that a required pointer is not NULL.
191  *
192  * @param report_data debug_report_data object for routing validation messages.
193  * @param apiName Name of API call being validated.
194  * @param parameterName Name of parameter being validated.
195  * @param value Pointer to validate.
196  * @return Boolean value indicating that the call should be skipped.
197  */
validate_required_pointer(debug_report_data * report_data,const char * apiName,const ParameterName & parameterName,const void * value,UNIQUE_VALIDATION_ERROR_CODE vuid)198 static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
199                                       const void *value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
200     bool skip_call = false;
201 
202     if (value == NULL) {
203         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
204                              LayerName, "%s: required parameter %s specified as NULL. %s", apiName,
205                              parameterName.get_name().c_str(), validation_error_map[vuid]);
206     }
207 
208     return skip_call;
209 }
210 
211 /**
212  * Validate array count and pointer to array.
213  *
214  * Verify that required count and array parameters are not 0 or NULL.  If the
215  * count parameter is not optional, verify that it is not 0.  If the array
216  * parameter is NULL, and it is not optional, verify that count is 0.
217  *
218  * @param report_data debug_report_data object for routing validation messages.
219  * @param apiName Name of API call being validated.
220  * @param countName Name of count parameter.
221  * @param arrayName Name of array parameter.
222  * @param count Number of elements in the array.
223  * @param array Array to validate.
224  * @param countRequired The 'count' parameter may not be 0 when true.
225  * @param arrayRequired The 'array' parameter may not be NULL when true.
226  * @return Boolean value indicating that the call should be skipped.
227  */
228 template <typename T>
validate_array(debug_report_data * report_data,const char * apiName,const ParameterName & countName,const ParameterName & arrayName,T count,const void * array,bool countRequired,bool arrayRequired,UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,UNIQUE_VALIDATION_ERROR_CODE array_required_vuid)229 bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
230                     const ParameterName &arrayName, T count, const void *array, bool countRequired, bool arrayRequired,
231                     UNIQUE_VALIDATION_ERROR_CODE count_required_vuid, UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
232     bool skip_call = false;
233 
234     // Count parameters not tagged as optional cannot be 0
235     if (countRequired && (count == 0)) {
236         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
237                              count_required_vuid, LayerName, "%s: parameter %s must be greater than 0. %s", apiName,
238                              countName.get_name().c_str(), validation_error_map[count_required_vuid]);
239     }
240 
241     // Array parameters not tagged as optional cannot be NULL, unless the count is 0
242     if ((array == NULL) && arrayRequired && (count != 0)) {
243         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
244                              array_required_vuid, LayerName, "%s: required parameter %s specified as NULL. %s", apiName,
245                              arrayName.get_name().c_str(), validation_error_map[array_required_vuid]);
246     }
247 
248     return skip_call;
249 }
250 
251 /**
252  * Validate pointer to array count and pointer to array.
253  *
254  * Verify that required count and array parameters are not NULL.  If count
255  * is not NULL and its value is not optional, verify that it is not 0.  If the
256  * array parameter is NULL, and it is not optional, verify that count is 0.
257  * The array parameter will typically be optional for this case (where count is
258  * a pointer), allowing the caller to retrieve the available count.
259  *
260  * @param report_data debug_report_data object for routing validation messages.
261  * @param apiName Name of API call being validated.
262  * @param countName Name of count parameter.
263  * @param arrayName Name of array parameter.
264  * @param count Pointer to the number of elements in the array.
265  * @param array Array to validate.
266  * @param countPtrRequired The 'count' parameter may not be NULL when true.
267  * @param countValueRequired The '*count' value may not be 0 when true.
268  * @param arrayRequired The 'array' parameter may not be NULL when true.
269  * @return Boolean value indicating that the call should be skipped.
270  */
271 template <typename T>
validate_array(debug_report_data * report_data,const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const T * count,const void * array,bool countPtrRequired,bool countValueRequired,bool arrayRequired,UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,UNIQUE_VALIDATION_ERROR_CODE array_required_vuid)272 bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
273                     const ParameterName &arrayName, const T *count, const void *array, bool countPtrRequired,
274                     bool countValueRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
275                     UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
276     bool skip_call = false;
277 
278     if (count == NULL) {
279         if (countPtrRequired) {
280             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
281                                  REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
282                                  countName.get_name().c_str());
283         }
284     } else {
285         skip_call |= validate_array(report_data, apiName, countName, arrayName, array ? (*count) : 0, array, countValueRequired,
286                                     arrayRequired, count_required_vuid, array_required_vuid);
287     }
288 
289     return skip_call;
290 }
291 
292 /**
293  * Validate a pointer to a Vulkan structure.
294  *
295  * Verify that a required pointer to a structure is not NULL.  If the pointer is
296  * not NULL, verify that each structure's sType field is set to the correct
297  * VkStructureType value.
298  *
299  * @param report_data debug_report_data object for routing validation messages.
300  * @param apiName Name of API call being validated.
301  * @param parameterName Name of struct parameter being validated.
302  * @param sTypeName Name of expected VkStructureType value.
303  * @param value Pointer to the struct to validate.
304  * @param sType VkStructureType for structure validation.
305  * @param required The parameter may not be NULL when true.
306  * @return Boolean value indicating that the call should be skipped.
307  */
308 template <typename T>
validate_struct_type(debug_report_data * report_data,const char * apiName,const ParameterName & parameterName,const char * sTypeName,const T * value,VkStructureType sType,bool required,UNIQUE_VALIDATION_ERROR_CODE vuid)309 bool validate_struct_type(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
310                           const char *sTypeName, const T *value, VkStructureType sType, bool required,
311                           UNIQUE_VALIDATION_ERROR_CODE vuid) {
312     bool skip_call = false;
313 
314     if (value == NULL) {
315         if (required) {
316             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
317                                  REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
318                                  parameterName.get_name().c_str());
319         }
320     } else if (value->sType != sType) {
321         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
322                              LayerName, "%s: parameter %s->sType must be %s. %s", apiName, parameterName.get_name().c_str(),
323                              sTypeName, validation_error_map[vuid]);
324     }
325 
326     return skip_call;
327 }
328 
329 /**
330  * Validate an array of Vulkan structures
331  *
332  * Verify that required count and array parameters are not 0 or NULL.  If
333  * the array contains 1 or more structures, verify that each structure's
334  * sType field is set to the correct VkStructureType value.
335  *
336  * @param report_data debug_report_data object for routing validation messages.
337  * @param apiName Name of API call being validated.
338  * @param countName Name of count parameter.
339  * @param arrayName Name of array parameter.
340  * @param sTypeName Name of expected VkStructureType value.
341  * @param count Number of elements in the array.
342  * @param array Array to validate.
343  * @param sType VkStructureType for structure validation.
344  * @param countRequired The 'count' parameter may not be 0 when true.
345  * @param arrayRequired The 'array' parameter may not be NULL when true.
346  * @return Boolean value indicating that the call should be skipped.
347  */
348 template <typename T>
validate_struct_type_array(debug_report_data * report_data,const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * sTypeName,uint32_t count,const T * array,VkStructureType sType,bool countRequired,bool arrayRequired,UNIQUE_VALIDATION_ERROR_CODE vuid)349 bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
350                                 const ParameterName &arrayName, const char *sTypeName, uint32_t count, const T *array,
351                                 VkStructureType sType, bool countRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE vuid) {
352     bool skip_call = false;
353 
354     if ((count == 0) || (array == NULL)) {
355         skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
356                                     VALIDATION_ERROR_UNDEFINED, vuid);
357     } else {
358         // Verify that all structs in the array have the correct type
359         for (uint32_t i = 0; i < count; ++i) {
360             if (array[i].sType != sType) {
361                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
362                                      __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
363                                      arrayName.get_name().c_str(), i, sTypeName);
364             }
365         }
366     }
367 
368     return skip_call;
369 }
370 
371 /**
372  * Validate an array of Vulkan structures.
373  *
374  * Verify that required count and array parameters are not NULL.  If count
375  * is not NULL and its value is not optional, verify that it is not 0.
376  * If the array contains 1 or more structures, verify that each structure's
377  * sType field is set to the correct VkStructureType value.
378  *
379  * @param report_data debug_report_data object for routing validation messages.
380  * @param apiName Name of API call being validated.
381  * @param countName Name of count parameter.
382  * @param arrayName Name of array parameter.
383  * @param sTypeName Name of expected VkStructureType value.
384  * @param count Pointer to the number of elements in the array.
385  * @param array Array to validate.
386  * @param sType VkStructureType for structure validation.
387  * @param countPtrRequired The 'count' parameter may not be NULL when true.
388  * @param countValueRequired The '*count' value may not be 0 when true.
389  * @param arrayRequired The 'array' parameter may not be NULL when true.
390  * @return Boolean value indicating that the call should be skipped.
391  */
392 template <typename T>
validate_struct_type_array(debug_report_data * report_data,const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * sTypeName,uint32_t * count,const T * array,VkStructureType sType,bool countPtrRequired,bool countValueRequired,bool arrayRequired,UNIQUE_VALIDATION_ERROR_CODE vuid)393 bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
394                                 const ParameterName &arrayName, const char *sTypeName, uint32_t *count, const T *array,
395                                 VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired,
396                                 UNIQUE_VALIDATION_ERROR_CODE vuid) {
397     bool skip_call = false;
398 
399     if (count == NULL) {
400         if (countPtrRequired) {
401             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
402                                  REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
403                                  countName.get_name().c_str());
404         }
405     } else {
406         skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
407                                                 countValueRequired, arrayRequired, vuid);
408     }
409 
410     return skip_call;
411 }
412 
413 /**
414  * Validate a Vulkan handle.
415  *
416  * Verify that the specified handle is not VK_NULL_HANDLE.
417  *
418  * @param report_data debug_report_data object for routing validation messages.
419  * @param api_name Name of API call being validated.
420  * @param parameter_name Name of struct parameter being validated.
421  * @param value Handle to validate.
422  * @return Boolean value indicating that the call should be skipped.
423  */
424 template <typename T>
validate_required_handle(debug_report_data * report_data,const char * api_name,const ParameterName & parameter_name,T value)425 bool validate_required_handle(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, T value) {
426     bool skip_call = false;
427 
428     if (value == VK_NULL_HANDLE) {
429         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
430                              REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
431                              parameter_name.get_name().c_str());
432     }
433 
434     return skip_call;
435 }
436 
437 /**
438  * Validate an array of Vulkan handles.
439  *
440  * Verify that required count and array parameters are not NULL.  If count
441  * is not NULL and its value is not optional, verify that it is not 0.
442  * If the array contains 1 or more handles, verify that no handle is set to
443  * VK_NULL_HANDLE.
444  *
445  * @note This function is only intended to validate arrays of handles when none
446  *       of the handles are allowed to be VK_NULL_HANDLE.  For arrays of handles
447  *       that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
448  *
449  * @param report_data debug_report_data object for routing validation messages.
450  * @param api_name Name of API call being validated.
451  * @param count_name Name of count parameter.
452  * @param array_name Name of array parameter.
453  * @param count Number of elements in the array.
454  * @param array Array to validate.
455  * @param count_required The 'count' parameter may not be 0 when true.
456  * @param array_required The 'array' parameter may not be NULL when true.
457  * @return Boolean value indicating that the call should be skipped.
458  */
459 template <typename T>
validate_handle_array(debug_report_data * report_data,const char * api_name,const ParameterName & count_name,const ParameterName & array_name,uint32_t count,const T * array,bool count_required,bool array_required)460 bool validate_handle_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
461                            const ParameterName &array_name, uint32_t count, const T *array, bool count_required,
462                            bool array_required) {
463     bool skip_call = false;
464 
465     if ((count == 0) || (array == NULL)) {
466         skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
467                                     VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
468     } else {
469         // Verify that no handles in the array are VK_NULL_HANDLE
470         for (uint32_t i = 0; i < count; ++i) {
471             if (array[i] == VK_NULL_HANDLE) {
472                 skip_call |=
473                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
474                             REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name,
475                             array_name.get_name().c_str(), i);
476             }
477         }
478     }
479 
480     return skip_call;
481 }
482 
483 /**
484  * Validate string array count and content.
485  *
486  * Verify that required count and array parameters are not 0 or NULL.  If the
487  * count parameter is not optional, verify that it is not 0.  If the array
488  * parameter is NULL, and it is not optional, verify that count is 0.  If the
489  * array parameter is not NULL, verify that none of the strings are NULL.
490  *
491  * @param report_data debug_report_data object for routing validation messages.
492  * @param apiName Name of API call being validated.
493  * @param countName Name of count parameter.
494  * @param arrayName Name of array parameter.
495  * @param count Number of strings in the array.
496  * @param array Array of strings to validate.
497  * @param countRequired The 'count' parameter may not be 0 when true.
498  * @param arrayRequired The 'array' parameter may not be NULL when true.
499  * @return Boolean value indicating that the call should be skipped.
500  */
validate_string_array(debug_report_data * report_data,const char * apiName,const ParameterName & countName,const ParameterName & arrayName,uint32_t count,const char * const * array,bool countRequired,bool arrayRequired,UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,UNIQUE_VALIDATION_ERROR_CODE array_required_vuid)501 static bool validate_string_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
502                                   const ParameterName &arrayName, uint32_t count, const char *const *array, bool countRequired,
503                                   bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
504                                   UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
505     bool skip_call = false;
506 
507     if ((count == 0) || (array == NULL)) {
508         skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
509                                     count_required_vuid, array_required_vuid);
510     } else {
511         // Verify that strings in the array are not NULL
512         for (uint32_t i = 0; i < count; ++i) {
513             if (array[i] == NULL) {
514                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
515                                      __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
516                                      apiName, arrayName.get_name().c_str(), i);
517             }
518         }
519     }
520 
521     return skip_call;
522 }
523 
524 /**
525  * Validate a structure's pNext member.
526  *
527  * Verify that the specified pNext value points to the head of a list of
528  * allowed extension structures.  If no extension structures are allowed,
529  * verify that pNext is null.
530  *
531  * @param report_data debug_report_data object for routing validation messages.
532  * @param api_name Name of API call being validated.
533  * @param parameter_name Name of parameter being validated.
534  * @param allowed_struct_names Names of allowed structs.
535  * @param next Pointer to validate.
536  * @param allowed_type_count Total number of allowed structure types.
537  * @param allowed_types Array of strcuture types allowed for pNext.
538  * @param header_version Version of header defining the pNext validation rules.
539  * @return Boolean value indicating that the call should be skipped.
540  */
validate_struct_pnext(debug_report_data * report_data,const char * api_name,const ParameterName & parameter_name,const char * allowed_struct_names,const void * next,size_t allowed_type_count,const VkStructureType * allowed_types,uint32_t header_version,UNIQUE_VALIDATION_ERROR_CODE vuid)541 static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
542                                   const char *allowed_struct_names, const void *next, size_t allowed_type_count,
543                                   const VkStructureType *allowed_types, uint32_t header_version,
544                                   UNIQUE_VALIDATION_ERROR_CODE vuid) {
545     bool skip_call = false;
546     std::unordered_set<const void *> cycle_check;
547     std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
548 
549     const char disclaimer[] =
550         "This warning is based on the Valid Usage documentation for version %d of the Vulkan header.  It is possible that you are "
551         "using a struct from a private extension or an extension that was added to a later version of the Vulkan header, in which "
552         "case your use of %s is perfectly valid but is not guaranteed to work correctly with validation enabled";
553 
554     // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
555     // Codegen a map of vectors containing the allowable pNext types for each struct and use that here -- also simplifies parms.
556     if (next != NULL) {
557         if (allowed_type_count == 0) {
558             std::string message = "%s: value of %s must be NULL. %s ";
559             message += disclaimer;
560             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
561                                  vuid, LayerName, message.c_str(), api_name, parameter_name.get_name().c_str(),
562                                  validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
563         } else {
564             const VkStructureType *start = allowed_types;
565             const VkStructureType *end = allowed_types + allowed_type_count;
566             const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
567 
568             cycle_check.insert(next);
569 
570             while (current != NULL) {
571                 if (cycle_check.find(current->pNext) != cycle_check.end()) {
572                     std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
573                     skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
574                                          __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
575                                          parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next));
576                     break;
577                 } else {
578                     cycle_check.insert(current->pNext);
579                 }
580 
581                 std::string type_name = string_VkStructureType(current->sType);
582                 if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
583                     std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
584                     skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
585                                          __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
586                                          parameter_name.get_name().c_str(), type_name.c_str());
587                 } else {
588                     unique_stype_check.insert(current->sType);
589                 }
590 
591                 if (std::find(start, end, current->sType) == end) {
592                     if (type_name == UnsupportedStructureTypeString) {
593                         std::string message =
594                             "%s: %s chain includes a structure with unknown VkStructureType (%d); Allowed structures are [%s]. %s ";
595                         message += disclaimer;
596                         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
597                                              0, __LINE__, vuid, LayerName, message.c_str(), api_name,
598                                              parameter_name.get_name().c_str(), current->sType, allowed_struct_names,
599                                              validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
600                     } else {
601                         std::string message =
602                             "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]. "
603                             "%s ";
604                         message += disclaimer;
605                         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
606                                              0, __LINE__, vuid, LayerName, message.c_str(), api_name,
607                                              parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names,
608                                              validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
609                     }
610                 }
611                 current = reinterpret_cast<const GenericHeader *>(current->pNext);
612             }
613         }
614     }
615 
616     return skip_call;
617 }
618 
619 /**
620  * Validate a VkBool32 value.
621  *
622  * Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
623  *
624  * @param report_data debug_report_data object for routing validation messages.
625  * @param apiName Name of API call being validated.
626  * @param parameterName Name of parameter being validated.
627  * @param value Boolean value to validate.
628  * @return Boolean value indicating that the call should be skipped.
629  */
validate_bool32(debug_report_data * report_data,const char * apiName,const ParameterName & parameterName,VkBool32 value)630 static bool validate_bool32(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
631                             VkBool32 value) {
632     bool skip_call = false;
633 
634     if ((value != VK_TRUE) && (value != VK_FALSE)) {
635         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
636                              UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
637                              parameterName.get_name().c_str(), value);
638     }
639 
640     return skip_call;
641 }
642 
643 /**
644  * Validate a Vulkan enumeration value.
645  *
646  * Generate a warning if an enumeration token value does not fall within the core enumeration
647  * begin and end token values, and was not added to the enumeration by an extension.  Extension
648  * provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
649  * with 1,000,000,000 as the base token value.
650  *
651  * @note This function does not expect to process enumerations defining bitmask flag bits.
652  *
653  * @param report_data debug_report_data object for routing validation messages.
654  * @param apiName Name of API call being validated.
655  * @param parameterName Name of parameter being validated.
656  * @param enumName Name of the enumeration being validated.
657  * @param valid_values The list of valid values for the enumeration.
658  * @param value Enumeration value to validate.
659  * @return Boolean value indicating that the call should be skipped.
660  */
661 template <typename T>
validate_ranged_enum(debug_report_data * report_data,const char * apiName,const ParameterName & parameterName,const char * enumName,const std::vector<T> & valid_values,T value,UNIQUE_VALIDATION_ERROR_CODE vuid)662 bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
663                           const char *enumName, const std::vector<T> &valid_values, T value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
664     bool skip = false;
665 
666     if (std::find(valid_values.begin(), valid_values.end(), value) == valid_values.end()) {
667         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
668                         LayerName,
669                         "%s: value of %s (%d) does not fall within the begin..end range of the core %s enumeration tokens and is "
670                         "not an extension added token. %s",
671                         apiName, parameterName.get_name().c_str(), value, enumName, validation_error_map[vuid]);
672     }
673 
674     return skip;
675 }
676 
677 /**
678  * Validate an array of Vulkan enumeration value.
679  *
680  * Process all enumeration token values in the specified array and generate a warning if a value
681  * does not fall within the core enumeration begin and end token values, and was not added to
682  * the enumeration by an extension.  Extension provided enumerations use the equation specified
683  * in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
684  *
685  * @note This function does not expect to process enumerations defining bitmask flag bits.
686  *
687  * @param report_data debug_report_data object for routing validation messages.
688  * @param apiName Name of API call being validated.
689  * @param countName Name of count parameter.
690  * @param arrayName Name of array parameter.
691  * @param enumName Name of the enumeration being validated.
692  * @param valid_values The list of valid values for the enumeration.
693  * @param count Number of enumeration values in the array.
694  * @param array Array of enumeration values to validate.
695  * @param countRequired The 'count' parameter may not be 0 when true.
696  * @param arrayRequired The 'array' parameter may not be NULL when true.
697  * @return Boolean value indicating that the call should be skipped.
698  */
699 template <typename T>
validate_ranged_enum_array(debug_report_data * report_data,const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * enumName,const std::vector<T> & valid_values,uint32_t count,const T * array,bool countRequired,bool arrayRequired)700 static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
701                                        const ParameterName &arrayName, const char *enumName, const std::vector<T> &valid_values,
702                                        uint32_t count, const T *array, bool countRequired, bool arrayRequired) {
703     bool skip_call = false;
704 
705     if ((count == 0) || (array == NULL)) {
706         skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
707                                     VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
708     } else {
709         for (uint32_t i = 0; i < count; ++i) {
710             if (std::find(valid_values.begin(), valid_values.end(), array[i]) == valid_values.end()) {
711                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
712                                      __LINE__, UNRECOGNIZED_VALUE, LayerName,
713                                      "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
714                                      "enumeration tokens and is not an extension added token",
715                                      apiName, arrayName.get_name().c_str(), i, array[i], enumName);
716             }
717         }
718     }
719 
720     return skip_call;
721 }
722 
723 /**
724  * Verify that a reserved VkFlags value is zero.
725  *
726  * Verify that the specified value is zero, to check VkFlags values that are reserved for
727  * future use.
728  *
729  * @param report_data debug_report_data object for routing validation messages.
730  * @param api_name Name of API call being validated.
731  * @param parameter_name Name of parameter being validated.
732  * @param value Value to validate.
733  * @return Boolean value indicating that the call should be skipped.
734  */
validate_reserved_flags(debug_report_data * report_data,const char * api_name,const ParameterName & parameter_name,VkFlags value,UNIQUE_VALIDATION_ERROR_CODE vuid)735 static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
736                                     VkFlags value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
737     bool skip_call = false;
738 
739     if (value != 0) {
740         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
741                              LayerName, "%s: parameter %s must be 0. %s", api_name, parameter_name.get_name().c_str(),
742                              validation_error_map[vuid]);
743     }
744 
745     return skip_call;
746 }
747 
748 /**
749  * Validate a Vulkan bitmask value.
750  *
751  * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
752  * for that type.
753  *
754  * @param report_data debug_report_data object for routing validation messages.
755  * @param api_name Name of API call being validated.
756  * @param parameter_name Name of parameter being validated.
757  * @param flag_bits_name Name of the VkFlags type being validated.
758  * @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
759  * @param value VkFlags value to validate.
760  * @param flags_required The 'value' parameter may not be 0 when true.
761  * @param singleFlag The 'value' parameter may not contain more than one bit from all_flags.
762  * @return Boolean value indicating that the call should be skipped.
763  */
validate_flags(debug_report_data * report_data,const char * api_name,const ParameterName & parameter_name,const char * flag_bits_name,VkFlags all_flags,VkFlags value,bool flags_required,bool singleFlag,UNIQUE_VALIDATION_ERROR_CODE vuid)764 static bool validate_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
765                            const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required, bool singleFlag,
766                            UNIQUE_VALIDATION_ERROR_CODE vuid) {
767     bool skip_call = false;
768 
769     if (value == 0) {
770         if (flags_required) {
771             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
772                                  vuid, LayerName, "%s: value of %s must not be 0. %s", api_name, parameter_name.get_name().c_str(),
773                                  validation_error_map[vuid]);
774         }
775     } else if ((value & (~all_flags)) != 0) {
776         skip_call |=
777             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
778                     UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
779                     api_name, parameter_name.get_name().c_str(), flag_bits_name);
780     } else if (singleFlag && (std::bitset<sizeof(VkFlags) * 8>(value).count() > 1)) {
781         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
782                              UNRECOGNIZED_VALUE, LayerName,
783                              "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
784                              parameter_name.get_name().c_str(), flag_bits_name);
785     }
786 
787     return skip_call;
788 }
789 
790 /**
791  * Validate an array of Vulkan bitmask values.
792  *
793  * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
794  * for that type.
795  *
796  * @param report_data debug_report_data object for routing validation messages.
797  * @param api_name Name of API call being validated.
798  * @param count_name Name of parameter being validated.
799  * @param array_name Name of parameter being validated.
800  * @param flag_bits_name Name of the VkFlags type being validated.
801  * @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
802  * @param count Number of VkFlags values in the array.
803  * @param array Array of VkFlags value to validate.
804  * @param count_required The 'count' parameter may not be 0 when true.
805  * @param array_required The 'array' parameter may not be NULL when true.
806  * @return Boolean value indicating that the call should be skipped.
807  */
validate_flags_array(debug_report_data * report_data,const char * api_name,const ParameterName & count_name,const ParameterName & array_name,const char * flag_bits_name,VkFlags all_flags,uint32_t count,const VkFlags * array,bool count_required,bool array_required)808 static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
809                                  const ParameterName &array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
810                                  const VkFlags *array, bool count_required, bool array_required) {
811     bool skip_call = false;
812 
813     if ((count == 0) || (array == NULL)) {
814         skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
815                                     VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
816     } else {
817         // Verify that all VkFlags values in the array
818         for (uint32_t i = 0; i < count; ++i) {
819             if (array[i] == 0) {
820                 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
821                 // elements in the array are allowed be 0
822                 if (array_required) {
823                     skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
824                                          __LINE__, REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name,
825                                          array_name.get_name().c_str(), i);
826                 }
827             } else if ((array[i] & (~all_flags)) != 0) {
828                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
829                                      __LINE__, UNRECOGNIZED_VALUE, LayerName,
830                                      "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
831                                      array_name.get_name().c_str(), i, flag_bits_name);
832             }
833         }
834     }
835 
836     return skip_call;
837 }
838 
839 /**
840  * Get VkResult code description.
841  *
842  * Returns a string describing the specified VkResult code.  The description is based on the language in the Vulkan API
843  * specification.
844  *
845  * @param value VkResult code to process.
846  * @return String describing the specified VkResult code.
847  */
get_result_description(VkResult result)848 static std::string get_result_description(VkResult result) {
849     // clang-format off
850     switch (result) {
851         case VK_SUCCESS:                        return "a command completed successfully";
852         case VK_NOT_READY:                      return "a fence or query has not yet completed";
853         case VK_TIMEOUT:                        return "a wait operation has not completed in the specified time";
854         case VK_EVENT_SET:                      return "an event is signaled";
855         case VK_EVENT_RESET:                    return "an event is unsignalled";
856         case VK_INCOMPLETE:                     return "a return array was too small for the result";
857         case VK_ERROR_OUT_OF_HOST_MEMORY:       return "a host memory allocation has failed";
858         case VK_ERROR_OUT_OF_DEVICE_MEMORY:     return "a device memory allocation has failed";
859         case VK_ERROR_INITIALIZATION_FAILED:    return "initialization of an object has failed";
860         case VK_ERROR_DEVICE_LOST:              return "the logical device has been lost";
861         case VK_ERROR_MEMORY_MAP_FAILED:        return "mapping of a memory object has failed";
862         case VK_ERROR_LAYER_NOT_PRESENT:        return "the specified layer does not exist";
863         case VK_ERROR_EXTENSION_NOT_PRESENT:    return "the specified extension does not exist";
864         case VK_ERROR_FEATURE_NOT_PRESENT:      return "the requested feature is not available on this device";
865         case VK_ERROR_INCOMPATIBLE_DRIVER:      return "a Vulkan driver could not be found";
866         case VK_ERROR_TOO_MANY_OBJECTS:         return "too many objects of the type have already been created";
867         case VK_ERROR_FORMAT_NOT_SUPPORTED:     return "the requested format is not supported on this device";
868         case VK_ERROR_SURFACE_LOST_KHR:         return "a surface is no longer available";
869         case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
870                                                        "VkSurfaceKHR object, or some other non-Vulkan surface object";
871         case VK_SUBOPTIMAL_KHR:                 return "an image became available, and the swapchain no longer "
872                                                        "matches the surface properties exactly, but can still be used to "
873                                                        "present to the surface successfully.";
874         case VK_ERROR_OUT_OF_DATE_KHR:          return "a surface has changed in such a way that it is no "
875                                                        "longer compatible with the swapchain";
876         case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
877                                                        "presentable image layout, or is incompatible in a way that prevents "
878                                                        "sharing an image";
879         case VK_ERROR_VALIDATION_FAILED_EXT:    return "API validation has detected an invalid use of the API";
880         case VK_ERROR_INVALID_SHADER_NV:        return "one or more shaders failed to compile or link";
881         default:                                return "an error has occurred";
882     };
883     // clang-format on
884 }
885 
886 /**
887  * Validate return code.
888  *
889  * Print a message describing the reason for failure when an error code is returned.
890  *
891  * @param report_data debug_report_data object for routing validation messages.
892  * @param apiName Name of API call being validated.
893  * @param ignore vector of VkResult return codes to be ignored
894  * @param value VkResult value to validate.
895  */
validate_result(debug_report_data * report_data,const char * apiName,std::vector<VkResult> const & ignore,VkResult result)896 static void validate_result(debug_report_data *report_data, const char *apiName, std::vector<VkResult> const &ignore,
897                             VkResult result) {
898     if (result < 0 && result != VK_ERROR_VALIDATION_FAILED_EXT) {
899         if (std::find(ignore.begin(), ignore.end(), result) != ignore.end()) {
900             return;
901         }
902         std::string resultName = string_VkResult(result);
903         if (resultName == UnsupportedResultString) {
904             // Unrecognized result code
905             log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
906                     FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
907         } else {
908             std::string resultDesc = get_result_description(result);
909             log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
910                     FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
911                     resultDesc.c_str());
912         }
913     }
914 }
915 
916 }  // namespace parameter_validation
917 
918 #endif  // PARAMETER_VALIDATION_UTILS_H
919