blob: 6ef3de2ec91f331d5df1b409685e510cf8bc6858 [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>
Petr Kraus595468a2017-09-10 02:26:33 +020028#include <mutex>
Mark Lobodzinski5cd08512017-09-12 09:50:25 -060029#include <unordered_set>
Dustin Graves58c2f662016-03-08 17:48:20 -070030
Dustin Graves1e92cd72016-02-09 14:00:18 -070031#include "vulkan/vulkan.h"
Dustin Graves58c2f662016-03-08 17:48:20 -070032#include "vk_enum_string_helper.h"
Dustin Graves1e92cd72016-02-09 14:00:18 -070033#include "vk_layer_logging.h"
Karl Schultza9ef1e52016-10-06 17:53:48 -060034#include "vk_validation_error_messages.h"
Mark Lobodzinski89cdf722017-06-01 15:09:55 -060035#include "vk_extension_helper.h"
Mark Lobodzinski944ec372017-05-30 14:21:21 -060036
Dustin Graves1e92cd72016-02-09 14:00:18 -070037
Dustin Graves8ffbbf62016-07-22 13:19:46 -060038#include "parameter_name.h"
39
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060040namespace parameter_validation {
41
Mark Lobodzinskid4950072017-08-01 13:02:20 -060042extern const uint32_t GeneratedHeaderVersion;
43extern const std::unordered_map<std::string, void*> name_to_funcptr_map;
44
45extern const VkQueryPipelineStatisticFlags AllVkQueryPipelineStatisticFlagBits;
46extern const VkColorComponentFlags AllVkColorComponentFlagBits;
47extern const VkShaderStageFlags AllVkShaderStageFlagBits;
48extern const VkQueryControlFlags AllVkQueryControlFlagBits;
49
50extern const std::vector<VkCompareOp> AllVkCompareOpEnums;
51extern const std::vector<VkStencilOp> AllVkStencilOpEnums;
52extern const std::vector<VkBlendFactor> AllVkBlendFactorEnums;
53extern const std::vector<VkBlendOp> AllVkBlendOpEnums;
54extern const std::vector<VkLogicOp> AllVkLogicOpEnums;
55extern const std::vector<VkBorderColor> AllVkBorderColorEnums;
56extern const std::vector<VkImageLayout> AllVkImageLayoutEnums;
57
Mark Lobodzinski944ec372017-05-30 14:21:21 -060058struct instance_layer_data {
59 VkInstance instance = VK_NULL_HANDLE;
60
61 debug_report_data *report_data = nullptr;
62 std::vector<VkDebugReportCallbackEXT> logging_callback;
63
64 // The following are for keeping track of the temporary callbacks that can
65 // be used in vkCreateInstance and vkDestroyInstance:
66 uint32_t num_tmp_callbacks = 0;
67 VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos = nullptr;
68 VkDebugReportCallbackEXT *tmp_callbacks = nullptr;
69 InstanceExtensions extensions = {};
Mark Lobodzinski944ec372017-05-30 14:21:21 -060070 VkLayerInstanceDispatchTable dispatch_table = {};
71};
72
73struct layer_data {
74 debug_report_data *report_data = nullptr;
75 // Map for queue family index to queue count
76 std::unordered_map<uint32_t, uint32_t> queueFamilyIndexMap;
77 VkPhysicalDeviceLimits device_limits = {};
78 VkPhysicalDeviceFeatures physical_device_features = {};
79 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
80 VkDevice device = VK_NULL_HANDLE;
Mark Lobodzinskib8626db2017-06-01 08:44:53 -060081 DeviceExtensions extensions;
Mark Lobodzinski944ec372017-05-30 14:21:21 -060082
83 VkLayerDispatchTable dispatch_table = {};
84};
85
Dustin Gravesf233e502016-05-05 13:44:21 -060086enum ErrorCode {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070087 NONE, // Used for INFO & other non-error messages
88 INVALID_USAGE, // The value of a parameter is not consistent
89 // with the valid usage criteria defined in
90 // the Vulkan specification.
91 INVALID_STRUCT_STYPE, // The sType field of a Vulkan structure does
92 // not contain the value expected for a structure
93 // of that type.
94 INVALID_STRUCT_PNEXT, // The pNext field of a Vulkan structure references
95 // a value that is not compatible with a structure of
96 // that type or is not NULL when a structure of that
97 // type has no compatible pNext values.
98 REQUIRED_PARAMETER, // A required parameter was specified as 0 or NULL.
99 RESERVED_PARAMETER, // A parameter reserved for future use was not
100 // specified as 0 or NULL.
101 UNRECOGNIZED_VALUE, // A Vulkan enumeration, VkFlags, or VkBool32 parameter
102 // contains a value that is not recognized as valid for
103 // that type.
104 DEVICE_LIMIT, // A specified parameter exceeds the limits returned
105 // by the physical device
106 DEVICE_FEATURE, // Use of a requested feature is not supported by
107 // the device
108 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
109 // was encountered.
110 EXTENSION_NOT_ENABLED, // An extension entrypoint was called, but the required
111 // extension was not enabled at CreateInstance or
112 // CreateDevice time.
Dustin Gravesf233e502016-05-05 13:44:21 -0600113};
114
Dustin Graves58c2f662016-03-08 17:48:20 -0700115struct GenericHeader {
116 VkStructureType sType;
117 const void *pNext;
118};
Dustin Graves58c2f662016-03-08 17:48:20 -0700119
Dustin Graves29148ff2016-03-23 19:44:00 -0600120// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600121const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -0600122
123// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -0700124const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
125
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600126// String returned by string_VkResult for an unrecognized type.
127const std::string UnsupportedResultString = "Unhandled VkResult";
128
Dustin Graves29148ff2016-03-23 19:44:00 -0600129// The base value used when computing the offset for an enumeration token value that is added by an extension.
130// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
131// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
132const uint32_t ExtEnumBaseValue = 1000000000;
133
Cort Strattonedbe9b82017-05-16 07:38:35 -0700134// The value of all VK_xxx_MAX_ENUM tokens
135const uint32_t MaxEnumValue = 0x7FFFFFFF;
136
Mark Lobodzinski26112592017-05-30 12:02:17 -0600137
Dustin Graves1e92cd72016-02-09 14:00:18 -0700138/**
Dustin Gravesf8032f22016-05-11 18:31:44 -0600139* Validate a minimum value.
140*
141* Verify that the specified value is greater than the specified lower bound.
142*
143* @param report_data debug_report_data object for routing validation messages.
144* @param api_name Name of API call being validated.
145* @param parameter_name Name of parameter being validated.
146* @param value Value to validate.
147* @param lower_bound Lower bound value to use for validation.
148* @return Boolean value indicating that the call should be skipped.
149*/
150template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600151bool ValidateGreaterThan(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, T value,
152 T lower_bound) {
Dustin Gravesf8032f22016-05-11 18:31:44 -0600153 bool skip_call = false;
154
155 if (value <= lower_bound) {
Mark Lobodzinskieb9e73f2017-04-13 10:06:48 -0600156 skip_call |=
157 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, 1, LayerName,
158 "%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 -0600159 }
160
161 return skip_call;
162}
163
164/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700165 * Validate a required pointer.
166 *
Dustin Graves58c2f662016-03-08 17:48:20 -0700167 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700168 *
169 * @param report_data debug_report_data object for routing validation messages.
170 * @param apiName Name of API call being validated.
171 * @param parameterName Name of parameter being validated.
172 * @param value Pointer to validate.
173 * @return Boolean value indicating that the call should be skipped.
174 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600175static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinskidead0b62017-06-28 13:22:03 -0600176 const void *value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600177 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700178
179 if (value == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600180 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
Mark Lobodzinskidead0b62017-06-28 13:22:03 -0600181 vuid, LayerName, "%s: required parameter %s specified as NULL. %s", apiName,
182 parameterName.get_name().c_str(), validation_error_map[vuid]);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700183 }
184
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600185 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700186}
187
188/**
189 * Validate array count and pointer to array.
190 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700191 * Verify that required count and array parameters are not 0 or NULL. If the
192 * count parameter is not optional, verify that it is not 0. If the array
193 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700194 *
195 * @param report_data debug_report_data object for routing validation messages.
196 * @param apiName Name of API call being validated.
197 * @param countName Name of count parameter.
198 * @param arrayName Name of array parameter.
199 * @param count Number of elements in the array.
200 * @param array Array to validate.
201 * @param countRequired The 'count' parameter may not be 0 when true.
202 * @param arrayRequired The 'array' parameter may not be NULL when true.
203 * @return Boolean value indicating that the call should be skipped.
204 */
205template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600206bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600207 const ParameterName &arrayName, T count, const void *array, bool countRequired, bool arrayRequired,
208 UNIQUE_VALIDATION_ERROR_CODE count_required_vuid, UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
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 Lobodzinski1e707bd2017-06-28 10:54:55 -0600214 count_required_vuid, LayerName, "%s: parameter %s must be greater than 0. %s", apiName,
215 countName.get_name().c_str(), validation_error_map[count_required_vuid]);
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 Lobodzinski1e707bd2017-06-28 10:54:55 -0600221 array_required_vuid, LayerName, "%s: required parameter %s specified as NULL. %s", apiName,
222 arrayName.get_name().c_str(), validation_error_map[array_required_vuid]);
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,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600251 bool countValueRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
252 UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600253 bool skip_call = false;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600254
255 if (count == NULL) {
256 if (countPtrRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600257 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 -0600258 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
259 countName.get_name().c_str());
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600260 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700261 } else {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600262 skip_call |= validate_array(report_data, apiName, countName, arrayName, array ? (*count) : 0, array, countValueRequired,
263 arrayRequired, count_required_vuid, array_required_vuid);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700264 }
265
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600266 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700267}
268
269/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600270 * Validate a pointer to a Vulkan structure.
271 *
272 * Verify that a required pointer to a structure is not NULL. If the pointer is
273 * not NULL, verify that each structure's sType field is set to the correct
274 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700275 *
276 * @param report_data debug_report_data object for routing validation messages.
277 * @param apiName Name of API call being validated.
278 * @param parameterName Name of struct parameter being validated.
279 * @param sTypeName Name of expected VkStructureType value.
280 * @param value Pointer to the struct to validate.
281 * @param sType VkStructureType for structure validation.
282 * @param required The parameter may not be NULL when true.
283 * @return Boolean value indicating that the call should be skipped.
284 */
285template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600286bool validate_struct_type(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600287 const char *sTypeName, const T *value, VkStructureType sType, bool required,
288 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600289 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700290
291 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600292 if (required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600293 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
294 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
295 parameterName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700296 }
297 } else if (value->sType != sType) {
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600298 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
299 LayerName, "%s: parameter %s->sType must be %s. %s", apiName, parameterName.get_name().c_str(),
300 sTypeName, validation_error_map[vuid]);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700301 }
302
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600303 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700304}
305
306/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700307 * Validate an array of Vulkan structures
308 *
309 * Verify that required count and array parameters are not 0 or NULL. If
310 * the array contains 1 or more structures, verify that each structure's
311 * sType field is set to the correct VkStructureType value.
312 *
313 * @param report_data debug_report_data object for routing validation messages.
314 * @param apiName Name of API call being validated.
315 * @param countName Name of count parameter.
316 * @param arrayName Name of array parameter.
317 * @param sTypeName Name of expected VkStructureType value.
318 * @param count Number of elements in the array.
319 * @param array Array to validate.
320 * @param sType VkStructureType for structure validation.
321 * @param countRequired The 'count' parameter may not be 0 when true.
322 * @param arrayRequired The 'array' parameter may not be NULL when true.
323 * @return Boolean value indicating that the call should be skipped.
324 */
325template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600326bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
327 const ParameterName &arrayName, const char *sTypeName, uint32_t count, const T *array,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600328 VkStructureType sType, bool countRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600329 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700330
331 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600332 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600333 VALIDATION_ERROR_UNDEFINED, vuid);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700334 } else {
335 // Verify that all structs in the array have the correct type
336 for (uint32_t i = 0; i < count; ++i) {
337 if (array[i].sType != sType) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600338 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 -0600339 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
340 arrayName.get_name().c_str(), i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700341 }
342 }
343 }
344
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600345 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700346}
347
Dustin Graves58d114b2016-03-08 14:42:59 -0700348/**
Mark Young39389872017-01-19 21:10:49 -0700349 * Validate an array of Vulkan structures.
350 *
351 * Verify that required count and array parameters are not NULL. If count
352 * is not NULL and its value is not optional, verify that it is not 0.
353 * If the array contains 1 or more structures, verify that each structure's
354 * sType field is set to the correct VkStructureType value.
355 *
356 * @param report_data debug_report_data object for routing validation messages.
357 * @param apiName Name of API call being validated.
358 * @param countName Name of count parameter.
359 * @param arrayName Name of array parameter.
360 * @param sTypeName Name of expected VkStructureType value.
361 * @param count Pointer to the number of elements in the array.
362 * @param array Array to validate.
363 * @param sType VkStructureType for structure validation.
364 * @param countPtrRequired The 'count' parameter may not be NULL when true.
365 * @param countValueRequired The '*count' value may not be 0 when true.
366 * @param arrayRequired The 'array' parameter may not be NULL when true.
367 * @return Boolean value indicating that the call should be skipped.
368 */
369template <typename T>
370bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
371 const ParameterName &arrayName, const char *sTypeName, uint32_t *count, const T *array,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600372 VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired,
373 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Young39389872017-01-19 21:10:49 -0700374 bool skip_call = false;
375
376 if (count == NULL) {
377 if (countPtrRequired) {
378 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
379 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
380 countName.get_name().c_str());
381 }
382 } else {
383 skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600384 countValueRequired, arrayRequired, vuid);
Mark Young39389872017-01-19 21:10:49 -0700385 }
386
387 return skip_call;
388}
389
390/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600391* Validate a Vulkan handle.
392*
393* Verify that the specified handle is not VK_NULL_HANDLE.
394*
395* @param report_data debug_report_data object for routing validation messages.
396* @param api_name Name of API call being validated.
397* @param parameter_name Name of struct parameter being validated.
398* @param value Handle to validate.
399* @return Boolean value indicating that the call should be skipped.
400*/
401template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600402bool 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 -0600403 bool skip_call = false;
404
405 if (value == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600406 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
407 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600408 parameter_name.get_name().c_str());
Dustin Graves20fd66f2016-04-18 18:33:21 -0600409 }
410
411 return skip_call;
412}
413
414/**
415* Validate an array of Vulkan handles.
416*
417* Verify that required count and array parameters are not NULL. If count
418* is not NULL and its value is not optional, verify that it is not 0.
419* If the array contains 1 or more handles, verify that no handle is set to
420* VK_NULL_HANDLE.
421*
422* @note This function is only intended to validate arrays of handles when none
423* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
424* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
425*
426* @param report_data debug_report_data object for routing validation messages.
427* @param api_name Name of API call being validated.
428* @param count_name Name of count parameter.
429* @param array_name Name of array parameter.
430* @param count Number of elements in the array.
431* @param array Array to validate.
432* @param count_required The 'count' parameter may not be 0 when true.
433* @param array_required The 'array' parameter may not be NULL when true.
434* @return Boolean value indicating that the call should be skipped.
435*/
436template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600437bool validate_handle_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
438 const ParameterName &array_name, uint32_t count, const T *array, bool count_required,
439 bool array_required) {
Dustin Graves20fd66f2016-04-18 18:33:21 -0600440 bool skip_call = false;
441
442 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600443 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
444 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600445 } else {
446 // Verify that no handles in the array are VK_NULL_HANDLE
447 for (uint32_t i = 0; i < count; ++i) {
448 if (array[i] == VK_NULL_HANDLE) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600449 skip_call |=
450 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
451 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name,
452 array_name.get_name().c_str(), i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600453 }
454 }
455 }
456
457 return skip_call;
458}
459
460/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700461 * Validate string array count and content.
462 *
463 * Verify that required count and array parameters are not 0 or NULL. If the
464 * count parameter is not optional, verify that it is not 0. If the array
465 * parameter is NULL, and it is not optional, verify that count is 0. If the
466 * array parameter is not NULL, verify that none of the strings are NULL.
467 *
468 * @param report_data debug_report_data object for routing validation messages.
469 * @param apiName Name of API call being validated.
470 * @param countName Name of count parameter.
471 * @param arrayName Name of array parameter.
472 * @param count Number of strings in the array.
473 * @param array Array of strings to validate.
474 * @param countRequired The 'count' parameter may not be 0 when true.
475 * @param arrayRequired The 'array' parameter may not be NULL when true.
476 * @return Boolean value indicating that the call should be skipped.
477 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600478static bool validate_string_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
479 const ParameterName &arrayName, uint32_t count, const char *const *array, bool countRequired,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600480 bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
481 UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600482 bool skip_call = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700483
484 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600485 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
486 count_required_vuid, array_required_vuid);
Dustin Graves58d114b2016-03-08 14:42:59 -0700487 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600488 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700489 for (uint32_t i = 0; i < count; ++i) {
490 if (array[i] == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600491 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 -0600492 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
493 apiName, arrayName.get_name().c_str(), i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700494 }
495 }
496 }
497
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600498 return skip_call;
Dustin Graves58d114b2016-03-08 14:42:59 -0700499}
500
Dustin Graves58c2f662016-03-08 17:48:20 -0700501/**
502 * Validate a structure's pNext member.
503 *
504 * Verify that the specified pNext value points to the head of a list of
505 * allowed extension structures. If no extension structures are allowed,
506 * verify that pNext is null.
507 *
508 * @param report_data debug_report_data object for routing validation messages.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600509 * @param api_name Name of API call being validated.
510 * @param parameter_name Name of parameter being validated.
511 * @param allowed_struct_names Names of allowed structs.
Dustin Graves58c2f662016-03-08 17:48:20 -0700512 * @param next Pointer to validate.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600513 * @param allowed_type_count Total number of allowed structure types.
514 * @param allowed_types Array of strcuture types allowed for pNext.
515 * @param header_version Version of header defining the pNext validation rules.
Dustin Graves58c2f662016-03-08 17:48:20 -0700516 * @return Boolean value indicating that the call should be skipped.
517 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600518static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600519 const char *allowed_struct_names, const void *next, size_t allowed_type_count,
Mark Lobodzinski3c828522017-06-26 13:05:57 -0600520 const VkStructureType *allowed_types, uint32_t header_version,
521 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600522 bool skip_call = false;
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600523 std::unordered_set<const void *> cycle_check;
524 std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
525
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700526 const char disclaimer[] =
527 "This warning is based on the Valid Usage documentation for version %d of the Vulkan header. It "
528 "is possible that you are using a struct from a private extension or an extension that was added "
529 "to a later version of the Vulkan header, in which case your use of %s is perfectly valid but "
530 "is not guaranteed to work correctly with validation enabled";
Dustin Graves58c2f662016-03-08 17:48:20 -0700531
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600532 // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
533 // 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 -0700534 if (next != NULL) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600535 if (allowed_type_count == 0) {
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600536 std::string message = "%s: value of %s must be NULL. %s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600537 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600538 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 -0600539 vuid, LayerName, message.c_str(), api_name, parameter_name.get_name().c_str(),
540 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700541 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600542 const VkStructureType *start = allowed_types;
543 const VkStructureType *end = allowed_types + allowed_type_count;
Dustin Graves58c2f662016-03-08 17:48:20 -0700544 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
545
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600546 cycle_check.insert(next);
Dustin Graves58c2f662016-03-08 17:48:20 -0700547
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600548 while (current != NULL) {
549 if (cycle_check.find(current->pNext) != cycle_check.end()) {
550 std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
551 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
552 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
553 parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next));
554 break;
555 } else {
556 cycle_check.insert(current->pNext);
557 }
558
559 std::string type_name = string_VkStructureType(current->sType);
560 if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
561 std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
562 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
563 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
564 parameter_name.get_name().c_str(), type_name.c_str());
565 } else {
566 unique_stype_check.insert(current->sType);
567 }
568
569 if (std::find(start, end, current->sType) == end) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600570 if (type_name == UnsupportedStructureTypeString) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700571 std::string message =
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600572 "%s: %s chain includes a structure with unknown VkStructureType (%d); Allowed structures are [%s]. %s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600573 message += disclaimer;
574 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 -0600575 0, __LINE__, vuid, LayerName, message.c_str(), api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600576 parameter_name.get_name().c_str(), current->sType, allowed_struct_names,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600577 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700578 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600579 std::string message =
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600580 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]. "
581 "%s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600582 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600583 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 -0600584 0, __LINE__, vuid, LayerName, message.c_str(), api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600585 parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600586 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700587 }
588 }
Dustin Graves58c2f662016-03-08 17:48:20 -0700589 current = reinterpret_cast<const GenericHeader *>(current->pNext);
590 }
591 }
592 }
593
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600594 return skip_call;
Dustin Graves58c2f662016-03-08 17:48:20 -0700595}
596
Dustin Graves29148ff2016-03-23 19:44:00 -0600597/**
598* Validate a VkBool32 value.
599*
600* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
601*
602* @param report_data debug_report_data object for routing validation messages.
603* @param apiName Name of API call being validated.
604* @param parameterName Name of parameter being validated.
605* @param value Boolean value to validate.
606* @return Boolean value indicating that the call should be skipped.
607*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600608static bool validate_bool32(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
609 VkBool32 value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600610 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600611
612 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600613 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 -0600614 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
615 parameterName.get_name().c_str(), value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600616 }
617
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600618 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600619}
620
621/**
622* Validate a Vulkan enumeration value.
623*
624* Generate a warning if an enumeration token value does not fall within the core enumeration
625* begin and end token values, and was not added to the enumeration by an extension. Extension
626* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
627* with 1,000,000,000 as the base token value.
628*
629* @note This function does not expect to process enumerations defining bitmask flag bits.
630*
631* @param report_data debug_report_data object for routing validation messages.
632* @param apiName Name of API call being validated.
633* @param parameterName Name of parameter being validated.
634* @param enumName Name of the enumeration being validated.
Mark Lobodzinskiff9db7c2017-07-25 15:32:11 -0600635* @param valid_values The list of valid values for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600636* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600637* @return Boolean value indicating that the call should be skipped.
638*/
639template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600640bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinskib4d1ab72017-07-25 14:49:06 -0600641 const char *enumName, const std::vector<T> &valid_values, T value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
642 bool skip = false;
643
644 if (std::find(valid_values.begin(), valid_values.end(), value) == valid_values.end()) {
645 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
646 LayerName,
647 "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
648 "enumeration tokens and is not an extension added token. %s",
649 apiName, parameterName.get_name().c_str(), value, enumName, validation_error_map[vuid]);
650 }
651
652 return skip;
653}
654
Dustin Graves29148ff2016-03-23 19:44:00 -0600655/**
656* Validate an array of Vulkan enumeration value.
657*
658* Process all enumeration token values in the specified array and generate a warning if a value
659* does not fall within the core enumeration begin and end token values, and was not added to
660* the enumeration by an extension. Extension provided enumerations use the equation specified
661* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
662*
663* @note This function does not expect to process enumerations defining bitmask flag bits.
664*
665* @param report_data debug_report_data object for routing validation messages.
666* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600667* @param countName Name of count parameter.
668* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600669* @param enumName Name of the enumeration being validated.
Mark Lobodzinskiff9db7c2017-07-25 15:32:11 -0600670* @param valid_values The list of valid values for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600671* @param count Number of enumeration values in the array.
672* @param array Array of enumeration values to validate.
673* @param countRequired The 'count' parameter may not be 0 when true.
674* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600675* @return Boolean value indicating that the call should be skipped.
676*/
677template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600678static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
Mark Lobodzinskibd72bec2017-07-25 15:29:36 -0600679 const ParameterName &arrayName, const char *enumName, const std::vector<T> &valid_values,
680 uint32_t count, const T *array, bool countRequired, bool arrayRequired) {
681 bool skip_call = false;
682
683 if ((count == 0) || (array == NULL)) {
684 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
685 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
686 } else {
687 for (uint32_t i = 0; i < count; ++i) {
688 if (std::find(valid_values.begin(), valid_values.end(), array[i]) == valid_values.end()) {
689 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
690 __LINE__, UNRECOGNIZED_VALUE, LayerName,
691 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
692 "enumeration tokens and is not an extension added token",
693 apiName, arrayName.get_name().c_str(), i, array[i], enumName);
694 }
695 }
696 }
697
698 return skip_call;
699}
700
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600701/**
Dustin Graves78df8512016-04-28 17:58:59 -0600702* Verify that a reserved VkFlags value is zero.
703*
704* Verify that the specified value is zero, to check VkFlags values that are reserved for
705* future use.
706*
707* @param report_data debug_report_data object for routing validation messages.
708* @param api_name Name of API call being validated.
709* @param parameter_name Name of parameter being validated.
710* @param value Value to validate.
711* @return Boolean value indicating that the call should be skipped.
712*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600713static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Mark Lobodzinskid0b0c512017-06-28 12:06:41 -0600714 VkFlags value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Graves78df8512016-04-28 17:58:59 -0600715 bool skip_call = false;
716
717 if (value != 0) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600718 skip_call |=
719 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 -0600720 vuid, LayerName, "%s: parameter %s must be 0. %s", api_name, parameter_name.get_name().c_str(),
721 validation_error_map[vuid]);
Dustin Graves78df8512016-04-28 17:58:59 -0600722 }
723
724 return skip_call;
725}
726
727/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600728* Validate a Vulkan bitmask value.
729*
730* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
731* for that type.
732*
733* @param report_data debug_report_data object for routing validation messages.
734* @param api_name Name of API call being validated.
735* @param parameter_name Name of parameter being validated.
736* @param flag_bits_name Name of the VkFlags type being validated.
737* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
738* @param value VkFlags value to validate.
739* @param flags_required The 'value' parameter may not be 0 when true.
Mike Schuchardt47619c82017-05-31 09:14:22 -0600740* @param singleFlag The 'value' parameter may not contain more than one bit from all_flags.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600741* @return Boolean value indicating that the call should be skipped.
742*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600743static bool validate_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Mark Lobodzinskie643fcc2017-06-26 16:27:15 -0600744 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required, bool singleFlag,
745 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600746 bool skip_call = false;
747
748 if (value == 0) {
749 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600750 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 -0600751 vuid, LayerName, "%s: value of %s must not be 0. %s", api_name,
752 parameter_name.get_name().c_str(), validation_error_map[vuid]);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600753 }
754 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600755 skip_call |=
756 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
757 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600758 api_name, parameter_name.get_name().c_str(), flag_bits_name);
Mike Schuchardt47619c82017-05-31 09:14:22 -0600759 } else if (singleFlag && (std::bitset<sizeof(VkFlags) * 8>(value).count() > 1)) {
760 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
761 UNRECOGNIZED_VALUE, LayerName,
762 "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
763 parameter_name.get_name().c_str(), flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600764 }
765
766 return skip_call;
767}
768
769/**
770* Validate an array of Vulkan bitmask values.
771*
772* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
773* for that type.
774*
775* @param report_data debug_report_data object for routing validation messages.
776* @param api_name Name of API call being validated.
777* @param count_name Name of parameter being validated.
778* @param array_name Name of parameter being validated.
779* @param flag_bits_name Name of the VkFlags type being validated.
780* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
781* @param count Number of VkFlags values in the array.
782* @param array Array of VkFlags value to validate.
783* @param count_required The 'count' parameter may not be 0 when true.
784* @param array_required The 'array' parameter may not be NULL when true.
785* @return Boolean value indicating that the call should be skipped.
786*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600787static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
788 const ParameterName &array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
Dustin Graves78df8512016-04-28 17:58:59 -0600789 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600790 bool skip_call = false;
791
792 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600793 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
794 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600795 } else {
796 // Verify that all VkFlags values in the array
797 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600798 if (array[i] == 0) {
799 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
800 // elements in the array are allowed be 0
801 if (array_required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600802 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
803 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name,
804 array_name.get_name().c_str(), i);
Dustin Graves78df8512016-04-28 17:58:59 -0600805 }
806 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600807 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
808 __LINE__, UNRECOGNIZED_VALUE, LayerName,
809 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600810 array_name.get_name().c_str(), i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600811 }
812 }
813 }
814
815 return skip_call;
816}
817
818/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600819* Get VkResult code description.
820*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600821* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
822* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600823*
824* @param value VkResult code to process.
825* @return String describing the specified VkResult code.
826*/
827static std::string get_result_description(VkResult result) {
828 // clang-format off
829 switch (result) {
830 case VK_SUCCESS: return "a command completed successfully";
831 case VK_NOT_READY: return "a fence or query has not yet completed";
832 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
833 case VK_EVENT_SET: return "an event is signaled";
834 case VK_EVENT_RESET: return "an event is unsignalled";
835 case VK_INCOMPLETE: return "a return array was too small for the result";
836 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
837 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
Dustin Graves2adca842016-05-16 18:35:55 -0600838 case VK_ERROR_INITIALIZATION_FAILED: return "initialization of an object has failed";
839 case VK_ERROR_DEVICE_LOST: return "the logical device has been lost";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600840 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
841 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
842 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
843 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
844 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
845 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
846 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
847 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
848 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
849 "VkSurfaceKHR object, or some other non-Vulkan surface object";
850 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
851 "matches the surface properties exactly, but can still be used to "
852 "present to the surface successfully.";
853 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
854 "longer compatible with the swapchain";
855 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
856 "presentable image layout, or is incompatible in a way that prevents "
857 "sharing an image";
858 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
859 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100860 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600861 };
862 // clang-format on
863}
864
865/**
866* Validate return code.
867*
868* Print a message describing the reason for failure when an error code is returned.
869*
870* @param report_data debug_report_data object for routing validation messages.
871* @param apiName Name of API call being validated.
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600872* @param ignore vector of VkResult return codes to be ignored
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600873* @param value VkResult value to validate.
874*/
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600875static void validate_result(debug_report_data *report_data, const char *apiName, std::vector<VkResult> const &ignore,
876 VkResult result) {
Chris Forbesf1f4e382016-10-13 14:44:03 +1300877 if (result < 0 && result != VK_ERROR_VALIDATION_FAILED_EXT) {
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600878 if (std::find(ignore.begin(), ignore.end(), result) != ignore.end()) {
879 return;
880 }
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600881 std::string resultName = string_VkResult(result);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600882 if (resultName == UnsupportedResultString) {
883 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600884 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
885 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600886 } else {
887 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600888 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
889 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
890 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600891 }
892 }
893}
894
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700895} // namespace parameter_validation
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600896
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700897#endif // PARAMETER_VALIDATION_UTILS_H