blob: 6660ab3d4ee30ded3a01ea95a7a0eae462797336 [file] [log] [blame]
Dustin Graves1e92cd72016-02-09 14:00:18 -07001/* 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 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -06006 * 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
Dustin Graves1e92cd72016-02-09 14:00:18 -07009 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060010 * http://www.apache.org/licenses/LICENSE-2.0
Dustin Graves1e92cd72016-02-09 14:00:18 -070011 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060012 * 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.
Dustin Graves1e92cd72016-02-09 14:00:18 -070017 *
18 * Author: Dustin Graves <dustin@lunarg.com>
19 */
20
Mark Lobodzinski739391a2016-03-17 15:08:18 -060021#ifndef PARAMETER_VALIDATION_UTILS_H
22#define PARAMETER_VALIDATION_UTILS_H
Dustin Graves1e92cd72016-02-09 14:00:18 -070023
Dustin Graves58c2f662016-03-08 17:48:20 -070024#include <algorithm>
Dustin Graves29148ff2016-03-23 19:44:00 -060025#include <cstdlib>
Dustin Graves58c2f662016-03-08 17:48:20 -070026#include <string>
27
Dustin Graves1e92cd72016-02-09 14:00:18 -070028#include "vulkan/vulkan.h"
Dustin Graves58c2f662016-03-08 17:48:20 -070029#include "vk_enum_string_helper.h"
Dustin Graves1e92cd72016-02-09 14:00:18 -070030#include "vk_layer_logging.h"
31
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060032namespace parameter_validation {
33
Dustin Gravesf233e502016-05-05 13:44:21 -060034enum ErrorCode {
35 NONE, // Used for INFO & other non-error messages
36 INVALID_USAGE, // The value of a parameter is not consistent
37 // with the valid usage criteria defined in
38 // the Vulkan specification.
39 INVALID_STRUCT_STYPE, // The sType field of a Vulkan structure does
40 // not contain the value expected for a structure
41 // of that type.
42 INVALID_STRUCT_PNEXT, // The pNext field of a Vulkan structure references
43 // a value that is not compatible with a structure of
44 // that type or is not NULL when a structure of that
45 // type has no compatible pNext values.
46 REQUIRED_PARAMETER, // A required parameter was specified as 0 or NULL.
47 RESERVED_PARAMETER, // A parameter reserved for future use was not
48 // specified as 0 or NULL.
49 UNRECOGNIZED_VALUE, // A Vulkan enumeration, VkFlags, or VkBool32 parameter
50 // contains a value that is not recognized as valid for
51 // that type.
52 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
53 // was encountered.
54};
55
Dustin Graves58c2f662016-03-08 17:48:20 -070056struct GenericHeader {
57 VkStructureType sType;
58 const void *pNext;
59};
Dustin Graves58c2f662016-03-08 17:48:20 -070060
Dustin Graves29148ff2016-03-23 19:44:00 -060061// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060062const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -060063
64// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -070065const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
66
Dustin Gravesca7aa7c2016-03-25 15:13:28 -060067// String returned by string_VkResult for an unrecognized type.
68const std::string UnsupportedResultString = "Unhandled VkResult";
69
Dustin Graves29148ff2016-03-23 19:44:00 -060070// The base value used when computing the offset for an enumeration token value that is added by an extension.
71// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
72// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
73const uint32_t ExtEnumBaseValue = 1000000000;
74
75template <typename T> bool is_extension_added_token(T value) {
76 return (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
77}
78
79// VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE token is a special case that was converted from a core token to an
80// extension added token. Its original value was intentionally preserved after the conversion, so it does not use
81// the base value that other extension added tokens use, and it does not fall within the enum's begin/end range.
82template <> bool is_extension_added_token(VkSamplerAddressMode value) {
83 bool result = (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
84 return (result || (value == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE));
85}
86
Dustin Graves1e92cd72016-02-09 14:00:18 -070087/**
88 * Validate a required pointer.
89 *
Dustin Graves58c2f662016-03-08 17:48:20 -070090 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -070091 *
92 * @param report_data debug_report_data object for routing validation messages.
93 * @param apiName Name of API call being validated.
94 * @param parameterName Name of parameter being validated.
95 * @param value Pointer to validate.
96 * @return Boolean value indicating that the call should be skipped.
97 */
Dustin Graves080069b2016-04-05 13:48:15 -060098static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const char *parameterName,
99 const void *value) {
100 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700101
102 if (value == NULL) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600103 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
104 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700105 }
106
107 return skipCall;
108}
109
110/**
111 * Validate array count and pointer to array.
112 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700113 * Verify that required count and array parameters are not 0 or NULL. If the
114 * count parameter is not optional, verify that it is not 0. If the array
115 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700116 *
117 * @param report_data debug_report_data object for routing validation messages.
118 * @param apiName Name of API call being validated.
119 * @param countName Name of count parameter.
120 * @param arrayName Name of array parameter.
121 * @param count Number of elements in the array.
122 * @param array Array to validate.
123 * @param countRequired The 'count' parameter may not be 0 when true.
124 * @param arrayRequired The 'array' parameter may not be NULL when true.
125 * @return Boolean value indicating that the call should be skipped.
126 */
127template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600128bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName, T count,
129 const void *array, bool countRequired, bool arrayRequired) {
130 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700131
132 // Count parameters not tagged as optional cannot be 0
Dustin Graves080069b2016-04-05 13:48:15 -0600133 if ((count == 0) && countRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600134 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
135 REQUIRED_PARAMETER, LayerName, "%s: parameter %s must be greater than 0", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700136 }
137
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600138 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600139 if ((array == NULL) && arrayRequired && (count != 0)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600140 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
141 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, arrayName);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600142 }
143
144 return skipCall;
145}
146
147/**
148* Validate pointer to array count and pointer to array.
149*
150* Verify that required count and array parameters are not NULL. If count
151* is not NULL and its value is not optional, verify that it is not 0. If the
152* array parameter is NULL, and it is not optional, verify that count is 0.
153* The array parameter will typically be optional for this case (where count is
154* a pointer), allowing the caller to retrieve the available count.
155*
156* @param report_data debug_report_data object for routing validation messages.
157* @param apiName Name of API call being validated.
158* @param countName Name of count parameter.
159* @param arrayName Name of array parameter.
160* @param count Pointer to the number of elements in the array.
161* @param array Array to validate.
162* @param countPtrRequired The 'count' parameter may not be NULL when true.
163* @param countValueRequired The '*count' value may not be 0 when true.
164* @param arrayRequired The 'array' parameter may not be NULL when true.
165* @return Boolean value indicating that the call should be skipped.
166*/
167template <typename T>
168bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
169 const T *count, const void *array, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
170 bool skipCall = false;
171
172 if (count == NULL) {
173 if (countPtrRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600174 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
175 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600176 }
177 }
178 else {
179 skipCall |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700180 }
181
182 return skipCall;
183}
184
185/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600186 * Validate a pointer to a Vulkan structure.
187 *
188 * Verify that a required pointer to a structure is not NULL. If the pointer is
189 * not NULL, verify that each structure's sType field is set to the correct
190 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700191 *
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 struct parameter being validated.
195 * @param sTypeName Name of expected VkStructureType value.
196 * @param value Pointer to the struct to validate.
197 * @param sType VkStructureType for structure validation.
198 * @param required The parameter may not be NULL when true.
199 * @return Boolean value indicating that the call should be skipped.
200 */
201template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600202bool validate_struct_type(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *sTypeName,
203 const T *value, VkStructureType sType, bool required) {
204 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700205
206 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600207 if (required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600208 skipCall |=
209 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
210 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700211 }
212 } else if (value->sType != sType) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600213 skipCall |=
214 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
215 INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700216 }
217
218 return skipCall;
219}
220
221/**
222 * Validate an array of Vulkan structures.
223 *
224 * Verify that required count and array parameters are not NULL. If count
225 * is not NULL and its value is not optional, verify that it is not 0.
226 * If the array contains 1 or more structures, verify that each structure's
227 * sType field is set to the correct VkStructureType value.
228 *
229 * @param report_data debug_report_data object for routing validation messages.
230 * @param apiName Name of API call being validated.
231 * @param countName Name of count parameter.
232 * @param arrayName Name of array parameter.
233 * @param sTypeName Name of expected VkStructureType value.
234 * @param count Pointer to the number of elements in the array.
235 * @param array Array to validate.
236 * @param sType VkStructureType for structure validation.
237 * @param countPtrRequired The 'count' parameter may not be NULL when true.
238 * @param countValueRequired The '*count' value may not be 0 when true.
239 * @param arrayRequired The 'array' parameter may not be NULL when true.
240 * @return Boolean value indicating that the call should be skipped.
241 */
242template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600243bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
244 const char *sTypeName, const uint32_t *count, const T *array, VkStructureType sType,
245 bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
246 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700247
248 if (count == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600249 if (countPtrRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600250 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
251 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700252 }
253 } else {
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700254 skipCall |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
255 countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700256 }
257
258 return skipCall;
259}
260
261/**
262 * Validate an array of Vulkan structures
263 *
264 * Verify that required count and array parameters are not 0 or NULL. If
265 * the array contains 1 or more structures, verify that each structure's
266 * sType field is set to the correct VkStructureType value.
267 *
268 * @param report_data debug_report_data object for routing validation messages.
269 * @param apiName Name of API call being validated.
270 * @param countName Name of count parameter.
271 * @param arrayName Name of array parameter.
272 * @param sTypeName Name of expected VkStructureType value.
273 * @param count Number of elements in the array.
274 * @param array Array to validate.
275 * @param sType VkStructureType for structure validation.
276 * @param countRequired The 'count' parameter may not be 0 when true.
277 * @param arrayRequired The 'array' parameter may not be NULL when true.
278 * @return Boolean value indicating that the call should be skipped.
279 */
280template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600281bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
282 const char *sTypeName, uint32_t count, const T *array, VkStructureType sType, bool countRequired,
283 bool arrayRequired) {
284 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700285
286 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600287 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700288 } else {
289 // Verify that all structs in the array have the correct type
290 for (uint32_t i = 0; i < count; ++i) {
291 if (array[i].sType != sType) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600292 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
293 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
294 arrayName, i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700295 }
296 }
297 }
298
299 return skipCall;
300}
301
Dustin Graves58d114b2016-03-08 14:42:59 -0700302/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600303* Validate a Vulkan handle.
304*
305* Verify that the specified handle is not VK_NULL_HANDLE.
306*
307* @param report_data debug_report_data object for routing validation messages.
308* @param api_name Name of API call being validated.
309* @param parameter_name Name of struct parameter being validated.
310* @param value Handle to validate.
311* @return Boolean value indicating that the call should be skipped.
312*/
313template <typename T>
314bool validate_required_handle(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value) {
315 bool skip_call = false;
316
317 if (value == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600318 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
319 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
320 parameter_name);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600321 }
322
323 return skip_call;
324}
325
326/**
327* Validate an array of Vulkan handles.
328*
329* Verify that required count and array parameters are not NULL. If count
330* is not NULL and its value is not optional, verify that it is not 0.
331* If the array contains 1 or more handles, verify that no handle is set to
332* VK_NULL_HANDLE.
333*
334* @note This function is only intended to validate arrays of handles when none
335* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
336* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
337*
338* @param report_data debug_report_data object for routing validation messages.
339* @param api_name Name of API call being validated.
340* @param count_name Name of count parameter.
341* @param array_name Name of array parameter.
342* @param count Number of elements in the array.
343* @param array Array to validate.
344* @param count_required The 'count' parameter may not be 0 when true.
345* @param array_required The 'array' parameter may not be NULL when true.
346* @return Boolean value indicating that the call should be skipped.
347*/
348template <typename T>
349bool validate_handle_array(debug_report_data *report_data, const char *api_name, const char *count_name, const char *array_name,
350 uint32_t count, const T *array, bool count_required, bool array_required) {
351 bool skip_call = false;
352
353 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600354 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600355 } else {
356 // Verify that no handles in the array are VK_NULL_HANDLE
357 for (uint32_t i = 0; i < count; ++i) {
358 if (array[i] == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600359 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
360 __LINE__, REQUIRED_PARAMETER, LayerName,
361 "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name, array_name, i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600362 }
363 }
364 }
365
366 return skip_call;
367}
368
369/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700370 * Validate string array count and content.
371 *
372 * Verify that required count and array parameters are not 0 or NULL. If the
373 * count parameter is not optional, verify that it is not 0. If the array
374 * parameter is NULL, and it is not optional, verify that count is 0. If the
375 * array parameter is not NULL, verify that none of the strings are NULL.
376 *
377 * @param report_data debug_report_data object for routing validation messages.
378 * @param apiName Name of API call being validated.
379 * @param countName Name of count parameter.
380 * @param arrayName Name of array parameter.
381 * @param count Number of strings in the array.
382 * @param array Array of strings to validate.
383 * @param countRequired The 'count' parameter may not be 0 when true.
384 * @param arrayRequired The 'array' parameter may not be NULL when true.
385 * @return Boolean value indicating that the call should be skipped.
386 */
Dustin Graves080069b2016-04-05 13:48:15 -0600387static bool validate_string_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
388 uint32_t count, const char *const *array, bool countRequired, bool arrayRequired) {
389 bool skipCall = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700390
391 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600392 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves58d114b2016-03-08 14:42:59 -0700393 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600394 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700395 for (uint32_t i = 0; i < count; ++i) {
396 if (array[i] == NULL) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600397 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
398 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
399 apiName, arrayName, i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700400 }
401 }
402 }
403
404 return skipCall;
405}
406
Dustin Graves58c2f662016-03-08 17:48:20 -0700407/**
408 * Validate a structure's pNext member.
409 *
410 * Verify that the specified pNext value points to the head of a list of
411 * allowed extension structures. If no extension structures are allowed,
412 * verify that pNext is null.
413 *
414 * @param report_data debug_report_data object for routing validation messages.
415 * @param apiName Name of API call being validated.
416 * @param parameterName Name of parameter being validated.
417 * @param allowedStructNames Names of allowed structs.
418 * @param next Pointer to validate.
419 * @param allowedTypeCount total number of allowed structure types.
420 * @param allowedTypes array of strcuture types allowed for pNext.
421 * @return Boolean value indicating that the call should be skipped.
422 */
Dustin Graves080069b2016-04-05 13:48:15 -0600423static bool validate_struct_pnext(debug_report_data *report_data, const char *apiName, const char *parameterName,
424 const char *allowedStructNames, const void *next, size_t allowedTypeCount,
425 const VkStructureType *allowedTypes) {
426 bool skipCall = false;
Dustin Graves58c2f662016-03-08 17:48:20 -0700427
428 if (next != NULL) {
429 if (allowedTypeCount == 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600430 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
431 INVALID_STRUCT_PNEXT, LayerName, "%s: value of %s must be NULL", apiName, parameterName);
Dustin Graves58c2f662016-03-08 17:48:20 -0700432 } else {
433 const VkStructureType *start = allowedTypes;
434 const VkStructureType *end = allowedTypes + allowedTypeCount;
435 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
436
437 while (current != NULL) {
438 if (std::find(start, end, current->sType) == end) {
439 std::string typeName = string_VkStructureType(current->sType);
440
441 if (typeName == UnsupportedStructureTypeString) {
442 skipCall |= log_msg(
Dustin Gravesf233e502016-05-05 13:44:21 -0600443 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
444 INVALID_STRUCT_PNEXT, LayerName,
Dustin Graves58c2f662016-03-08 17:48:20 -0700445 "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed structures are [%s]",
446 apiName, parameterName, current->sType, allowedStructNames);
447 } else {
448 skipCall |= log_msg(
Dustin Gravesf233e502016-05-05 13:44:21 -0600449 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
450 INVALID_STRUCT_PNEXT, LayerName,
Dustin Graves58c2f662016-03-08 17:48:20 -0700451 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]",
452 apiName, parameterName, typeName.c_str(), allowedStructNames);
453 }
454 }
455
456 current = reinterpret_cast<const GenericHeader *>(current->pNext);
457 }
458 }
459 }
460
461 return skipCall;
462}
463
Dustin Graves29148ff2016-03-23 19:44:00 -0600464/**
465* Validate a VkBool32 value.
466*
467* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
468*
469* @param report_data debug_report_data object for routing validation messages.
470* @param apiName Name of API call being validated.
471* @param parameterName Name of parameter being validated.
472* @param value Boolean value to validate.
473* @return Boolean value indicating that the call should be skipped.
474*/
Dustin Graves080069b2016-04-05 13:48:15 -0600475static bool validate_bool32(debug_report_data *report_data, const char *apiName, const char *parameterName, VkBool32 value) {
476 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600477
478 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600479 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
480 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
481 parameterName, value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600482 }
483
484 return skipCall;
485}
486
487/**
488* Validate a Vulkan enumeration value.
489*
490* Generate a warning if an enumeration token value does not fall within the core enumeration
491* begin and end token values, and was not added to the enumeration by an extension. Extension
492* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
493* with 1,000,000,000 as the base token value.
494*
495* @note This function does not expect to process enumerations defining bitmask flag bits.
496*
497* @param report_data debug_report_data object for routing validation messages.
498* @param apiName Name of API call being validated.
499* @param parameterName Name of parameter being validated.
500* @param enumName Name of the enumeration being validated.
501* @param begin The begin range value for the enumeration.
502* @param end The end range value for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600503* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600504* @return Boolean value indicating that the call should be skipped.
505*/
506template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600507bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *enumName,
508 T begin, T end, T value) {
509 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600510
511 if (((value < begin) || (value > end)) && !is_extension_added_token(value)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600512 skipCall |=
513 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
514 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
515 "enumeration tokens and is not an extension added token",
516 apiName, parameterName, value, enumName);
Dustin Graves29148ff2016-03-23 19:44:00 -0600517 }
518
519 return skipCall;
520}
521
522/**
523* Validate an array of Vulkan enumeration value.
524*
525* Process all enumeration token values in the specified array and generate a warning if a value
526* does not fall within the core enumeration begin and end token values, and was not added to
527* the enumeration by an extension. Extension provided enumerations use the equation specified
528* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
529*
530* @note This function does not expect to process enumerations defining bitmask flag bits.
531*
532* @param report_data debug_report_data object for routing validation messages.
533* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600534* @param countName Name of count parameter.
535* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600536* @param enumName Name of the enumeration being validated.
537* @param begin The begin range value for the enumeration.
538* @param end The end range value for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600539* @param count Number of enumeration values in the array.
540* @param array Array of enumeration values to validate.
541* @param countRequired The 'count' parameter may not be 0 when true.
542* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600543* @return Boolean value indicating that the call should be skipped.
544*/
545template <typename T>
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600546static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const char *countName,
547 const char *arrayName, const char *enumName, T begin, T end, uint32_t count, const T *array,
548 bool countRequired, bool arrayRequired) {
Dustin Graves080069b2016-04-05 13:48:15 -0600549 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600550
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600551 if ((count == 0) || (array == NULL)) {
552 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
553 } else {
554 for (uint32_t i = 0; i < count; ++i) {
555 if (((array[i] < begin) || (array[i] > end)) && !is_extension_added_token(array[i])) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600556 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
557 __LINE__, UNRECOGNIZED_VALUE, LayerName,
558 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
559 "enumeration tokens and is not an extension added token",
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600560 apiName, arrayName, i, array[i], enumName);
561 }
Dustin Graves29148ff2016-03-23 19:44:00 -0600562 }
563 }
564
565 return skipCall;
566}
567
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600568/**
Dustin Graves78df8512016-04-28 17:58:59 -0600569* Verify that a reserved VkFlags value is zero.
570*
571* Verify that the specified value is zero, to check VkFlags values that are reserved for
572* future use.
573*
574* @param report_data debug_report_data object for routing validation messages.
575* @param api_name Name of API call being validated.
576* @param parameter_name Name of parameter being validated.
577* @param value Value to validate.
578* @return Boolean value indicating that the call should be skipped.
579*/
580static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
581 VkFlags value) {
582 bool skip_call = false;
583
584 if (value != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600585 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
586 RESERVED_PARAMETER, LayerName, "%s: parameter %s must be 0", api_name, parameter_name);
Dustin Graves78df8512016-04-28 17:58:59 -0600587 }
588
589 return skip_call;
590}
591
592/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600593* Validate a Vulkan bitmask value.
594*
595* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
596* for that type.
597*
598* @param report_data debug_report_data object for routing validation messages.
599* @param api_name Name of API call being validated.
600* @param parameter_name Name of parameter being validated.
601* @param flag_bits_name Name of the VkFlags type being validated.
602* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
603* @param value VkFlags value to validate.
604* @param flags_required The 'value' parameter may not be 0 when true.
605* @return Boolean value indicating that the call should be skipped.
606*/
Dustin Graves78df8512016-04-28 17:58:59 -0600607static bool validate_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
608 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600609 bool skip_call = false;
610
611 if (value == 0) {
612 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600613 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
614 REQUIRED_PARAMETER, LayerName, "%s: value of %s must not be 0", api_name, parameter_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600615 }
616 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600617 skip_call |=
618 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
619 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
620 api_name, parameter_name, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600621 }
622
623 return skip_call;
624}
625
626/**
627* Validate an array of Vulkan bitmask values.
628*
629* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
630* for that type.
631*
632* @param report_data debug_report_data object for routing validation messages.
633* @param api_name Name of API call being validated.
634* @param count_name Name of parameter being validated.
635* @param array_name Name of parameter being validated.
636* @param flag_bits_name Name of the VkFlags type being validated.
637* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
638* @param count Number of VkFlags values in the array.
639* @param array Array of VkFlags value to validate.
640* @param count_required The 'count' parameter may not be 0 when true.
641* @param array_required The 'array' parameter may not be NULL when true.
642* @return Boolean value indicating that the call should be skipped.
643*/
Dustin Graves78df8512016-04-28 17:58:59 -0600644static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const char *count_name,
645 const char *array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
646 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600647 bool skip_call = false;
648
649 if ((count == 0) || (array == NULL)) {
650 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
651 } else {
652 // Verify that all VkFlags values in the array
653 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600654 if (array[i] == 0) {
655 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
656 // elements in the array are allowed be 0
657 if (array_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600658 skip_call |=
659 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
660 REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name, array_name, i);
Dustin Graves78df8512016-04-28 17:58:59 -0600661 }
662 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600663 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
664 __LINE__, UNRECOGNIZED_VALUE, LayerName,
665 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
666 array_name, i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600667 }
668 }
669 }
670
671 return skip_call;
672}
673
674/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600675* Get VkResult code description.
676*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600677* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
678* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600679*
680* @param value VkResult code to process.
681* @return String describing the specified VkResult code.
682*/
683static std::string get_result_description(VkResult result) {
684 // clang-format off
685 switch (result) {
686 case VK_SUCCESS: return "a command completed successfully";
687 case VK_NOT_READY: return "a fence or query has not yet completed";
688 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
689 case VK_EVENT_SET: return "an event is signaled";
690 case VK_EVENT_RESET: return "an event is unsignalled";
691 case VK_INCOMPLETE: return "a return array was too small for the result";
692 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
693 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
694 case VK_ERROR_INITIALIZATION_FAILED: return "the logical device has been lost";
695 case VK_ERROR_DEVICE_LOST: return "initialization of an object has failed";
696 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
697 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
698 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
699 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
700 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
701 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
702 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
703 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
704 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
705 "VkSurfaceKHR object, or some other non-Vulkan surface object";
706 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
707 "matches the surface properties exactly, but can still be used to "
708 "present to the surface successfully.";
709 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
710 "longer compatible with the swapchain";
711 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
712 "presentable image layout, or is incompatible in a way that prevents "
713 "sharing an image";
714 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
715 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100716 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600717 };
718 // clang-format on
719}
720
721/**
722* Validate return code.
723*
724* Print a message describing the reason for failure when an error code is returned.
725*
726* @param report_data debug_report_data object for routing validation messages.
727* @param apiName Name of API call being validated.
728* @param value VkResult value to validate.
729*/
730static void validate_result(debug_report_data *report_data, const char *apiName, VkResult result) {
731 if (result < 0) {
732 std::string resultName = string_VkResult(result);
733
734 if (resultName == UnsupportedResultString) {
735 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600736 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
737 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600738 } else {
739 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600740 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
741 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
742 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600743 }
744 }
745}
746
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600747} // namespace parameter_validation
748
Mark Lobodzinski739391a2016-03-17 15:08:18 -0600749#endif // PARAMETER_VALIDATION_UTILS_H