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 ¶meter_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 ¶meter_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 ¶meterName,
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 ¶meterName,
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 ¶meter_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 ¶meter_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 ¶meterName,
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 ¶meterName,
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 ¶meter_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 ¶meter_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