blob: e1e3ab017d0de8e9808795b47ed14cb570c91cfe [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 = {};
Mark Lobodzinski944ec372017-05-30 14:21:21 -060052 VkLayerInstanceDispatchTable dispatch_table = {};
53};
54
55struct layer_data {
56 debug_report_data *report_data = nullptr;
57 // Map for queue family index to queue count
58 std::unordered_map<uint32_t, uint32_t> queueFamilyIndexMap;
59 VkPhysicalDeviceLimits device_limits = {};
60 VkPhysicalDeviceFeatures physical_device_features = {};
61 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
62 VkDevice device = VK_NULL_HANDLE;
Mark Lobodzinskib8626db2017-06-01 08:44:53 -060063 DeviceExtensions extensions;
Mark Lobodzinski944ec372017-05-30 14:21:21 -060064
65 VkLayerDispatchTable dispatch_table = {};
66};
67
Dustin Gravesf233e502016-05-05 13:44:21 -060068enum ErrorCode {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070069 NONE, // Used for INFO & other non-error messages
70 INVALID_USAGE, // The value of a parameter is not consistent
71 // with the valid usage criteria defined in
72 // the Vulkan specification.
73 INVALID_STRUCT_STYPE, // The sType field of a Vulkan structure does
74 // not contain the value expected for a structure
75 // of that type.
76 INVALID_STRUCT_PNEXT, // The pNext field of a Vulkan structure references
77 // a value that is not compatible with a structure of
78 // that type or is not NULL when a structure of that
79 // type has no compatible pNext values.
80 REQUIRED_PARAMETER, // A required parameter was specified as 0 or NULL.
81 RESERVED_PARAMETER, // A parameter reserved for future use was not
82 // specified as 0 or NULL.
83 UNRECOGNIZED_VALUE, // A Vulkan enumeration, VkFlags, or VkBool32 parameter
84 // contains a value that is not recognized as valid for
85 // that type.
86 DEVICE_LIMIT, // A specified parameter exceeds the limits returned
87 // by the physical device
88 DEVICE_FEATURE, // Use of a requested feature is not supported by
89 // the device
90 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
91 // was encountered.
92 EXTENSION_NOT_ENABLED, // An extension entrypoint was called, but the required
93 // extension was not enabled at CreateInstance or
94 // CreateDevice time.
Dustin Gravesf233e502016-05-05 13:44:21 -060095};
96
Dustin Graves58c2f662016-03-08 17:48:20 -070097struct GenericHeader {
98 VkStructureType sType;
99 const void *pNext;
100};
Dustin Graves58c2f662016-03-08 17:48:20 -0700101
Dustin Graves29148ff2016-03-23 19:44:00 -0600102// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600103const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -0600104
105// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -0700106const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
107
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600108// String returned by string_VkResult for an unrecognized type.
109const std::string UnsupportedResultString = "Unhandled VkResult";
110
Dustin Graves29148ff2016-03-23 19:44:00 -0600111// The base value used when computing the offset for an enumeration token value that is added by an extension.
112// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
113// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
114const uint32_t ExtEnumBaseValue = 1000000000;
115
Cort Strattonedbe9b82017-05-16 07:38:35 -0700116// The value of all VK_xxx_MAX_ENUM tokens
117const uint32_t MaxEnumValue = 0x7FFFFFFF;
118
Mark Lobodzinski26112592017-05-30 12:02:17 -0600119// Forward declaration
Mark Lobodzinskic4452972017-05-31 09:14:22 -0600120template <typename T>
Mark Lobodzinskid8b7e022017-06-01 15:10:13 -0600121bool OutputExtensionError(const T *layer_data, const std::string &api_name, const std::string &extension_name);
Mark Lobodzinski26112592017-05-30 12:02:17 -0600122
Dustin Graves1e92cd72016-02-09 14:00:18 -0700123/**
Dustin Gravesf8032f22016-05-11 18:31:44 -0600124* Validate a minimum value.
125*
126* Verify that the specified value is greater than the specified lower bound.
127*
128* @param report_data debug_report_data object for routing validation messages.
129* @param api_name Name of API call being validated.
130* @param parameter_name Name of parameter being validated.
131* @param value Value to validate.
132* @param lower_bound Lower bound value to use for validation.
133* @return Boolean value indicating that the call should be skipped.
134*/
135template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600136bool ValidateGreaterThan(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, T value,
137 T lower_bound) {
Dustin Gravesf8032f22016-05-11 18:31:44 -0600138 bool skip_call = false;
139
140 if (value <= lower_bound) {
Mark Lobodzinskieb9e73f2017-04-13 10:06:48 -0600141 skip_call |=
142 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, 1, LayerName,
143 "%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 -0600144 }
145
146 return skip_call;
147}
148
149/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700150 * Validate a required pointer.
151 *
Dustin Graves58c2f662016-03-08 17:48:20 -0700152 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700153 *
154 * @param report_data debug_report_data object for routing validation messages.
155 * @param apiName Name of API call being validated.
156 * @param parameterName Name of parameter being validated.
157 * @param value Pointer to validate.
158 * @return Boolean value indicating that the call should be skipped.
159 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600160static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinskidead0b62017-06-28 13:22:03 -0600161 const void *value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600162 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700163
164 if (value == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600165 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinskidead0b62017-06-28 13:22:03 -0600166 vuid, LayerName, "%s: required parameter %s specified as NULL. %s", apiName,
167 parameterName.get_name().c_str(), validation_error_map[vuid]);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700168 }
169
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600170 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700171}
172
173/**
174 * Validate array count and pointer to array.
175 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700176 * Verify that required count and array parameters are not 0 or NULL. If the
177 * count parameter is not optional, verify that it is not 0. If the array
178 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700179 *
180 * @param report_data debug_report_data object for routing validation messages.
181 * @param apiName Name of API call being validated.
182 * @param countName Name of count parameter.
183 * @param arrayName Name of array parameter.
184 * @param count Number of elements in the array.
185 * @param array Array to validate.
186 * @param countRequired The 'count' parameter may not be 0 when true.
187 * @param arrayRequired The 'array' parameter may not be NULL when true.
188 * @return Boolean value indicating that the call should be skipped.
189 */
190template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600191bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600192 const ParameterName &arrayName, T count, const void *array, bool countRequired, bool arrayRequired,
193 UNIQUE_VALIDATION_ERROR_CODE count_required_vuid, UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600194 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700195
196 // Count parameters not tagged as optional cannot be 0
Józef Kucia20bb8fb2016-09-23 12:45:04 +0200197 if (countRequired && (count == 0)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600198 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600199 count_required_vuid, LayerName, "%s: parameter %s must be greater than 0. %s", apiName,
200 countName.get_name().c_str(), validation_error_map[count_required_vuid]);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700201 }
202
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600203 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600204 if ((array == NULL) && arrayRequired && (count != 0)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600205 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600206 array_required_vuid, LayerName, "%s: required parameter %s specified as NULL. %s", apiName,
207 arrayName.get_name().c_str(), validation_error_map[array_required_vuid]);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600208 }
209
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600210 return skip_call;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600211}
212
213/**
214* Validate pointer to array count and pointer to array.
215*
216* Verify that required count and array parameters are not NULL. If count
217* is not NULL and its value is not optional, verify that it is not 0. If the
218* array parameter is NULL, and it is not optional, verify that count is 0.
219* The array parameter will typically be optional for this case (where count is
220* a pointer), allowing the caller to retrieve the available count.
221*
222* @param report_data debug_report_data object for routing validation messages.
223* @param apiName Name of API call being validated.
224* @param countName Name of count parameter.
225* @param arrayName Name of array parameter.
226* @param count Pointer to the number of elements in the array.
227* @param array Array to validate.
228* @param countPtrRequired The 'count' parameter may not be NULL when true.
229* @param countValueRequired The '*count' value may not be 0 when true.
230* @param arrayRequired The 'array' parameter may not be NULL when true.
231* @return Boolean value indicating that the call should be skipped.
232*/
233template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600234bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
235 const ParameterName &arrayName, const T *count, const void *array, bool countPtrRequired,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600236 bool countValueRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
237 UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600238 bool skip_call = false;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600239
240 if (count == NULL) {
241 if (countPtrRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600242 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 -0600243 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
244 countName.get_name().c_str());
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600245 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700246 } else {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600247 skip_call |= validate_array(report_data, apiName, countName, arrayName, array ? (*count) : 0, array, countValueRequired,
248 arrayRequired, count_required_vuid, array_required_vuid);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700249 }
250
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600251 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700252}
253
254/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600255 * Validate a pointer to a Vulkan structure.
256 *
257 * Verify that a required pointer to a structure is not NULL. If the pointer is
258 * not NULL, verify that each structure's sType field is set to the correct
259 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700260 *
261 * @param report_data debug_report_data object for routing validation messages.
262 * @param apiName Name of API call being validated.
263 * @param parameterName Name of struct parameter being validated.
264 * @param sTypeName Name of expected VkStructureType value.
265 * @param value Pointer to the struct to validate.
266 * @param sType VkStructureType for structure validation.
267 * @param required The parameter may not be NULL when true.
268 * @return Boolean value indicating that the call should be skipped.
269 */
270template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600271bool validate_struct_type(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600272 const char *sTypeName, const T *value, VkStructureType sType, bool required,
273 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600274 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700275
276 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600277 if (required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600278 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
279 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
280 parameterName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700281 }
282 } else if (value->sType != sType) {
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600283 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
284 LayerName, "%s: parameter %s->sType must be %s. %s", apiName, parameterName.get_name().c_str(),
285 sTypeName, validation_error_map[vuid]);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700286 }
287
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600288 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700289}
290
291/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700292 * Validate an array of Vulkan structures
293 *
294 * Verify that required count and array parameters are not 0 or NULL. If
295 * the array contains 1 or more structures, verify that each structure's
296 * sType field is set to the correct VkStructureType value.
297 *
298 * @param report_data debug_report_data object for routing validation messages.
299 * @param apiName Name of API call being validated.
300 * @param countName Name of count parameter.
301 * @param arrayName Name of array parameter.
302 * @param sTypeName Name of expected VkStructureType value.
303 * @param count Number of elements in the array.
304 * @param array Array to validate.
305 * @param sType VkStructureType for structure validation.
306 * @param countRequired The 'count' parameter may not be 0 when true.
307 * @param arrayRequired The 'array' parameter may not be NULL when true.
308 * @return Boolean value indicating that the call should be skipped.
309 */
310template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600311bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
312 const ParameterName &arrayName, const char *sTypeName, uint32_t count, const T *array,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600313 VkStructureType sType, bool countRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600314 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700315
316 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600317 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600318 VALIDATION_ERROR_UNDEFINED, vuid);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700319 } else {
320 // Verify that all structs in the array have the correct type
321 for (uint32_t i = 0; i < count; ++i) {
322 if (array[i].sType != sType) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600323 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 -0600324 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
325 arrayName.get_name().c_str(), i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700326 }
327 }
328 }
329
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600330 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700331}
332
Dustin Graves58d114b2016-03-08 14:42:59 -0700333/**
Mark Young39389872017-01-19 21:10:49 -0700334 * Validate an array of Vulkan structures.
335 *
336 * Verify that required count and array parameters are not NULL. If count
337 * is not NULL and its value is not optional, verify that it is not 0.
338 * If the array contains 1 or more structures, verify that each structure's
339 * sType field is set to the correct VkStructureType value.
340 *
341 * @param report_data debug_report_data object for routing validation messages.
342 * @param apiName Name of API call being validated.
343 * @param countName Name of count parameter.
344 * @param arrayName Name of array parameter.
345 * @param sTypeName Name of expected VkStructureType value.
346 * @param count Pointer to the number of elements in the array.
347 * @param array Array to validate.
348 * @param sType VkStructureType for structure validation.
349 * @param countPtrRequired The 'count' parameter may not be NULL when true.
350 * @param countValueRequired The '*count' value may not be 0 when true.
351 * @param arrayRequired The 'array' parameter may not be NULL when true.
352 * @return Boolean value indicating that the call should be skipped.
353 */
354template <typename T>
355bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
356 const ParameterName &arrayName, const char *sTypeName, uint32_t *count, const T *array,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600357 VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired,
358 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Young39389872017-01-19 21:10:49 -0700359 bool skip_call = false;
360
361 if (count == NULL) {
362 if (countPtrRequired) {
363 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
364 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
365 countName.get_name().c_str());
366 }
367 } else {
368 skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600369 countValueRequired, arrayRequired, vuid);
Mark Young39389872017-01-19 21:10:49 -0700370 }
371
372 return skip_call;
373}
374
375/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600376* Validate a Vulkan handle.
377*
378* Verify that the specified handle is not VK_NULL_HANDLE.
379*
380* @param report_data debug_report_data object for routing validation messages.
381* @param api_name Name of API call being validated.
382* @param parameter_name Name of struct parameter being validated.
383* @param value Handle to validate.
384* @return Boolean value indicating that the call should be skipped.
385*/
386template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600387bool 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 -0600388 bool skip_call = false;
389
390 if (value == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600391 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
392 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600393 parameter_name.get_name().c_str());
Dustin Graves20fd66f2016-04-18 18:33:21 -0600394 }
395
396 return skip_call;
397}
398
399/**
400* Validate an array of Vulkan handles.
401*
402* Verify that required count and array parameters are not NULL. If count
403* is not NULL and its value is not optional, verify that it is not 0.
404* If the array contains 1 or more handles, verify that no handle is set to
405* VK_NULL_HANDLE.
406*
407* @note This function is only intended to validate arrays of handles when none
408* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
409* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
410*
411* @param report_data debug_report_data object for routing validation messages.
412* @param api_name Name of API call being validated.
413* @param count_name Name of count parameter.
414* @param array_name Name of array parameter.
415* @param count Number of elements in the array.
416* @param array Array to validate.
417* @param count_required The 'count' parameter may not be 0 when true.
418* @param array_required The 'array' parameter may not be NULL when true.
419* @return Boolean value indicating that the call should be skipped.
420*/
421template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600422bool validate_handle_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
423 const ParameterName &array_name, uint32_t count, const T *array, bool count_required,
424 bool array_required) {
Dustin Graves20fd66f2016-04-18 18:33:21 -0600425 bool skip_call = false;
426
427 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600428 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
429 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600430 } else {
431 // Verify that no handles in the array are VK_NULL_HANDLE
432 for (uint32_t i = 0; i < count; ++i) {
433 if (array[i] == VK_NULL_HANDLE) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600434 skip_call |=
435 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
436 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name,
437 array_name.get_name().c_str(), i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600438 }
439 }
440 }
441
442 return skip_call;
443}
444
445/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700446 * Validate string array count and content.
447 *
448 * Verify that required count and array parameters are not 0 or NULL. If the
449 * count parameter is not optional, verify that it is not 0. If the array
450 * parameter is NULL, and it is not optional, verify that count is 0. If the
451 * array parameter is not NULL, verify that none of the strings are NULL.
452 *
453 * @param report_data debug_report_data object for routing validation messages.
454 * @param apiName Name of API call being validated.
455 * @param countName Name of count parameter.
456 * @param arrayName Name of array parameter.
457 * @param count Number of strings in the array.
458 * @param array Array of strings to validate.
459 * @param countRequired The 'count' parameter may not be 0 when true.
460 * @param arrayRequired The 'array' parameter may not be NULL when true.
461 * @return Boolean value indicating that the call should be skipped.
462 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600463static bool validate_string_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
464 const ParameterName &arrayName, uint32_t count, const char *const *array, bool countRequired,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600465 bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
466 UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600467 bool skip_call = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700468
469 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600470 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
471 count_required_vuid, array_required_vuid);
Dustin Graves58d114b2016-03-08 14:42:59 -0700472 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600473 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700474 for (uint32_t i = 0; i < count; ++i) {
475 if (array[i] == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600476 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 -0600477 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
478 apiName, arrayName.get_name().c_str(), i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700479 }
480 }
481 }
482
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600483 return skip_call;
Dustin Graves58d114b2016-03-08 14:42:59 -0700484}
485
Dustin Graves58c2f662016-03-08 17:48:20 -0700486/**
487 * Validate a structure's pNext member.
488 *
489 * Verify that the specified pNext value points to the head of a list of
490 * allowed extension structures. If no extension structures are allowed,
491 * verify that pNext is null.
492 *
493 * @param report_data debug_report_data object for routing validation messages.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600494 * @param api_name Name of API call being validated.
495 * @param parameter_name Name of parameter being validated.
496 * @param allowed_struct_names Names of allowed structs.
Dustin Graves58c2f662016-03-08 17:48:20 -0700497 * @param next Pointer to validate.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600498 * @param allowed_type_count Total number of allowed structure types.
499 * @param allowed_types Array of strcuture types allowed for pNext.
500 * @param header_version Version of header defining the pNext validation rules.
Dustin Graves58c2f662016-03-08 17:48:20 -0700501 * @return Boolean value indicating that the call should be skipped.
502 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600503static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600504 const char *allowed_struct_names, const void *next, size_t allowed_type_count,
Mark Lobodzinski3c828522017-06-26 13:05:57 -0600505 const VkStructureType *allowed_types, uint32_t header_version,
506 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600507 bool skip_call = false;
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600508 std::unordered_set<const void *> cycle_check;
509 std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
510
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700511 const char disclaimer[] =
512 "This warning is based on the Valid Usage documentation for version %d of the Vulkan header. It "
513 "is possible that you are using a struct from a private extension or an extension that was added "
514 "to a later version of the Vulkan header, in which case your use of %s is perfectly valid but "
515 "is not guaranteed to work correctly with validation enabled";
Dustin Graves58c2f662016-03-08 17:48:20 -0700516
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600517 // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
518 // 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 -0700519 if (next != NULL) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600520 if (allowed_type_count == 0) {
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600521 std::string message = "%s: value of %s must be NULL. %s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600522 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600523 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600524 vuid, LayerName, message.c_str(), api_name, parameter_name.get_name().c_str(),
525 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700526 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600527 const VkStructureType *start = allowed_types;
528 const VkStructureType *end = allowed_types + allowed_type_count;
Dustin Graves58c2f662016-03-08 17:48:20 -0700529 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
530
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600531 cycle_check.insert(next);
Dustin Graves58c2f662016-03-08 17:48:20 -0700532
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600533 while (current != NULL) {
534 if (cycle_check.find(current->pNext) != cycle_check.end()) {
535 std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
536 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
537 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
538 parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next));
539 break;
540 } else {
541 cycle_check.insert(current->pNext);
542 }
543
544 std::string type_name = string_VkStructureType(current->sType);
545 if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
546 std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
547 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
548 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
549 parameter_name.get_name().c_str(), type_name.c_str());
550 } else {
551 unique_stype_check.insert(current->sType);
552 }
553
554 if (std::find(start, end, current->sType) == end) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600555 if (type_name == UnsupportedStructureTypeString) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700556 std::string message =
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600557 "%s: %s chain includes a structure with unknown VkStructureType (%d); Allowed structures are [%s]. %s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600558 message += disclaimer;
559 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600560 0, __LINE__, vuid, LayerName, message.c_str(), api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600561 parameter_name.get_name().c_str(), current->sType, allowed_struct_names,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600562 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700563 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600564 std::string message =
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600565 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]. "
566 "%s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600567 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600568 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600569 0, __LINE__, vuid, LayerName, message.c_str(), api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600570 parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600571 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700572 }
573 }
Dustin Graves58c2f662016-03-08 17:48:20 -0700574 current = reinterpret_cast<const GenericHeader *>(current->pNext);
575 }
576 }
577 }
578
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600579 return skip_call;
Dustin Graves58c2f662016-03-08 17:48:20 -0700580}
581
Dustin Graves29148ff2016-03-23 19:44:00 -0600582/**
583* Validate a VkBool32 value.
584*
585* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
586*
587* @param report_data debug_report_data object for routing validation messages.
588* @param apiName Name of API call being validated.
589* @param parameterName Name of parameter being validated.
590* @param value Boolean value to validate.
591* @return Boolean value indicating that the call should be skipped.
592*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600593static bool validate_bool32(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
594 VkBool32 value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600595 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600596
597 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600598 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 -0600599 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
600 parameterName.get_name().c_str(), value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600601 }
602
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600603 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600604}
605
606/**
607* Validate a Vulkan enumeration value.
608*
609* Generate a warning if an enumeration token value does not fall within the core enumeration
610* begin and end token values, and was not added to the enumeration by an extension. Extension
611* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
612* with 1,000,000,000 as the base token value.
613*
614* @note This function does not expect to process enumerations defining bitmask flag bits.
615*
616* @param report_data debug_report_data object for routing validation messages.
617* @param apiName Name of API call being validated.
618* @param parameterName Name of parameter being validated.
619* @param enumName Name of the enumeration being validated.
Mark Lobodzinskiff9db7c2017-07-25 15:32:11 -0600620* @param valid_values The list of valid values for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600621* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600622* @return Boolean value indicating that the call should be skipped.
623*/
624template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600625bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinskib4d1ab72017-07-25 14:49:06 -0600626 const char *enumName, const std::vector<T> &valid_values, T value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
627 bool skip = false;
628
629 if (std::find(valid_values.begin(), valid_values.end(), value) == valid_values.end()) {
630 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
631 LayerName,
632 "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
633 "enumeration tokens and is not an extension added token. %s",
634 apiName, parameterName.get_name().c_str(), value, enumName, validation_error_map[vuid]);
635 }
636
637 return skip;
638}
639
Dustin Graves29148ff2016-03-23 19:44:00 -0600640/**
641* Validate an array of Vulkan enumeration value.
642*
643* Process all enumeration token values in the specified array and generate a warning if a value
644* does not fall within the core enumeration begin and end token values, and was not added to
645* the enumeration by an extension. Extension provided enumerations use the equation specified
646* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
647*
648* @note This function does not expect to process enumerations defining bitmask flag bits.
649*
650* @param report_data debug_report_data object for routing validation messages.
651* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600652* @param countName Name of count parameter.
653* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600654* @param enumName Name of the enumeration being validated.
Mark Lobodzinskiff9db7c2017-07-25 15:32:11 -0600655* @param valid_values The list of valid values for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600656* @param count Number of enumeration values in the array.
657* @param array Array of enumeration values to validate.
658* @param countRequired The 'count' parameter may not be 0 when true.
659* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600660* @return Boolean value indicating that the call should be skipped.
661*/
662template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600663static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
Mark Lobodzinskibd72bec2017-07-25 15:29:36 -0600664 const ParameterName &arrayName, const char *enumName, const std::vector<T> &valid_values,
665 uint32_t count, const T *array, bool countRequired, bool arrayRequired) {
666 bool skip_call = false;
667
668 if ((count == 0) || (array == NULL)) {
669 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
670 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
671 } else {
672 for (uint32_t i = 0; i < count; ++i) {
673 if (std::find(valid_values.begin(), valid_values.end(), array[i]) == valid_values.end()) {
674 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
675 __LINE__, UNRECOGNIZED_VALUE, LayerName,
676 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
677 "enumeration tokens and is not an extension added token",
678 apiName, arrayName.get_name().c_str(), i, array[i], enumName);
679 }
680 }
681 }
682
683 return skip_call;
684}
685
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600686/**
Dustin Graves78df8512016-04-28 17:58:59 -0600687* Verify that a reserved VkFlags value is zero.
688*
689* Verify that the specified value is zero, to check VkFlags values that are reserved for
690* future use.
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 value Value to validate.
696* @return Boolean value indicating that the call should be skipped.
697*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600698static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Mark Lobodzinskid0b0c512017-06-28 12:06:41 -0600699 VkFlags value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Graves78df8512016-04-28 17:58:59 -0600700 bool skip_call = false;
701
702 if (value != 0) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600703 skip_call |=
704 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinskid0b0c512017-06-28 12:06:41 -0600705 vuid, LayerName, "%s: parameter %s must be 0. %s", api_name, parameter_name.get_name().c_str(),
706 validation_error_map[vuid]);
Dustin Graves78df8512016-04-28 17:58:59 -0600707 }
708
709 return skip_call;
710}
711
712/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600713* Validate a Vulkan bitmask value.
714*
715* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
716* for that type.
717*
718* @param report_data debug_report_data object for routing validation messages.
719* @param api_name Name of API call being validated.
720* @param parameter_name Name of parameter being validated.
721* @param flag_bits_name Name of the VkFlags type being validated.
722* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
723* @param value VkFlags value to validate.
724* @param flags_required The 'value' parameter may not be 0 when true.
Mike Schuchardt47619c82017-05-31 09:14:22 -0600725* @param singleFlag The 'value' parameter may not contain more than one bit from all_flags.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600726* @return Boolean value indicating that the call should be skipped.
727*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600728static bool validate_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Mark Lobodzinskie643fcc2017-06-26 16:27:15 -0600729 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required, bool singleFlag,
730 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600731 bool skip_call = false;
732
733 if (value == 0) {
734 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600735 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinskie643fcc2017-06-26 16:27:15 -0600736 vuid, LayerName, "%s: value of %s must not be 0. %s", api_name,
737 parameter_name.get_name().c_str(), validation_error_map[vuid]);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600738 }
739 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600740 skip_call |=
741 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
742 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600743 api_name, parameter_name.get_name().c_str(), flag_bits_name);
Mike Schuchardt47619c82017-05-31 09:14:22 -0600744 } else if (singleFlag && (std::bitset<sizeof(VkFlags) * 8>(value).count() > 1)) {
745 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
746 UNRECOGNIZED_VALUE, LayerName,
747 "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
748 parameter_name.get_name().c_str(), flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600749 }
750
751 return skip_call;
752}
753
754/**
755* Validate an array of Vulkan bitmask values.
756*
757* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
758* for that type.
759*
760* @param report_data debug_report_data object for routing validation messages.
761* @param api_name Name of API call being validated.
762* @param count_name Name of parameter being validated.
763* @param array_name Name of parameter being validated.
764* @param flag_bits_name Name of the VkFlags type being validated.
765* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
766* @param count Number of VkFlags values in the array.
767* @param array Array of VkFlags value to validate.
768* @param count_required The 'count' parameter may not be 0 when true.
769* @param array_required The 'array' parameter may not be NULL when true.
770* @return Boolean value indicating that the call should be skipped.
771*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600772static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
773 const ParameterName &array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
Dustin Graves78df8512016-04-28 17:58:59 -0600774 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600775 bool skip_call = false;
776
777 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600778 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
779 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600780 } else {
781 // Verify that all VkFlags values in the array
782 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600783 if (array[i] == 0) {
784 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
785 // elements in the array are allowed be 0
786 if (array_required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600787 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
788 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name,
789 array_name.get_name().c_str(), i);
Dustin Graves78df8512016-04-28 17:58:59 -0600790 }
791 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600792 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
793 __LINE__, UNRECOGNIZED_VALUE, LayerName,
794 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600795 array_name.get_name().c_str(), i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600796 }
797 }
798 }
799
800 return skip_call;
801}
802
803/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600804* Get VkResult code description.
805*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600806* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
807* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600808*
809* @param value VkResult code to process.
810* @return String describing the specified VkResult code.
811*/
812static std::string get_result_description(VkResult result) {
813 // clang-format off
814 switch (result) {
815 case VK_SUCCESS: return "a command completed successfully";
816 case VK_NOT_READY: return "a fence or query has not yet completed";
817 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
818 case VK_EVENT_SET: return "an event is signaled";
819 case VK_EVENT_RESET: return "an event is unsignalled";
820 case VK_INCOMPLETE: return "a return array was too small for the result";
821 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
822 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
Dustin Graves2adca842016-05-16 18:35:55 -0600823 case VK_ERROR_INITIALIZATION_FAILED: return "initialization of an object has failed";
824 case VK_ERROR_DEVICE_LOST: return "the logical device has been lost";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600825 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
826 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
827 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
828 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
829 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
830 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
831 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
832 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
833 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
834 "VkSurfaceKHR object, or some other non-Vulkan surface object";
835 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
836 "matches the surface properties exactly, but can still be used to "
837 "present to the surface successfully.";
838 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
839 "longer compatible with the swapchain";
840 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
841 "presentable image layout, or is incompatible in a way that prevents "
842 "sharing an image";
843 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
844 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100845 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600846 };
847 // clang-format on
848}
849
850/**
851* Validate return code.
852*
853* Print a message describing the reason for failure when an error code is returned.
854*
855* @param report_data debug_report_data object for routing validation messages.
856* @param apiName Name of API call being validated.
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600857* @param ignore vector of VkResult return codes to be ignored
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600858* @param value VkResult value to validate.
859*/
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600860static void validate_result(debug_report_data *report_data, const char *apiName, std::vector<VkResult> const &ignore,
861 VkResult result) {
Chris Forbesf1f4e382016-10-13 14:44:03 +1300862 if (result < 0 && result != VK_ERROR_VALIDATION_FAILED_EXT) {
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600863 if (std::find(ignore.begin(), ignore.end(), result) != ignore.end()) {
864 return;
865 }
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600866 std::string resultName = string_VkResult(result);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600867 if (resultName == UnsupportedResultString) {
868 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600869 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
870 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600871 } else {
872 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600873 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
874 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
875 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600876 }
877 }
878}
879
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700880} // namespace parameter_validation
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600881
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700882#endif // PARAMETER_VALIDATION_UTILS_H