blob: 269d7a2e7f684db054061d0f8d7633079e0525df [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"
Mark Lobodzinski89cdf722017-06-01 15:09:55 -060033#include "vk_extension_helper.h"
Mark Lobodzinski944ec372017-05-30 14:21:21 -060034
Dustin Graves1e92cd72016-02-09 14:00:18 -070035
Dustin Graves8ffbbf62016-07-22 13:19:46 -060036#include "parameter_name.h"
37
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060038namespace parameter_validation {
39
Mark Lobodzinski944ec372017-05-30 14:21:21 -060040struct instance_layer_data {
41 VkInstance instance = VK_NULL_HANDLE;
42
43 debug_report_data *report_data = nullptr;
44 std::vector<VkDebugReportCallbackEXT> logging_callback;
45
46 // The following are for keeping track of the temporary callbacks that can
47 // be used in vkCreateInstance and vkDestroyInstance:
48 uint32_t num_tmp_callbacks = 0;
49 VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos = nullptr;
50 VkDebugReportCallbackEXT *tmp_callbacks = nullptr;
51 InstanceExtensions extensions = {};
52 std::unordered_set<std::string> enabled_extensions;
53 VkLayerInstanceDispatchTable dispatch_table = {};
54};
55
56struct layer_data {
57 debug_report_data *report_data = nullptr;
58 // Map for queue family index to queue count
59 std::unordered_map<uint32_t, uint32_t> queueFamilyIndexMap;
60 VkPhysicalDeviceLimits device_limits = {};
61 VkPhysicalDeviceFeatures physical_device_features = {};
62 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
63 VkDevice device = VK_NULL_HANDLE;
Mark Lobodzinskib8626db2017-06-01 08:44:53 -060064 DeviceExtensions extensions;
Mark Lobodzinski944ec372017-05-30 14:21:21 -060065 std::unordered_set<std::string> enabled_extensions;
66
67 VkLayerDispatchTable dispatch_table = {};
68};
69
Dustin Gravesf233e502016-05-05 13:44:21 -060070enum ErrorCode {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070071 NONE, // Used for INFO & other non-error messages
72 INVALID_USAGE, // The value of a parameter is not consistent
73 // with the valid usage criteria defined in
74 // the Vulkan specification.
75 INVALID_STRUCT_STYPE, // The sType field of a Vulkan structure does
76 // not contain the value expected for a structure
77 // of that type.
78 INVALID_STRUCT_PNEXT, // The pNext field of a Vulkan structure references
79 // a value that is not compatible with a structure of
80 // that type or is not NULL when a structure of that
81 // type has no compatible pNext values.
82 REQUIRED_PARAMETER, // A required parameter was specified as 0 or NULL.
83 RESERVED_PARAMETER, // A parameter reserved for future use was not
84 // specified as 0 or NULL.
85 UNRECOGNIZED_VALUE, // A Vulkan enumeration, VkFlags, or VkBool32 parameter
86 // contains a value that is not recognized as valid for
87 // that type.
88 DEVICE_LIMIT, // A specified parameter exceeds the limits returned
89 // by the physical device
90 DEVICE_FEATURE, // Use of a requested feature is not supported by
91 // the device
92 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
93 // was encountered.
94 EXTENSION_NOT_ENABLED, // An extension entrypoint was called, but the required
95 // extension was not enabled at CreateInstance or
96 // CreateDevice time.
Dustin Gravesf233e502016-05-05 13:44:21 -060097};
98
Dustin Graves58c2f662016-03-08 17:48:20 -070099struct GenericHeader {
100 VkStructureType sType;
101 const void *pNext;
102};
Dustin Graves58c2f662016-03-08 17:48:20 -0700103
Dustin Graves29148ff2016-03-23 19:44:00 -0600104// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600105const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -0600106
107// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -0700108const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
109
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600110// String returned by string_VkResult for an unrecognized type.
111const std::string UnsupportedResultString = "Unhandled VkResult";
112
Dustin Graves29148ff2016-03-23 19:44:00 -0600113// The base value used when computing the offset for an enumeration token value that is added by an extension.
114// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
115// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
116const uint32_t ExtEnumBaseValue = 1000000000;
117
Cort Strattonedbe9b82017-05-16 07:38:35 -0700118// The value of all VK_xxx_MAX_ENUM tokens
119const uint32_t MaxEnumValue = 0x7FFFFFFF;
120
Mark Lobodzinski26112592017-05-30 12:02:17 -0600121// Forward declaration
Mark Lobodzinskic4452972017-05-31 09:14:22 -0600122template <typename T>
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600123bool OutputExtensionError(const T *layer_data, const std::string &api_name, const std::string &extension_name);
Mark Lobodzinski26112592017-05-30 12:02:17 -0600124
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700125template <typename T>
126bool is_extension_added_token(T value) {
Cort Strattonedbe9b82017-05-16 07:38:35 -0700127 return (value != MaxEnumValue) && (static_cast<uint32_t>(std::abs(static_cast<int32_t>(value))) >= ExtEnumBaseValue);
Dustin Graves29148ff2016-03-23 19:44:00 -0600128}
129
130// VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE token is a special case that was converted from a core token to an
131// extension added token. Its original value was intentionally preserved after the conversion, so it does not use
132// 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 -0700133template <>
134bool is_extension_added_token(VkSamplerAddressMode value) {
Cort Strattonedbe9b82017-05-16 07:38:35 -0700135 bool result = is_extension_added_token(static_cast<uint32_t>(value));
136 return result || (value == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE);
Dustin Graves29148ff2016-03-23 19:44:00 -0600137}
138
Dustin Graves1e92cd72016-02-09 14:00:18 -0700139/**
Dustin Gravesf8032f22016-05-11 18:31:44 -0600140* Validate a minimum value.
141*
142* Verify that the specified value is greater than the specified lower bound.
143*
144* @param report_data debug_report_data object for routing validation messages.
145* @param api_name Name of API call being validated.
146* @param parameter_name Name of parameter being validated.
147* @param value Value to validate.
148* @param lower_bound Lower bound value to use for validation.
149* @return Boolean value indicating that the call should be skipped.
150*/
151template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600152bool ValidateGreaterThan(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, T value,
153 T lower_bound) {
Dustin Gravesf8032f22016-05-11 18:31:44 -0600154 bool skip_call = false;
155
156 if (value <= lower_bound) {
Mark Lobodzinskieb9e73f2017-04-13 10:06:48 -0600157 skip_call |=
158 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, 1, LayerName,
159 "%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 -0600160 }
161
162 return skip_call;
163}
164
165/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700166 * Validate a required pointer.
167 *
Dustin Graves58c2f662016-03-08 17:48:20 -0700168 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700169 *
170 * @param report_data debug_report_data object for routing validation messages.
171 * @param apiName Name of API call being validated.
172 * @param parameterName Name of parameter being validated.
173 * @param value Pointer to validate.
174 * @return Boolean value indicating that the call should be skipped.
175 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600176static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Dustin Graves080069b2016-04-05 13:48:15 -0600177 const void *value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600178 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700179
180 if (value == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600181 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 -0600182 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
183 parameterName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700184 }
185
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600186 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700187}
188
189/**
190 * Validate array count and pointer to array.
191 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700192 * Verify that required count and array parameters are not 0 or NULL. If the
193 * count parameter is not optional, verify that it is not 0. If the array
194 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700195 *
196 * @param report_data debug_report_data object for routing validation messages.
197 * @param apiName Name of API call being validated.
198 * @param countName Name of count parameter.
199 * @param arrayName Name of array parameter.
200 * @param count Number of elements in the array.
201 * @param array Array to validate.
202 * @param countRequired The 'count' parameter may not be 0 when true.
203 * @param arrayRequired The 'array' parameter may not be NULL when true.
204 * @return Boolean value indicating that the call should be skipped.
205 */
206template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600207bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
208 const ParameterName &arrayName, T count, const void *array, bool countRequired, bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600209 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700210
211 // Count parameters not tagged as optional cannot be 0
Józef Kucia20bb8fb2016-09-23 12:45:04 +0200212 if (countRequired && (count == 0)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600213 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 -0700214 REQUIRED_PARAMETER, LayerName, "%s: parameter %s must be greater than 0", apiName,
215 countName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700216 }
217
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600218 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600219 if ((array == NULL) && arrayRequired && (count != 0)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600220 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 -0700221 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
222 arrayName.get_name().c_str());
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600223 }
224
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600225 return skip_call;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600226}
227
228/**
229* Validate pointer to array count and pointer to array.
230*
231* Verify that required count and array parameters are not NULL. If count
232* is not NULL and its value is not optional, verify that it is not 0. If the
233* array parameter is NULL, and it is not optional, verify that count is 0.
234* The array parameter will typically be optional for this case (where count is
235* a pointer), allowing the caller to retrieve the available count.
236*
237* @param report_data debug_report_data object for routing validation messages.
238* @param apiName Name of API call being validated.
239* @param countName Name of count parameter.
240* @param arrayName Name of array parameter.
241* @param count Pointer to the number of elements in the array.
242* @param array Array to validate.
243* @param countPtrRequired The 'count' parameter may not be NULL when true.
244* @param countValueRequired The '*count' value may not be 0 when true.
245* @param arrayRequired The 'array' parameter may not be NULL when true.
246* @return Boolean value indicating that the call should be skipped.
247*/
248template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600249bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
250 const ParameterName &arrayName, const T *count, const void *array, bool countPtrRequired,
251 bool countValueRequired, bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600252 bool skip_call = false;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600253
254 if (count == NULL) {
255 if (countPtrRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600256 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 -0600257 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
258 countName.get_name().c_str());
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600259 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700260 } else {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600261 skip_call |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700262 }
263
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600264 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700265}
266
267/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600268 * Validate a pointer to a Vulkan structure.
269 *
270 * Verify that a required pointer to a structure is not NULL. If the pointer is
271 * not NULL, verify that each structure's sType field is set to the correct
272 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700273 *
274 * @param report_data debug_report_data object for routing validation messages.
275 * @param apiName Name of API call being validated.
276 * @param parameterName Name of struct parameter being validated.
277 * @param sTypeName Name of expected VkStructureType value.
278 * @param value Pointer to the struct to validate.
279 * @param sType VkStructureType for structure validation.
280 * @param required The parameter may not be NULL when true.
281 * @return Boolean value indicating that the call should be skipped.
282 */
283template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600284bool validate_struct_type(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
285 const char *sTypeName, const T *value, VkStructureType sType, bool required) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600286 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700287
288 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600289 if (required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600290 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
291 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
292 parameterName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700293 }
294 } else if (value->sType != sType) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600295 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
296 INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s->sType must be %s", apiName,
297 parameterName.get_name().c_str(), sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700298 }
299
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600300 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700301}
302
303/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700304 * Validate an array of Vulkan structures
305 *
306 * Verify that required count and array parameters are not 0 or NULL. If
307 * the array contains 1 or more structures, verify that each structure's
308 * sType field is set to the correct VkStructureType value.
309 *
310 * @param report_data debug_report_data object for routing validation messages.
311 * @param apiName Name of API call being validated.
312 * @param countName Name of count parameter.
313 * @param arrayName Name of array parameter.
314 * @param sTypeName Name of expected VkStructureType value.
315 * @param count Number of elements in the array.
316 * @param array Array to validate.
317 * @param sType VkStructureType for structure validation.
318 * @param countRequired The 'count' parameter may not be 0 when true.
319 * @param arrayRequired The 'array' parameter may not be NULL when true.
320 * @return Boolean value indicating that the call should be skipped.
321 */
322template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600323bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
324 const ParameterName &arrayName, const char *sTypeName, uint32_t count, const T *array,
325 VkStructureType sType, bool countRequired, bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600326 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700327
328 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600329 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700330 } else {
331 // Verify that all structs in the array have the correct type
332 for (uint32_t i = 0; i < count; ++i) {
333 if (array[i].sType != sType) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600334 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 -0600335 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
336 arrayName.get_name().c_str(), i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700337 }
338 }
339 }
340
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600341 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700342}
343
Dustin Graves58d114b2016-03-08 14:42:59 -0700344/**
Mark Young39389872017-01-19 21:10:49 -0700345 * Validate an array of Vulkan structures.
346 *
347 * Verify that required count and array parameters are not NULL. If count
348 * is not NULL and its value is not optional, verify that it is not 0.
349 * If the array contains 1 or more structures, verify that each structure's
350 * sType field is set to the correct VkStructureType value.
351 *
352 * @param report_data debug_report_data object for routing validation messages.
353 * @param apiName Name of API call being validated.
354 * @param countName Name of count parameter.
355 * @param arrayName Name of array parameter.
356 * @param sTypeName Name of expected VkStructureType value.
357 * @param count Pointer to the number of elements in the array.
358 * @param array Array to validate.
359 * @param sType VkStructureType for structure validation.
360 * @param countPtrRequired The 'count' parameter may not be NULL when true.
361 * @param countValueRequired The '*count' value may not be 0 when true.
362 * @param arrayRequired The 'array' parameter may not be NULL when true.
363 * @return Boolean value indicating that the call should be skipped.
364 */
365template <typename T>
366bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
367 const ParameterName &arrayName, const char *sTypeName, uint32_t *count, const T *array,
368 VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
369 bool skip_call = false;
370
371 if (count == NULL) {
372 if (countPtrRequired) {
373 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
374 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
375 countName.get_name().c_str());
376 }
377 } else {
378 skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
379 countValueRequired, arrayRequired);
380 }
381
382 return skip_call;
383}
384
385/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600386* Validate a Vulkan handle.
387*
388* Verify that the specified handle is not VK_NULL_HANDLE.
389*
390* @param report_data debug_report_data object for routing validation messages.
391* @param api_name Name of API call being validated.
392* @param parameter_name Name of struct parameter being validated.
393* @param value Handle to validate.
394* @return Boolean value indicating that the call should be skipped.
395*/
396template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600397bool 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 -0600398 bool skip_call = false;
399
400 if (value == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600401 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
402 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600403 parameter_name.get_name().c_str());
Dustin Graves20fd66f2016-04-18 18:33:21 -0600404 }
405
406 return skip_call;
407}
408
409/**
410* Validate an array of Vulkan handles.
411*
412* Verify that required count and array parameters are not NULL. If count
413* is not NULL and its value is not optional, verify that it is not 0.
414* If the array contains 1 or more handles, verify that no handle is set to
415* VK_NULL_HANDLE.
416*
417* @note This function is only intended to validate arrays of handles when none
418* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
419* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
420*
421* @param report_data debug_report_data object for routing validation messages.
422* @param api_name Name of API call being validated.
423* @param count_name Name of count parameter.
424* @param array_name Name of array parameter.
425* @param count Number of elements in the array.
426* @param array Array to validate.
427* @param count_required The 'count' parameter may not be 0 when true.
428* @param array_required The 'array' parameter may not be NULL when true.
429* @return Boolean value indicating that the call should be skipped.
430*/
431template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600432bool validate_handle_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
433 const ParameterName &array_name, uint32_t count, const T *array, bool count_required,
434 bool array_required) {
Dustin Graves20fd66f2016-04-18 18:33:21 -0600435 bool skip_call = false;
436
437 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600438 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 -0600439 } else {
440 // Verify that no handles in the array are VK_NULL_HANDLE
441 for (uint32_t i = 0; i < count; ++i) {
442 if (array[i] == VK_NULL_HANDLE) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600443 skip_call |=
444 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
445 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name,
446 array_name.get_name().c_str(), i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600447 }
448 }
449 }
450
451 return skip_call;
452}
453
454/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700455 * Validate string array count and content.
456 *
457 * Verify that required count and array parameters are not 0 or NULL. If the
458 * count parameter is not optional, verify that it is not 0. If the array
459 * parameter is NULL, and it is not optional, verify that count is 0. If the
460 * array parameter is not NULL, verify that none of the strings are NULL.
461 *
462 * @param report_data debug_report_data object for routing validation messages.
463 * @param apiName Name of API call being validated.
464 * @param countName Name of count parameter.
465 * @param arrayName Name of array parameter.
466 * @param count Number of strings in the array.
467 * @param array Array of strings to validate.
468 * @param countRequired The 'count' parameter may not be 0 when true.
469 * @param arrayRequired The 'array' parameter may not be NULL when true.
470 * @return Boolean value indicating that the call should be skipped.
471 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600472static bool validate_string_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
473 const ParameterName &arrayName, uint32_t count, const char *const *array, bool countRequired,
474 bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600475 bool skip_call = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700476
477 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600478 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves58d114b2016-03-08 14:42:59 -0700479 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600480 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700481 for (uint32_t i = 0; i < count; ++i) {
482 if (array[i] == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600483 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 -0600484 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
485 apiName, arrayName.get_name().c_str(), i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700486 }
487 }
488 }
489
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600490 return skip_call;
Dustin Graves58d114b2016-03-08 14:42:59 -0700491}
492
Dustin Graves58c2f662016-03-08 17:48:20 -0700493/**
494 * Validate a structure's pNext member.
495 *
496 * Verify that the specified pNext value points to the head of a list of
497 * allowed extension structures. If no extension structures are allowed,
498 * verify that pNext is null.
499 *
500 * @param report_data debug_report_data object for routing validation messages.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600501 * @param api_name Name of API call being validated.
502 * @param parameter_name Name of parameter being validated.
503 * @param allowed_struct_names Names of allowed structs.
Dustin Graves58c2f662016-03-08 17:48:20 -0700504 * @param next Pointer to validate.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600505 * @param allowed_type_count Total number of allowed structure types.
506 * @param allowed_types Array of strcuture types allowed for pNext.
507 * @param header_version Version of header defining the pNext validation rules.
Dustin Graves58c2f662016-03-08 17:48:20 -0700508 * @return Boolean value indicating that the call should be skipped.
509 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600510static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600511 const char *allowed_struct_names, const void *next, size_t allowed_type_count,
512 const VkStructureType *allowed_types, uint32_t header_version) {
513 bool skip_call = false;
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600514 std::unordered_set<const void *> cycle_check;
515 std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
516
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700517 const char disclaimer[] =
518 "This warning is based on the Valid Usage documentation for version %d of the Vulkan header. It "
519 "is possible that you are using a struct from a private extension or an extension that was added "
520 "to a later version of the Vulkan header, in which case your use of %s is perfectly valid but "
521 "is not guaranteed to work correctly with validation enabled";
Dustin Graves58c2f662016-03-08 17:48:20 -0700522
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600523 // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
524 // 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 -0700525 if (next != NULL) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600526 if (allowed_type_count == 0) {
527 std::string message = "%s: value of %s must be NULL. ";
528 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600529 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
530 INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name, parameter_name.get_name().c_str(),
531 header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700532 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600533 const VkStructureType *start = allowed_types;
534 const VkStructureType *end = allowed_types + allowed_type_count;
Dustin Graves58c2f662016-03-08 17:48:20 -0700535 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
536
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600537 cycle_check.insert(next);
Dustin Graves58c2f662016-03-08 17:48:20 -0700538
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600539
540 while (current != NULL) {
541 if (cycle_check.find(current->pNext) != cycle_check.end()) {
542 std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
543 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
544 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
545 parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next));
546 break;
547 } else {
548 cycle_check.insert(current->pNext);
549 }
550
551 std::string type_name = string_VkStructureType(current->sType);
552 if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
553 std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
554 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
555 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
556 parameter_name.get_name().c_str(), type_name.c_str());
557 } else {
558 unique_stype_check.insert(current->sType);
559 }
560
561 if (std::find(start, end, current->sType) == end) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600562 if (type_name == UnsupportedStructureTypeString) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700563 std::string message =
564 "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed "
565 "structures are [%s]. ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600566 message += disclaimer;
567 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
568 0, __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600569 parameter_name.get_name().c_str(), current->sType, allowed_struct_names,
570 header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700571 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600572 std::string message =
573 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]. ";
574 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600575 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
576 0, __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
577 parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names,
578 header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700579 }
580 }
Dustin Graves58c2f662016-03-08 17:48:20 -0700581 current = reinterpret_cast<const GenericHeader *>(current->pNext);
582 }
583 }
584 }
585
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600586 return skip_call;
Dustin Graves58c2f662016-03-08 17:48:20 -0700587}
588
Dustin Graves29148ff2016-03-23 19:44:00 -0600589/**
590* Validate a VkBool32 value.
591*
592* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
593*
594* @param report_data debug_report_data object for routing validation messages.
595* @param apiName Name of API call being validated.
596* @param parameterName Name of parameter being validated.
597* @param value Boolean value to validate.
598* @return Boolean value indicating that the call should be skipped.
599*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600600static bool validate_bool32(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
601 VkBool32 value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600602 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600603
604 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600605 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 -0600606 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
607 parameterName.get_name().c_str(), value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600608 }
609
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600610 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600611}
612
613/**
614* Validate a Vulkan enumeration value.
615*
616* Generate a warning if an enumeration token value does not fall within the core enumeration
617* begin and end token values, and was not added to the enumeration by an extension. Extension
618* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
619* with 1,000,000,000 as the base token value.
620*
621* @note This function does not expect to process enumerations defining bitmask flag bits.
622*
623* @param report_data debug_report_data object for routing validation messages.
624* @param apiName Name of API call being validated.
625* @param parameterName Name of parameter being validated.
626* @param enumName Name of the enumeration being validated.
627* @param begin The begin range value for the enumeration.
628* @param end The end range value for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600629* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600630* @return Boolean value indicating that the call should be skipped.
631*/
632template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600633bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
634 const char *enumName, T begin, T end, T value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600635 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600636
637 if (((value < begin) || (value > end)) && !is_extension_added_token(value)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700638 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
639 UNRECOGNIZED_VALUE, LayerName,
640 "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
641 "enumeration tokens and is not an extension added token",
642 apiName, parameterName.get_name().c_str(), value, enumName);
Dustin Graves29148ff2016-03-23 19:44:00 -0600643 }
644
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600645 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600646}
647
648/**
649* Validate an array of Vulkan enumeration value.
650*
651* Process all enumeration token values in the specified array and generate a warning if a value
652* does not fall within the core enumeration begin and end token values, and was not added to
653* the enumeration by an extension. Extension provided enumerations use the equation specified
654* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
655*
656* @note This function does not expect to process enumerations defining bitmask flag bits.
657*
658* @param report_data debug_report_data object for routing validation messages.
659* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600660* @param countName Name of count parameter.
661* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600662* @param enumName Name of the enumeration being validated.
663* @param begin The begin range value for the enumeration.
664* @param end The end range value for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600665* @param count Number of enumeration values in the array.
666* @param array Array of enumeration values to validate.
667* @param countRequired The 'count' parameter may not be 0 when true.
668* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600669* @return Boolean value indicating that the call should be skipped.
670*/
671template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600672static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
673 const ParameterName &arrayName, const char *enumName, T begin, T end, uint32_t count,
674 const T *array, bool countRequired, bool arrayRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600675 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600676
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600677 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600678 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600679 } else {
680 for (uint32_t i = 0; i < count; ++i) {
681 if (((array[i] < begin) || (array[i] > end)) && !is_extension_added_token(array[i])) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600682 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 -0600683 __LINE__, UNRECOGNIZED_VALUE, LayerName,
684 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
685 "enumeration tokens and is not an extension added token",
686 apiName, arrayName.get_name().c_str(), i, array[i], enumName);
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600687 }
Dustin Graves29148ff2016-03-23 19:44:00 -0600688 }
689 }
690
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600691 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600692}
693
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600694/**
Dustin Graves78df8512016-04-28 17:58:59 -0600695* Verify that a reserved VkFlags value is zero.
696*
697* Verify that the specified value is zero, to check VkFlags values that are reserved for
698* future use.
699*
700* @param report_data debug_report_data object for routing validation messages.
701* @param api_name Name of API call being validated.
702* @param parameter_name Name of parameter being validated.
703* @param value Value to validate.
704* @return Boolean value indicating that the call should be skipped.
705*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600706static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Dustin Graves78df8512016-04-28 17:58:59 -0600707 VkFlags value) {
708 bool skip_call = false;
709
710 if (value != 0) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600711 skip_call |=
712 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
713 RESERVED_PARAMETER, LayerName, "%s: parameter %s must be 0", api_name, parameter_name.get_name().c_str());
Dustin Graves78df8512016-04-28 17:58:59 -0600714 }
715
716 return skip_call;
717}
718
719/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600720* Validate a Vulkan bitmask value.
721*
722* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
723* for that type.
724*
725* @param report_data debug_report_data object for routing validation messages.
726* @param api_name Name of API call being validated.
727* @param parameter_name Name of parameter being validated.
728* @param flag_bits_name Name of the VkFlags type being validated.
729* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
730* @param value VkFlags value to validate.
731* @param flags_required The 'value' parameter may not be 0 when true.
Mike Schuchardt47619c82017-05-31 09:14:22 -0600732* @param singleFlag The 'value' parameter may not contain more than one bit from all_flags.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600733* @return Boolean value indicating that the call should be skipped.
734*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600735static bool validate_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Mike Schuchardt47619c82017-05-31 09:14:22 -0600736 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required, bool singleFlag) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600737 bool skip_call = false;
738
739 if (value == 0) {
740 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600741 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 -0600742 REQUIRED_PARAMETER, LayerName, "%s: value of %s must not be 0", api_name,
743 parameter_name.get_name().c_str());
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600744 }
745 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600746 skip_call |=
747 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
748 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600749 api_name, parameter_name.get_name().c_str(), flag_bits_name);
Mike Schuchardt47619c82017-05-31 09:14:22 -0600750 } else if (singleFlag && (std::bitset<sizeof(VkFlags) * 8>(value).count() > 1)) {
751 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
752 UNRECOGNIZED_VALUE, LayerName,
753 "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
754 parameter_name.get_name().c_str(), flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600755 }
756
757 return skip_call;
758}
759
760/**
761* Validate an array of Vulkan bitmask values.
762*
763* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
764* for that type.
765*
766* @param report_data debug_report_data object for routing validation messages.
767* @param api_name Name of API call being validated.
768* @param count_name Name of parameter being validated.
769* @param array_name Name of parameter being validated.
770* @param flag_bits_name Name of the VkFlags type being validated.
771* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
772* @param count Number of VkFlags values in the array.
773* @param array Array of VkFlags value to validate.
774* @param count_required The 'count' parameter may not be 0 when true.
775* @param array_required The 'array' parameter may not be NULL when true.
776* @return Boolean value indicating that the call should be skipped.
777*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600778static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
779 const ParameterName &array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
Dustin Graves78df8512016-04-28 17:58:59 -0600780 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600781 bool skip_call = false;
782
783 if ((count == 0) || (array == NULL)) {
784 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
785 } else {
786 // Verify that all VkFlags values in the array
787 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600788 if (array[i] == 0) {
789 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
790 // elements in the array are allowed be 0
791 if (array_required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600792 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
793 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name,
794 array_name.get_name().c_str(), i);
Dustin Graves78df8512016-04-28 17:58:59 -0600795 }
796 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600797 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
798 __LINE__, UNRECOGNIZED_VALUE, LayerName,
799 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600800 array_name.get_name().c_str(), i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600801 }
802 }
803 }
804
805 return skip_call;
806}
807
808/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600809* Get VkResult code description.
810*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600811* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
812* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600813*
814* @param value VkResult code to process.
815* @return String describing the specified VkResult code.
816*/
817static std::string get_result_description(VkResult result) {
818 // clang-format off
819 switch (result) {
820 case VK_SUCCESS: return "a command completed successfully";
821 case VK_NOT_READY: return "a fence or query has not yet completed";
822 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
823 case VK_EVENT_SET: return "an event is signaled";
824 case VK_EVENT_RESET: return "an event is unsignalled";
825 case VK_INCOMPLETE: return "a return array was too small for the result";
826 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
827 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
Dustin Graves2adca842016-05-16 18:35:55 -0600828 case VK_ERROR_INITIALIZATION_FAILED: return "initialization of an object has failed";
829 case VK_ERROR_DEVICE_LOST: return "the logical device has been lost";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600830 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
831 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
832 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
833 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
834 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
835 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
836 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
837 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
838 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
839 "VkSurfaceKHR object, or some other non-Vulkan surface object";
840 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
841 "matches the surface properties exactly, but can still be used to "
842 "present to the surface successfully.";
843 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
844 "longer compatible with the swapchain";
845 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
846 "presentable image layout, or is incompatible in a way that prevents "
847 "sharing an image";
848 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
849 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100850 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600851 };
852 // clang-format on
853}
854
855/**
856* Validate return code.
857*
858* Print a message describing the reason for failure when an error code is returned.
859*
860* @param report_data debug_report_data object for routing validation messages.
861* @param apiName Name of API call being validated.
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600862* @param ignore vector of VkResult return codes to be ignored
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600863* @param value VkResult value to validate.
864*/
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600865static void validate_result(debug_report_data *report_data, const char *apiName, std::vector<VkResult> const &ignore,
866 VkResult result) {
Chris Forbesf1f4e382016-10-13 14:44:03 +1300867 if (result < 0 && result != VK_ERROR_VALIDATION_FAILED_EXT) {
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600868 if (std::find(ignore.begin(), ignore.end(), result) != ignore.end()) {
869 return;
870 }
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600871 std::string resultName = string_VkResult(result);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600872 if (resultName == UnsupportedResultString) {
873 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600874 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
875 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600876 } else {
877 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600878 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
879 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
880 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600881 }
882 }
883}
884
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700885} // namespace parameter_validation
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600886
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700887#endif // PARAMETER_VALIDATION_UTILS_H