blob: 791a7a1adcaee527911e69f8b4886902ac7825d3 [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>
Mike Schuchardt47619c82017-05-31 09:14:22 -060027#include <bitset>
Dustin Graves58c2f662016-03-08 17:48:20 -070028
Dustin Graves1e92cd72016-02-09 14:00:18 -070029#include "vulkan/vulkan.h"
Dustin Graves58c2f662016-03-08 17:48:20 -070030#include "vk_enum_string_helper.h"
Dustin Graves1e92cd72016-02-09 14:00:18 -070031#include "vk_layer_logging.h"
Karl Schultza9ef1e52016-10-06 17:53:48 -060032#include "vk_validation_error_messages.h"
Dustin Graves1e92cd72016-02-09 14:00:18 -070033
Dustin Graves8ffbbf62016-07-22 13:19:46 -060034#include "parameter_name.h"
35
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060036namespace parameter_validation {
37
Dustin Gravesf233e502016-05-05 13:44:21 -060038enum ErrorCode {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070039 NONE, // Used for INFO & other non-error messages
40 INVALID_USAGE, // The value of a parameter is not consistent
41 // with the valid usage criteria defined in
42 // the Vulkan specification.
43 INVALID_STRUCT_STYPE, // The sType field of a Vulkan structure does
44 // not contain the value expected for a structure
45 // of that type.
46 INVALID_STRUCT_PNEXT, // The pNext field of a Vulkan structure references
47 // a value that is not compatible with a structure of
48 // that type or is not NULL when a structure of that
49 // type has no compatible pNext values.
50 REQUIRED_PARAMETER, // A required parameter was specified as 0 or NULL.
51 RESERVED_PARAMETER, // A parameter reserved for future use was not
52 // specified as 0 or NULL.
53 UNRECOGNIZED_VALUE, // A Vulkan enumeration, VkFlags, or VkBool32 parameter
54 // contains a value that is not recognized as valid for
55 // that type.
56 DEVICE_LIMIT, // A specified parameter exceeds the limits returned
57 // by the physical device
58 DEVICE_FEATURE, // Use of a requested feature is not supported by
59 // the device
60 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
61 // was encountered.
62 EXTENSION_NOT_ENABLED, // An extension entrypoint was called, but the required
63 // extension was not enabled at CreateInstance or
64 // CreateDevice time.
Dustin Gravesf233e502016-05-05 13:44:21 -060065};
66
Dustin Graves58c2f662016-03-08 17:48:20 -070067struct GenericHeader {
68 VkStructureType sType;
69 const void *pNext;
70};
Dustin Graves58c2f662016-03-08 17:48:20 -070071
Dustin Graves29148ff2016-03-23 19:44:00 -060072// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060073const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -060074
75// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -070076const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
77
Dustin Gravesca7aa7c2016-03-25 15:13:28 -060078// String returned by string_VkResult for an unrecognized type.
79const std::string UnsupportedResultString = "Unhandled VkResult";
80
Dustin Graves29148ff2016-03-23 19:44:00 -060081// The base value used when computing the offset for an enumeration token value that is added by an extension.
82// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
83// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
84const uint32_t ExtEnumBaseValue = 1000000000;
85
Cort Strattonedbe9b82017-05-16 07:38:35 -070086// The value of all VK_xxx_MAX_ENUM tokens
87const uint32_t MaxEnumValue = 0x7FFFFFFF;
88
Mark Lobodzinski26112592017-05-30 12:02:17 -060089// Forward declaration
90bool ValidateRequiredExtensions(std::string api_name, const std::vector<std::string> required_extensions);
91
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070092template <typename T>
93bool is_extension_added_token(T value) {
Cort Strattonedbe9b82017-05-16 07:38:35 -070094 return (value != MaxEnumValue) && (static_cast<uint32_t>(std::abs(static_cast<int32_t>(value))) >= ExtEnumBaseValue);
Dustin Graves29148ff2016-03-23 19:44:00 -060095}
96
97// VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE token is a special case that was converted from a core token to an
98// extension added token. Its original value was intentionally preserved after the conversion, so it does not use
99// the base value that other extension added tokens use, and it does not fall within the enum's begin/end range.
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700100template <>
101bool is_extension_added_token(VkSamplerAddressMode value) {
Cort Strattonedbe9b82017-05-16 07:38:35 -0700102 bool result = is_extension_added_token(static_cast<uint32_t>(value));
103 return result || (value == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE);
Dustin Graves29148ff2016-03-23 19:44:00 -0600104}
105
Dustin Graves1e92cd72016-02-09 14:00:18 -0700106/**
Dustin Gravesf8032f22016-05-11 18:31:44 -0600107* Validate a minimum value.
108*
109* Verify that the specified value is greater than the specified lower bound.
110*
111* @param report_data debug_report_data object for routing validation messages.
112* @param api_name Name of API call being validated.
113* @param parameter_name Name of parameter being validated.
114* @param value Value to validate.
115* @param lower_bound Lower bound value to use for validation.
116* @return Boolean value indicating that the call should be skipped.
117*/
118template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600119bool ValidateGreaterThan(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, T value,
120 T lower_bound) {
Dustin Gravesf8032f22016-05-11 18:31:44 -0600121 bool skip_call = false;
122
123 if (value <= lower_bound) {
Mark Lobodzinskieb9e73f2017-04-13 10:06:48 -0600124 skip_call |=
125 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, 1, LayerName,
126 "%s: parameter %s must be greater than %d", api_name, parameter_name.get_name().c_str(), lower_bound);
Dustin Gravesf8032f22016-05-11 18:31:44 -0600127 }
128
129 return skip_call;
130}
131
132/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700133 * Validate a required pointer.
134 *
Dustin Graves58c2f662016-03-08 17:48:20 -0700135 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700136 *
137 * @param report_data debug_report_data object for routing validation messages.
138 * @param apiName Name of API call being validated.
139 * @param parameterName Name of parameter being validated.
140 * @param value Pointer to validate.
141 * @return Boolean value indicating that the call should be skipped.
142 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600143static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Dustin Graves080069b2016-04-05 13:48:15 -0600144 const void *value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600145 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700146
147 if (value == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600148 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600149 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
150 parameterName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700151 }
152
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600153 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700154}
155
156/**
157 * Validate array count and pointer to array.
158 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700159 * Verify that required count and array parameters are not 0 or NULL. If the
160 * count parameter is not optional, verify that it is not 0. If the array
161 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700162 *
163 * @param report_data debug_report_data object for routing validation messages.
164 * @param apiName Name of API call being validated.
165 * @param countName Name of count parameter.
166 * @param arrayName Name of array parameter.
167 * @param count Number of elements in the array.
168 * @param array Array to validate.
169 * @param countRequired The 'count' parameter may not be 0 when true.
170 * @param arrayRequired The 'array' parameter may not be NULL when true.
171 * @return Boolean value indicating that the call should be skipped.
172 */
173template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600174bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
175 const ParameterName &arrayName, T count, const void *array, bool countRequired, bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600176 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700177
178 // Count parameters not tagged as optional cannot be 0
Józef Kucia20bb8fb2016-09-23 12:45:04 +0200179 if (countRequired && (count == 0)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600180 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700181 REQUIRED_PARAMETER, LayerName, "%s: parameter %s must be greater than 0", apiName,
182 countName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700183 }
184
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600185 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600186 if ((array == NULL) && arrayRequired && (count != 0)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600187 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700188 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
189 arrayName.get_name().c_str());
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600190 }
191
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600192 return skip_call;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600193}
194
195/**
196* Validate pointer to array count and pointer to array.
197*
198* Verify that required count and array parameters are not NULL. If count
199* is not NULL and its value is not optional, verify that it is not 0. If the
200* array parameter is NULL, and it is not optional, verify that count is 0.
201* The array parameter will typically be optional for this case (where count is
202* a pointer), allowing the caller to retrieve the available count.
203*
204* @param report_data debug_report_data object for routing validation messages.
205* @param apiName Name of API call being validated.
206* @param countName Name of count parameter.
207* @param arrayName Name of array parameter.
208* @param count Pointer to the number of elements in the array.
209* @param array Array to validate.
210* @param countPtrRequired The 'count' parameter may not be NULL when true.
211* @param countValueRequired The '*count' value may not be 0 when true.
212* @param arrayRequired The 'array' parameter may not be NULL when true.
213* @return Boolean value indicating that the call should be skipped.
214*/
215template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600216bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
217 const ParameterName &arrayName, const T *count, const void *array, bool countPtrRequired,
218 bool countValueRequired, bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600219 bool skip_call = false;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600220
221 if (count == NULL) {
222 if (countPtrRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600223 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600224 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
225 countName.get_name().c_str());
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600226 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700227 } else {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600228 skip_call |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700229 }
230
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600231 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700232}
233
234/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600235 * Validate a pointer to a Vulkan structure.
236 *
237 * Verify that a required pointer to a structure is not NULL. If the pointer is
238 * not NULL, verify that each structure's sType field is set to the correct
239 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700240 *
241 * @param report_data debug_report_data object for routing validation messages.
242 * @param apiName Name of API call being validated.
243 * @param parameterName Name of struct parameter being validated.
244 * @param sTypeName Name of expected VkStructureType value.
245 * @param value Pointer to the struct to validate.
246 * @param sType VkStructureType for structure validation.
247 * @param required The parameter may not be NULL when true.
248 * @return Boolean value indicating that the call should be skipped.
249 */
250template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600251bool validate_struct_type(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
252 const char *sTypeName, const T *value, VkStructureType sType, bool required) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600253 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700254
255 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600256 if (required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600257 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
258 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
259 parameterName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700260 }
261 } else if (value->sType != sType) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600262 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
263 INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s->sType must be %s", apiName,
264 parameterName.get_name().c_str(), sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700265 }
266
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600267 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700268}
269
270/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700271 * Validate an array of Vulkan structures
272 *
273 * Verify that required count and array parameters are not 0 or NULL. If
274 * the array contains 1 or more structures, verify that each structure's
275 * sType field is set to the correct VkStructureType value.
276 *
277 * @param report_data debug_report_data object for routing validation messages.
278 * @param apiName Name of API call being validated.
279 * @param countName Name of count parameter.
280 * @param arrayName Name of array parameter.
281 * @param sTypeName Name of expected VkStructureType value.
282 * @param count Number of elements in the array.
283 * @param array Array to validate.
284 * @param sType VkStructureType for structure validation.
285 * @param countRequired The 'count' parameter may not be 0 when true.
286 * @param arrayRequired The 'array' parameter may not be NULL when true.
287 * @return Boolean value indicating that the call should be skipped.
288 */
289template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600290bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
291 const ParameterName &arrayName, const char *sTypeName, uint32_t count, const T *array,
292 VkStructureType sType, bool countRequired, bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600293 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700294
295 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600296 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700297 } else {
298 // Verify that all structs in the array have the correct type
299 for (uint32_t i = 0; i < count; ++i) {
300 if (array[i].sType != sType) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600301 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600302 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
303 arrayName.get_name().c_str(), i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700304 }
305 }
306 }
307
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600308 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700309}
310
Dustin Graves58d114b2016-03-08 14:42:59 -0700311/**
Mark Young39389872017-01-19 21:10:49 -0700312 * Validate an array of Vulkan structures.
313 *
314 * Verify that required count and array parameters are not NULL. If count
315 * is not NULL and its value is not optional, verify that it is not 0.
316 * If the array contains 1 or more structures, verify that each structure's
317 * sType field is set to the correct VkStructureType value.
318 *
319 * @param report_data debug_report_data object for routing validation messages.
320 * @param apiName Name of API call being validated.
321 * @param countName Name of count parameter.
322 * @param arrayName Name of array parameter.
323 * @param sTypeName Name of expected VkStructureType value.
324 * @param count Pointer to the number of elements in the array.
325 * @param array Array to validate.
326 * @param sType VkStructureType for structure validation.
327 * @param countPtrRequired The 'count' parameter may not be NULL when true.
328 * @param countValueRequired The '*count' value may not be 0 when true.
329 * @param arrayRequired The 'array' parameter may not be NULL when true.
330 * @return Boolean value indicating that the call should be skipped.
331 */
332template <typename T>
333bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
334 const ParameterName &arrayName, const char *sTypeName, uint32_t *count, const T *array,
335 VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
336 bool skip_call = false;
337
338 if (count == NULL) {
339 if (countPtrRequired) {
340 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
341 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
342 countName.get_name().c_str());
343 }
344 } else {
345 skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
346 countValueRequired, arrayRequired);
347 }
348
349 return skip_call;
350}
351
352/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600353* Validate a Vulkan handle.
354*
355* Verify that the specified handle is not VK_NULL_HANDLE.
356*
357* @param report_data debug_report_data object for routing validation messages.
358* @param api_name Name of API call being validated.
359* @param parameter_name Name of struct parameter being validated.
360* @param value Handle to validate.
361* @return Boolean value indicating that the call should be skipped.
362*/
363template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600364bool validate_required_handle(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, T value) {
Dustin Graves20fd66f2016-04-18 18:33:21 -0600365 bool skip_call = false;
366
367 if (value == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600368 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
369 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600370 parameter_name.get_name().c_str());
Dustin Graves20fd66f2016-04-18 18:33:21 -0600371 }
372
373 return skip_call;
374}
375
376/**
377* Validate an array of Vulkan handles.
378*
379* Verify that required count and array parameters are not NULL. If count
380* is not NULL and its value is not optional, verify that it is not 0.
381* If the array contains 1 or more handles, verify that no handle is set to
382* VK_NULL_HANDLE.
383*
384* @note This function is only intended to validate arrays of handles when none
385* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
386* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
387*
388* @param report_data debug_report_data object for routing validation messages.
389* @param api_name Name of API call being validated.
390* @param count_name Name of count parameter.
391* @param array_name Name of array parameter.
392* @param count Number of elements in the array.
393* @param array Array to validate.
394* @param count_required The 'count' parameter may not be 0 when true.
395* @param array_required The 'array' parameter may not be NULL when true.
396* @return Boolean value indicating that the call should be skipped.
397*/
398template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600399bool validate_handle_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
400 const ParameterName &array_name, uint32_t count, const T *array, bool count_required,
401 bool array_required) {
Dustin Graves20fd66f2016-04-18 18:33:21 -0600402 bool skip_call = false;
403
404 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600405 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 -0600406 } else {
407 // Verify that no handles in the array are VK_NULL_HANDLE
408 for (uint32_t i = 0; i < count; ++i) {
409 if (array[i] == VK_NULL_HANDLE) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600410 skip_call |=
411 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
412 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name,
413 array_name.get_name().c_str(), i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600414 }
415 }
416 }
417
418 return skip_call;
419}
420
421/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700422 * Validate string array count and content.
423 *
424 * Verify that required count and array parameters are not 0 or NULL. If the
425 * count parameter is not optional, verify that it is not 0. If the array
426 * parameter is NULL, and it is not optional, verify that count is 0. If the
427 * array parameter is not NULL, verify that none of the strings are NULL.
428 *
429 * @param report_data debug_report_data object for routing validation messages.
430 * @param apiName Name of API call being validated.
431 * @param countName Name of count parameter.
432 * @param arrayName Name of array parameter.
433 * @param count Number of strings in the array.
434 * @param array Array of strings to validate.
435 * @param countRequired The 'count' parameter may not be 0 when true.
436 * @param arrayRequired The 'array' parameter may not be NULL when true.
437 * @return Boolean value indicating that the call should be skipped.
438 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600439static bool validate_string_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
440 const ParameterName &arrayName, uint32_t count, const char *const *array, bool countRequired,
441 bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600442 bool skip_call = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700443
444 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600445 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves58d114b2016-03-08 14:42:59 -0700446 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600447 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700448 for (uint32_t i = 0; i < count; ++i) {
449 if (array[i] == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600450 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600451 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
452 apiName, arrayName.get_name().c_str(), i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700453 }
454 }
455 }
456
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600457 return skip_call;
Dustin Graves58d114b2016-03-08 14:42:59 -0700458}
459
Dustin Graves58c2f662016-03-08 17:48:20 -0700460/**
461 * Validate a structure's pNext member.
462 *
463 * Verify that the specified pNext value points to the head of a list of
464 * allowed extension structures. If no extension structures are allowed,
465 * verify that pNext is null.
466 *
467 * @param report_data debug_report_data object for routing validation messages.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600468 * @param api_name Name of API call being validated.
469 * @param parameter_name Name of parameter being validated.
470 * @param allowed_struct_names Names of allowed structs.
Dustin Graves58c2f662016-03-08 17:48:20 -0700471 * @param next Pointer to validate.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600472 * @param allowed_type_count Total number of allowed structure types.
473 * @param allowed_types Array of strcuture types allowed for pNext.
474 * @param header_version Version of header defining the pNext validation rules.
Dustin Graves58c2f662016-03-08 17:48:20 -0700475 * @return Boolean value indicating that the call should be skipped.
476 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600477static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600478 const char *allowed_struct_names, const void *next, size_t allowed_type_count,
479 const VkStructureType *allowed_types, uint32_t header_version) {
480 bool skip_call = false;
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600481 std::unordered_set<const void *> cycle_check;
482 std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
483
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700484 const char disclaimer[] =
485 "This warning is based on the Valid Usage documentation for version %d of the Vulkan header. It "
486 "is possible that you are using a struct from a private extension or an extension that was added "
487 "to a later version of the Vulkan header, in which case your use of %s is perfectly valid but "
488 "is not guaranteed to work correctly with validation enabled";
Dustin Graves58c2f662016-03-08 17:48:20 -0700489
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600490 // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
491 // Codegen a map of vectors containing the allowable pNext types for each struct and use that here -- also simplifies parms.
Dustin Graves58c2f662016-03-08 17:48:20 -0700492 if (next != NULL) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600493 if (allowed_type_count == 0) {
494 std::string message = "%s: value of %s must be NULL. ";
495 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600496 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
497 INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name, parameter_name.get_name().c_str(),
498 header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700499 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600500 const VkStructureType *start = allowed_types;
501 const VkStructureType *end = allowed_types + allowed_type_count;
Dustin Graves58c2f662016-03-08 17:48:20 -0700502 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
503
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600504 cycle_check.insert(next);
Dustin Graves58c2f662016-03-08 17:48:20 -0700505
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600506
507 while (current != NULL) {
508 if (cycle_check.find(current->pNext) != cycle_check.end()) {
509 std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
510 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
511 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
512 parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next));
513 break;
514 } else {
515 cycle_check.insert(current->pNext);
516 }
517
518 std::string type_name = string_VkStructureType(current->sType);
519 if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
520 std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
521 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
522 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
523 parameter_name.get_name().c_str(), type_name.c_str());
524 } else {
525 unique_stype_check.insert(current->sType);
526 }
527
528 if (std::find(start, end, current->sType) == end) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600529 if (type_name == UnsupportedStructureTypeString) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700530 std::string message =
531 "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed "
532 "structures are [%s]. ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600533 message += disclaimer;
534 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
535 0, __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600536 parameter_name.get_name().c_str(), current->sType, allowed_struct_names,
537 header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700538 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600539 std::string message =
540 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]. ";
541 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600542 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
543 0, __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
544 parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names,
545 header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700546 }
547 }
Dustin Graves58c2f662016-03-08 17:48:20 -0700548 current = reinterpret_cast<const GenericHeader *>(current->pNext);
549 }
550 }
551 }
552
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600553 return skip_call;
Dustin Graves58c2f662016-03-08 17:48:20 -0700554}
555
Dustin Graves29148ff2016-03-23 19:44:00 -0600556/**
557* Validate a VkBool32 value.
558*
559* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
560*
561* @param report_data debug_report_data object for routing validation messages.
562* @param apiName Name of API call being validated.
563* @param parameterName Name of parameter being validated.
564* @param value Boolean value to validate.
565* @return Boolean value indicating that the call should be skipped.
566*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600567static bool validate_bool32(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
568 VkBool32 value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600569 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600570
571 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600572 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600573 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
574 parameterName.get_name().c_str(), value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600575 }
576
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600577 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600578}
579
580/**
581* Validate a Vulkan enumeration value.
582*
583* Generate a warning if an enumeration token value does not fall within the core enumeration
584* begin and end token values, and was not added to the enumeration by an extension. Extension
585* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
586* with 1,000,000,000 as the base token value.
587*
588* @note This function does not expect to process enumerations defining bitmask flag bits.
589*
590* @param report_data debug_report_data object for routing validation messages.
591* @param apiName Name of API call being validated.
592* @param parameterName Name of parameter being validated.
593* @param enumName Name of the enumeration being validated.
594* @param begin The begin range value for the enumeration.
595* @param end The end range value for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600596* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600597* @return Boolean value indicating that the call should be skipped.
598*/
599template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600600bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
601 const char *enumName, T begin, T end, T value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600602 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600603
604 if (((value < begin) || (value > end)) && !is_extension_added_token(value)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700605 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
606 UNRECOGNIZED_VALUE, LayerName,
607 "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
608 "enumeration tokens and is not an extension added token",
609 apiName, parameterName.get_name().c_str(), value, enumName);
Dustin Graves29148ff2016-03-23 19:44:00 -0600610 }
611
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600612 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600613}
614
615/**
616* Validate an array of Vulkan enumeration value.
617*
618* Process all enumeration token values in the specified array and generate a warning if a value
619* does not fall within the core enumeration begin and end token values, and was not added to
620* the enumeration by an extension. Extension provided enumerations use the equation specified
621* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
622*
623* @note This function does not expect to process enumerations defining bitmask flag bits.
624*
625* @param report_data debug_report_data object for routing validation messages.
626* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600627* @param countName Name of count parameter.
628* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600629* @param enumName Name of the enumeration being validated.
630* @param begin The begin range value for the enumeration.
631* @param end The end range value for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600632* @param count Number of enumeration values in the array.
633* @param array Array of enumeration values to validate.
634* @param countRequired The 'count' parameter may not be 0 when true.
635* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600636* @return Boolean value indicating that the call should be skipped.
637*/
638template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600639static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
640 const ParameterName &arrayName, const char *enumName, T begin, T end, uint32_t count,
641 const T *array, bool countRequired, bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600642 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600643
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600644 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600645 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600646 } else {
647 for (uint32_t i = 0; i < count; ++i) {
648 if (((array[i] < begin) || (array[i] > end)) && !is_extension_added_token(array[i])) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600649 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600650 __LINE__, UNRECOGNIZED_VALUE, LayerName,
651 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
652 "enumeration tokens and is not an extension added token",
653 apiName, arrayName.get_name().c_str(), i, array[i], enumName);
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600654 }
Dustin Graves29148ff2016-03-23 19:44:00 -0600655 }
656 }
657
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600658 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600659}
660
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600661/**
Dustin Graves78df8512016-04-28 17:58:59 -0600662* Verify that a reserved VkFlags value is zero.
663*
664* Verify that the specified value is zero, to check VkFlags values that are reserved for
665* future use.
666*
667* @param report_data debug_report_data object for routing validation messages.
668* @param api_name Name of API call being validated.
669* @param parameter_name Name of parameter being validated.
670* @param value Value to validate.
671* @return Boolean value indicating that the call should be skipped.
672*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600673static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Dustin Graves78df8512016-04-28 17:58:59 -0600674 VkFlags value) {
675 bool skip_call = false;
676
677 if (value != 0) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600678 skip_call |=
679 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
680 RESERVED_PARAMETER, LayerName, "%s: parameter %s must be 0", api_name, parameter_name.get_name().c_str());
Dustin Graves78df8512016-04-28 17:58:59 -0600681 }
682
683 return skip_call;
684}
685
686/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600687* Validate a Vulkan bitmask value.
688*
689* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
690* for that type.
691*
692* @param report_data debug_report_data object for routing validation messages.
693* @param api_name Name of API call being validated.
694* @param parameter_name Name of parameter being validated.
695* @param flag_bits_name Name of the VkFlags type being validated.
696* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
697* @param value VkFlags value to validate.
698* @param flags_required The 'value' parameter may not be 0 when true.
Mike Schuchardt47619c82017-05-31 09:14:22 -0600699* @param singleFlag The 'value' parameter may not contain more than one bit from all_flags.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600700* @return Boolean value indicating that the call should be skipped.
701*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600702static bool validate_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Mike Schuchardt47619c82017-05-31 09:14:22 -0600703 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required, bool singleFlag) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600704 bool skip_call = false;
705
706 if (value == 0) {
707 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600708 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600709 REQUIRED_PARAMETER, LayerName, "%s: value of %s must not be 0", api_name,
710 parameter_name.get_name().c_str());
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600711 }
712 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600713 skip_call |=
714 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
715 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600716 api_name, parameter_name.get_name().c_str(), flag_bits_name);
Mike Schuchardt47619c82017-05-31 09:14:22 -0600717 } else if (singleFlag && (std::bitset<sizeof(VkFlags) * 8>(value).count() > 1)) {
718 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
719 UNRECOGNIZED_VALUE, LayerName,
720 "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
721 parameter_name.get_name().c_str(), flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600722 }
723
724 return skip_call;
725}
726
727/**
728* Validate an array of Vulkan bitmask values.
729*
730* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
731* for that type.
732*
733* @param report_data debug_report_data object for routing validation messages.
734* @param api_name Name of API call being validated.
735* @param count_name Name of parameter being validated.
736* @param array_name Name of parameter being validated.
737* @param flag_bits_name Name of the VkFlags type being validated.
738* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
739* @param count Number of VkFlags values in the array.
740* @param array Array of VkFlags value to validate.
741* @param count_required The 'count' parameter may not be 0 when true.
742* @param array_required The 'array' parameter may not be NULL when true.
743* @return Boolean value indicating that the call should be skipped.
744*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600745static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
746 const ParameterName &array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
Dustin Graves78df8512016-04-28 17:58:59 -0600747 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600748 bool skip_call = false;
749
750 if ((count == 0) || (array == NULL)) {
751 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
752 } else {
753 // Verify that all VkFlags values in the array
754 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600755 if (array[i] == 0) {
756 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
757 // elements in the array are allowed be 0
758 if (array_required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600759 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
760 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name,
761 array_name.get_name().c_str(), i);
Dustin Graves78df8512016-04-28 17:58:59 -0600762 }
763 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600764 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
765 __LINE__, UNRECOGNIZED_VALUE, LayerName,
766 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600767 array_name.get_name().c_str(), i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600768 }
769 }
770 }
771
772 return skip_call;
773}
774
775/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600776* Get VkResult code description.
777*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600778* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
779* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600780*
781* @param value VkResult code to process.
782* @return String describing the specified VkResult code.
783*/
784static std::string get_result_description(VkResult result) {
785 // clang-format off
786 switch (result) {
787 case VK_SUCCESS: return "a command completed successfully";
788 case VK_NOT_READY: return "a fence or query has not yet completed";
789 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
790 case VK_EVENT_SET: return "an event is signaled";
791 case VK_EVENT_RESET: return "an event is unsignalled";
792 case VK_INCOMPLETE: return "a return array was too small for the result";
793 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
794 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
Dustin Graves2adca842016-05-16 18:35:55 -0600795 case VK_ERROR_INITIALIZATION_FAILED: return "initialization of an object has failed";
796 case VK_ERROR_DEVICE_LOST: return "the logical device has been lost";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600797 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
798 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
799 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
800 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
801 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
802 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
803 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
804 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
805 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
806 "VkSurfaceKHR object, or some other non-Vulkan surface object";
807 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
808 "matches the surface properties exactly, but can still be used to "
809 "present to the surface successfully.";
810 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
811 "longer compatible with the swapchain";
812 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
813 "presentable image layout, or is incompatible in a way that prevents "
814 "sharing an image";
815 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
816 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100817 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600818 };
819 // clang-format on
820}
821
822/**
823* Validate return code.
824*
825* Print a message describing the reason for failure when an error code is returned.
826*
827* @param report_data debug_report_data object for routing validation messages.
828* @param apiName Name of API call being validated.
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600829* @param ignore vector of VkResult return codes to be ignored
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600830* @param value VkResult value to validate.
831*/
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600832static void validate_result(debug_report_data *report_data, const char *apiName, std::vector<VkResult> const &ignore,
833 VkResult result) {
Chris Forbesf1f4e382016-10-13 14:44:03 +1300834 if (result < 0 && result != VK_ERROR_VALIDATION_FAILED_EXT) {
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600835 if (std::find(ignore.begin(), ignore.end(), result) != ignore.end()) {
836 return;
837 }
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600838 std::string resultName = string_VkResult(result);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600839 if (resultName == UnsupportedResultString) {
840 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600841 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
842 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600843 } else {
844 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600845 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
846 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
847 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600848 }
849 }
850}
851
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700852} // namespace parameter_validation
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600853
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700854#endif // PARAMETER_VALIDATION_UTILS_H