blob: ffb9ec68d0fb33618409118f2bca6182104bb359 [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.
Mark Lobodzinski4dc6cb02016-06-28 11:23:08 -060052 DEVICE_LIMIT, // A specified parameter exceeds the limits returned
53 // by the physical device
54 DEVICE_FEATURE, // Use of a requested feature is not supported by
55 // the device
Dustin Gravesf233e502016-05-05 13:44:21 -060056 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
57 // was encountered.
58};
59
Dustin Graves58c2f662016-03-08 17:48:20 -070060struct GenericHeader {
61 VkStructureType sType;
62 const void *pNext;
63};
Dustin Graves58c2f662016-03-08 17:48:20 -070064
Dustin Graves29148ff2016-03-23 19:44:00 -060065// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060066const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -060067
Mark Lobodzinskiaf00fa82016-08-09 10:44:38 -060068// Enables for display-related instance extensions
69struct instance_extension_enables {
70 bool wsi_enabled;
71 bool xlib_enabled;
72 bool xcb_enabled;
73 bool wayland_enabled;
74 bool mir_enabled;
75 bool android_enabled;
76 bool win32_enabled;
77};
78
Dustin Graves29148ff2016-03-23 19:44:00 -060079// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -070080const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
81
Dustin Gravesca7aa7c2016-03-25 15:13:28 -060082// String returned by string_VkResult for an unrecognized type.
83const std::string UnsupportedResultString = "Unhandled VkResult";
84
Dustin Graves29148ff2016-03-23 19:44:00 -060085// The base value used when computing the offset for an enumeration token value that is added by an extension.
86// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
87// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
88const uint32_t ExtEnumBaseValue = 1000000000;
89
90template <typename T> bool is_extension_added_token(T value) {
91 return (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
92}
93
94// VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE token is a special case that was converted from a core token to an
95// extension added token. Its original value was intentionally preserved after the conversion, so it does not use
96// the base value that other extension added tokens use, and it does not fall within the enum's begin/end range.
97template <> bool is_extension_added_token(VkSamplerAddressMode value) {
98 bool result = (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
99 return (result || (value == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE));
100}
101
Dustin Graves1e92cd72016-02-09 14:00:18 -0700102/**
Dustin Gravesf8032f22016-05-11 18:31:44 -0600103* Validate a minimum value.
104*
105* Verify that the specified value is greater than the specified lower bound.
106*
107* @param report_data debug_report_data object for routing validation messages.
108* @param api_name Name of API call being validated.
109* @param parameter_name Name of parameter being validated.
110* @param value Value to validate.
111* @param lower_bound Lower bound value to use for validation.
112* @return Boolean value indicating that the call should be skipped.
113*/
114template <typename T>
115bool ValidateGreaterThan(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value,
116 T lower_bound) {
117 bool skip_call = false;
118
119 if (value <= lower_bound) {
120 skip_call |=
121 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
122 LayerName, "%s: parameter %s must be greater than %d", api_name, parameter_name, lower_bound);
123 }
124
125 return skip_call;
126}
127
128/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700129 * Validate a required pointer.
130 *
Dustin Graves58c2f662016-03-08 17:48:20 -0700131 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700132 *
133 * @param report_data debug_report_data object for routing validation messages.
134 * @param apiName Name of API call being validated.
135 * @param parameterName Name of parameter being validated.
136 * @param value Pointer to validate.
137 * @return Boolean value indicating that the call should be skipped.
138 */
Dustin Graves080069b2016-04-05 13:48:15 -0600139static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const char *parameterName,
140 const void *value) {
141 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700142
143 if (value == NULL) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600144 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
145 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700146 }
147
148 return skipCall;
149}
150
151/**
152 * Validate array count and pointer to array.
153 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700154 * Verify that required count and array parameters are not 0 or NULL. If the
155 * count parameter is not optional, verify that it is not 0. If the array
156 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700157 *
158 * @param report_data debug_report_data object for routing validation messages.
159 * @param apiName Name of API call being validated.
160 * @param countName Name of count parameter.
161 * @param arrayName Name of array parameter.
162 * @param count Number of elements in the array.
163 * @param array Array to validate.
164 * @param countRequired The 'count' parameter may not be 0 when true.
165 * @param arrayRequired The 'array' parameter may not be NULL when true.
166 * @return Boolean value indicating that the call should be skipped.
167 */
168template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600169bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName, T count,
170 const void *array, bool countRequired, bool arrayRequired) {
171 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700172
173 // Count parameters not tagged as optional cannot be 0
Dustin Graves080069b2016-04-05 13:48:15 -0600174 if ((count == 0) && countRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600175 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
176 REQUIRED_PARAMETER, LayerName, "%s: parameter %s must be greater than 0", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700177 }
178
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600179 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600180 if ((array == NULL) && arrayRequired && (count != 0)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600181 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
182 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, arrayName);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600183 }
184
185 return skipCall;
186}
187
188/**
189* Validate pointer to array count and pointer to array.
190*
191* Verify that required count and array parameters are not NULL. If count
192* is not NULL and its value is not optional, verify that it is not 0. If the
193* array parameter is NULL, and it is not optional, verify that count is 0.
194* The array parameter will typically be optional for this case (where count is
195* a pointer), allowing the caller to retrieve the available count.
196*
197* @param report_data debug_report_data object for routing validation messages.
198* @param apiName Name of API call being validated.
199* @param countName Name of count parameter.
200* @param arrayName Name of array parameter.
201* @param count Pointer to the number of elements in the array.
202* @param array Array to validate.
203* @param countPtrRequired The 'count' parameter may not be NULL when true.
204* @param countValueRequired The '*count' value may not be 0 when true.
205* @param arrayRequired The 'array' parameter may not be NULL when true.
206* @return Boolean value indicating that the call should be skipped.
207*/
208template <typename T>
209bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
210 const T *count, const void *array, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
211 bool skipCall = false;
212
213 if (count == NULL) {
214 if (countPtrRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600215 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
216 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600217 }
218 }
219 else {
220 skipCall |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700221 }
222
223 return skipCall;
224}
225
226/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600227 * Validate a pointer to a Vulkan structure.
228 *
229 * Verify that a required pointer to a structure is not NULL. If the pointer is
230 * not NULL, verify that each structure's sType field is set to the correct
231 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700232 *
233 * @param report_data debug_report_data object for routing validation messages.
234 * @param apiName Name of API call being validated.
235 * @param parameterName Name of struct parameter being validated.
236 * @param sTypeName Name of expected VkStructureType value.
237 * @param value Pointer to the struct to validate.
238 * @param sType VkStructureType for structure validation.
239 * @param required The 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(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *sTypeName,
244 const T *value, VkStructureType sType, bool required) {
245 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700246
247 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600248 if (required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600249 skipCall |=
250 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, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700252 }
253 } else if (value->sType != sType) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600254 skipCall |=
255 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
256 INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700257 }
258
259 return skipCall;
260}
261
262/**
263 * Validate an array of Vulkan structures.
264 *
265 * Verify that required count and array parameters are not NULL. If count
266 * is not NULL and its value is not optional, verify that it is not 0.
267 * If the array contains 1 or more structures, verify that each structure's
268 * sType field is set to the correct VkStructureType value.
269 *
270 * @param report_data debug_report_data object for routing validation messages.
271 * @param apiName Name of API call being validated.
272 * @param countName Name of count parameter.
273 * @param arrayName Name of array parameter.
274 * @param sTypeName Name of expected VkStructureType value.
275 * @param count Pointer to the number of elements in the array.
276 * @param array Array to validate.
277 * @param sType VkStructureType for structure validation.
278 * @param countPtrRequired The 'count' parameter may not be NULL when true.
279 * @param countValueRequired The '*count' value may not be 0 when true.
280 * @param arrayRequired The 'array' parameter may not be NULL when true.
281 * @return Boolean value indicating that the call should be skipped.
282 */
283template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600284bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
285 const char *sTypeName, const uint32_t *count, const T *array, VkStructureType sType,
286 bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
287 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700288
289 if (count == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600290 if (countPtrRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600291 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
292 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700293 }
294 } else {
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700295 skipCall |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
296 countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700297 }
298
299 return skipCall;
300}
301
302/**
303 * Validate an array of Vulkan structures
304 *
305 * Verify that required count and array parameters are not 0 or NULL. If
306 * the array contains 1 or more structures, verify that each structure's
307 * sType field is set to the correct VkStructureType value.
308 *
309 * @param report_data debug_report_data object for routing validation messages.
310 * @param apiName Name of API call being validated.
311 * @param countName Name of count parameter.
312 * @param arrayName Name of array parameter.
313 * @param sTypeName Name of expected VkStructureType value.
314 * @param count Number of elements in the array.
315 * @param array Array to validate.
316 * @param sType VkStructureType for structure validation.
317 * @param countRequired The 'count' parameter may not be 0 when true.
318 * @param arrayRequired The 'array' parameter may not be NULL when true.
319 * @return Boolean value indicating that the call should be skipped.
320 */
321template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600322bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
323 const char *sTypeName, uint32_t count, const T *array, VkStructureType sType, bool countRequired,
324 bool arrayRequired) {
325 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700326
327 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600328 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700329 } else {
330 // Verify that all structs in the array have the correct type
331 for (uint32_t i = 0; i < count; ++i) {
332 if (array[i].sType != sType) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600333 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
334 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
335 arrayName, i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700336 }
337 }
338 }
339
340 return skipCall;
341}
342
Dustin Graves58d114b2016-03-08 14:42:59 -0700343/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600344* Validate a Vulkan handle.
345*
346* Verify that the specified handle is not VK_NULL_HANDLE.
347*
348* @param report_data debug_report_data object for routing validation messages.
349* @param api_name Name of API call being validated.
350* @param parameter_name Name of struct parameter being validated.
351* @param value Handle to validate.
352* @return Boolean value indicating that the call should be skipped.
353*/
354template <typename T>
355bool validate_required_handle(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value) {
356 bool skip_call = false;
357
358 if (value == 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, __LINE__,
360 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
361 parameter_name);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600362 }
363
364 return skip_call;
365}
366
367/**
368* Validate an array of Vulkan handles.
369*
370* Verify that required count and array parameters are not NULL. If count
371* is not NULL and its value is not optional, verify that it is not 0.
372* If the array contains 1 or more handles, verify that no handle is set to
373* VK_NULL_HANDLE.
374*
375* @note This function is only intended to validate arrays of handles when none
376* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
377* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
378*
379* @param report_data debug_report_data object for routing validation messages.
380* @param api_name Name of API call being validated.
381* @param count_name Name of count parameter.
382* @param array_name Name of array parameter.
383* @param count Number of elements in the array.
384* @param array Array to validate.
385* @param count_required The 'count' parameter may not be 0 when true.
386* @param array_required The 'array' parameter may not be NULL when true.
387* @return Boolean value indicating that the call should be skipped.
388*/
389template <typename T>
390bool validate_handle_array(debug_report_data *report_data, const char *api_name, const char *count_name, const char *array_name,
391 uint32_t count, const T *array, bool count_required, bool array_required) {
392 bool skip_call = false;
393
394 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600395 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 -0600396 } else {
397 // Verify that no handles in the array are VK_NULL_HANDLE
398 for (uint32_t i = 0; i < count; ++i) {
399 if (array[i] == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600400 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
401 __LINE__, REQUIRED_PARAMETER, LayerName,
402 "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name, array_name, i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600403 }
404 }
405 }
406
407 return skip_call;
408}
409
410/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700411 * Validate string array count and content.
412 *
413 * Verify that required count and array parameters are not 0 or NULL. If the
414 * count parameter is not optional, verify that it is not 0. If the array
415 * parameter is NULL, and it is not optional, verify that count is 0. If the
416 * array parameter is not NULL, verify that none of the strings are NULL.
417 *
418 * @param report_data debug_report_data object for routing validation messages.
419 * @param apiName Name of API call being validated.
420 * @param countName Name of count parameter.
421 * @param arrayName Name of array parameter.
422 * @param count Number of strings in the array.
423 * @param array Array of strings to validate.
424 * @param countRequired The 'count' parameter may not be 0 when true.
425 * @param arrayRequired The 'array' parameter may not be NULL when true.
426 * @return Boolean value indicating that the call should be skipped.
427 */
Dustin Graves080069b2016-04-05 13:48:15 -0600428static bool validate_string_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
429 uint32_t count, const char *const *array, bool countRequired, bool arrayRequired) {
430 bool skipCall = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700431
432 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600433 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves58d114b2016-03-08 14:42:59 -0700434 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600435 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700436 for (uint32_t i = 0; i < count; ++i) {
437 if (array[i] == NULL) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600438 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
439 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
440 apiName, arrayName, i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700441 }
442 }
443 }
444
445 return skipCall;
446}
447
Dustin Graves58c2f662016-03-08 17:48:20 -0700448/**
449 * Validate a structure's pNext member.
450 *
451 * Verify that the specified pNext value points to the head of a list of
452 * allowed extension structures. If no extension structures are allowed,
453 * verify that pNext is null.
454 *
455 * @param report_data debug_report_data object for routing validation messages.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600456 * @param api_name Name of API call being validated.
457 * @param parameter_name Name of parameter being validated.
458 * @param allowed_struct_names Names of allowed structs.
Dustin Graves58c2f662016-03-08 17:48:20 -0700459 * @param next Pointer to validate.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600460 * @param allowed_type_count Total number of allowed structure types.
461 * @param allowed_types Array of strcuture types allowed for pNext.
462 * @param header_version Version of header defining the pNext validation rules.
Dustin Graves58c2f662016-03-08 17:48:20 -0700463 * @return Boolean value indicating that the call should be skipped.
464 */
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600465static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const char *parameter_name,
466 const char *allowed_struct_names, const void *next, size_t allowed_type_count,
467 const VkStructureType *allowed_types, uint32_t header_version) {
468 bool skip_call = false;
469 const char disclaimer[] = "This warning is based on the Valid Usage documentation for version %d of the Vulkan header. It "
470 "is possible that you are using a struct from a private extension or an extension that was added "
471 "to a later version of the Vulkan header, in which case your use of %s is perfectly valid but "
472 "is not guaranteed to work correctly with validation enabled";
Dustin Graves58c2f662016-03-08 17:48:20 -0700473
474 if (next != NULL) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600475 if (allowed_type_count == 0) {
476 std::string message = "%s: value of %s must be NULL. ";
477 message += disclaimer;
478 skip_call |=
479 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
480 INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name, parameter_name, header_version, parameter_name);
Dustin Graves58c2f662016-03-08 17:48:20 -0700481 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600482 const VkStructureType *start = allowed_types;
483 const VkStructureType *end = allowed_types + allowed_type_count;
Dustin Graves58c2f662016-03-08 17:48:20 -0700484 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
485
486 while (current != NULL) {
487 if (std::find(start, end, current->sType) == end) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600488 std::string type_name = string_VkStructureType(current->sType);
Dustin Graves58c2f662016-03-08 17:48:20 -0700489
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600490 if (type_name == UnsupportedStructureTypeString) {
491 std::string message = "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed "
492 "structures are [%s]. ";
493 message += disclaimer;
494 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
495 0, __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
496 parameter_name, current->sType, allowed_struct_names, header_version, parameter_name);
Dustin Graves58c2f662016-03-08 17:48:20 -0700497 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600498 std::string message =
499 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]. ";
500 message += disclaimer;
501 skip_call |=
502 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
503 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name, parameter_name,
504 type_name.c_str(), allowed_struct_names, header_version, parameter_name);
Dustin Graves58c2f662016-03-08 17:48:20 -0700505 }
506 }
507
508 current = reinterpret_cast<const GenericHeader *>(current->pNext);
509 }
510 }
511 }
512
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600513 return skip_call;
Dustin Graves58c2f662016-03-08 17:48:20 -0700514}
515
Dustin Graves29148ff2016-03-23 19:44:00 -0600516/**
517* Validate a VkBool32 value.
518*
519* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
520*
521* @param report_data debug_report_data object for routing validation messages.
522* @param apiName Name of API call being validated.
523* @param parameterName Name of parameter being validated.
524* @param value Boolean value to validate.
525* @return Boolean value indicating that the call should be skipped.
526*/
Dustin Graves080069b2016-04-05 13:48:15 -0600527static bool validate_bool32(debug_report_data *report_data, const char *apiName, const char *parameterName, VkBool32 value) {
528 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600529
530 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600531 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
532 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
533 parameterName, value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600534 }
535
536 return skipCall;
537}
538
539/**
540* Validate a Vulkan enumeration value.
541*
542* Generate a warning if an enumeration token value does not fall within the core enumeration
543* begin and end token values, and was not added to the enumeration by an extension. Extension
544* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
545* with 1,000,000,000 as the base token value.
546*
547* @note This function does not expect to process enumerations defining bitmask flag bits.
548*
549* @param report_data debug_report_data object for routing validation messages.
550* @param apiName Name of API call being validated.
551* @param parameterName Name of parameter being validated.
552* @param enumName Name of the enumeration being validated.
553* @param begin The begin range value for the enumeration.
554* @param end The end range value for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600555* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600556* @return Boolean value indicating that the call should be skipped.
557*/
558template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600559bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *enumName,
560 T begin, T end, T value) {
561 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600562
563 if (((value < begin) || (value > end)) && !is_extension_added_token(value)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600564 skipCall |=
565 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
566 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
567 "enumeration tokens and is not an extension added token",
568 apiName, parameterName, value, enumName);
Dustin Graves29148ff2016-03-23 19:44:00 -0600569 }
570
571 return skipCall;
572}
573
574/**
575* Validate an array of Vulkan enumeration value.
576*
577* Process all enumeration token values in the specified array and generate a warning if a value
578* does not fall within the core enumeration begin and end token values, and was not added to
579* the enumeration by an extension. Extension provided enumerations use the equation specified
580* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
581*
582* @note This function does not expect to process enumerations defining bitmask flag bits.
583*
584* @param report_data debug_report_data object for routing validation messages.
585* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600586* @param countName Name of count parameter.
587* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600588* @param enumName Name of the enumeration being validated.
589* @param begin The begin range value for the enumeration.
590* @param end The end range value for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600591* @param count Number of enumeration values in the array.
592* @param array Array of enumeration values to validate.
593* @param countRequired The 'count' parameter may not be 0 when true.
594* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600595* @return Boolean value indicating that the call should be skipped.
596*/
597template <typename T>
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600598static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const char *countName,
599 const char *arrayName, const char *enumName, T begin, T end, uint32_t count, const T *array,
600 bool countRequired, bool arrayRequired) {
Dustin Graves080069b2016-04-05 13:48:15 -0600601 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600602
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600603 if ((count == 0) || (array == NULL)) {
604 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
605 } else {
606 for (uint32_t i = 0; i < count; ++i) {
607 if (((array[i] < begin) || (array[i] > end)) && !is_extension_added_token(array[i])) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600608 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
609 __LINE__, UNRECOGNIZED_VALUE, LayerName,
610 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
611 "enumeration tokens and is not an extension added token",
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600612 apiName, arrayName, i, array[i], enumName);
613 }
Dustin Graves29148ff2016-03-23 19:44:00 -0600614 }
615 }
616
617 return skipCall;
618}
619
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600620/**
Dustin Graves78df8512016-04-28 17:58:59 -0600621* Verify that a reserved VkFlags value is zero.
622*
623* Verify that the specified value is zero, to check VkFlags values that are reserved for
624* future use.
625*
626* @param report_data debug_report_data object for routing validation messages.
627* @param api_name Name of API call being validated.
628* @param parameter_name Name of parameter being validated.
629* @param value Value to validate.
630* @return Boolean value indicating that the call should be skipped.
631*/
632static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
633 VkFlags value) {
634 bool skip_call = false;
635
636 if (value != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600637 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
638 RESERVED_PARAMETER, LayerName, "%s: parameter %s must be 0", api_name, parameter_name);
Dustin Graves78df8512016-04-28 17:58:59 -0600639 }
640
641 return skip_call;
642}
643
644/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600645* Validate a Vulkan bitmask value.
646*
647* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
648* for that type.
649*
650* @param report_data debug_report_data object for routing validation messages.
651* @param api_name Name of API call being validated.
652* @param parameter_name Name of parameter being validated.
653* @param flag_bits_name Name of the VkFlags type being validated.
654* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
655* @param value VkFlags value to validate.
656* @param flags_required The 'value' parameter may not be 0 when true.
657* @return Boolean value indicating that the call should be skipped.
658*/
Dustin Graves78df8512016-04-28 17:58:59 -0600659static bool validate_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
660 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600661 bool skip_call = false;
662
663 if (value == 0) {
664 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600665 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
666 REQUIRED_PARAMETER, LayerName, "%s: value of %s must not be 0", api_name, parameter_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600667 }
668 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600669 skip_call |=
670 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
671 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
672 api_name, parameter_name, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600673 }
674
675 return skip_call;
676}
677
678/**
679* Validate an array of Vulkan bitmask values.
680*
681* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
682* for that type.
683*
684* @param report_data debug_report_data object for routing validation messages.
685* @param api_name Name of API call being validated.
686* @param count_name Name of parameter being validated.
687* @param array_name Name of parameter being validated.
688* @param flag_bits_name Name of the VkFlags type being validated.
689* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
690* @param count Number of VkFlags values in the array.
691* @param array Array of VkFlags value to validate.
692* @param count_required The 'count' parameter may not be 0 when true.
693* @param array_required The 'array' parameter may not be NULL when true.
694* @return Boolean value indicating that the call should be skipped.
695*/
Dustin Graves78df8512016-04-28 17:58:59 -0600696static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const char *count_name,
697 const char *array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
698 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600699 bool skip_call = false;
700
701 if ((count == 0) || (array == NULL)) {
702 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
703 } else {
704 // Verify that all VkFlags values in the array
705 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600706 if (array[i] == 0) {
707 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
708 // elements in the array are allowed be 0
709 if (array_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600710 skip_call |=
711 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
712 REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name, array_name, i);
Dustin Graves78df8512016-04-28 17:58:59 -0600713 }
714 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600715 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
716 __LINE__, UNRECOGNIZED_VALUE, LayerName,
717 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
718 array_name, i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600719 }
720 }
721 }
722
723 return skip_call;
724}
725
726/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600727* Get VkResult code description.
728*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600729* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
730* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600731*
732* @param value VkResult code to process.
733* @return String describing the specified VkResult code.
734*/
735static std::string get_result_description(VkResult result) {
736 // clang-format off
737 switch (result) {
738 case VK_SUCCESS: return "a command completed successfully";
739 case VK_NOT_READY: return "a fence or query has not yet completed";
740 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
741 case VK_EVENT_SET: return "an event is signaled";
742 case VK_EVENT_RESET: return "an event is unsignalled";
743 case VK_INCOMPLETE: return "a return array was too small for the result";
744 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
745 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
Dustin Graves2adca842016-05-16 18:35:55 -0600746 case VK_ERROR_INITIALIZATION_FAILED: return "initialization of an object has failed";
747 case VK_ERROR_DEVICE_LOST: return "the logical device has been lost";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600748 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
749 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
750 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
751 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
752 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
753 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
754 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
755 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
756 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
757 "VkSurfaceKHR object, or some other non-Vulkan surface object";
758 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
759 "matches the surface properties exactly, but can still be used to "
760 "present to the surface successfully.";
761 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
762 "longer compatible with the swapchain";
763 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
764 "presentable image layout, or is incompatible in a way that prevents "
765 "sharing an image";
766 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
767 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100768 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600769 };
770 // clang-format on
771}
772
773/**
774* Validate return code.
775*
776* Print a message describing the reason for failure when an error code is returned.
777*
778* @param report_data debug_report_data object for routing validation messages.
779* @param apiName Name of API call being validated.
780* @param value VkResult value to validate.
781*/
782static void validate_result(debug_report_data *report_data, const char *apiName, VkResult result) {
783 if (result < 0) {
784 std::string resultName = string_VkResult(result);
785
786 if (resultName == UnsupportedResultString) {
787 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600788 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
789 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600790 } else {
791 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600792 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
793 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
794 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600795 }
796 }
797}
798
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600799} // namespace parameter_validation
800
Mark Lobodzinski739391a2016-03-17 15:08:18 -0600801#endif // PARAMETER_VALIDATION_UTILS_H