blob: ced0810cae30ab7ae08f01e2fab6435df4544ca2 [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 Schuchardt52c3ce22017-12-13 09:45:36 -070027#include <sstream>
Mike Schuchardt47619c82017-05-31 09:14:22 -060028#include <bitset>
Petr Kraus595468a2017-09-10 02:26:33 +020029#include <mutex>
Petr Krause91f7a12017-12-14 20:57:36 +010030#include <unordered_map>
Mark Lobodzinski5cd08512017-09-12 09:50:25 -060031#include <unordered_set>
Dustin Graves58c2f662016-03-08 17:48:20 -070032
Dustin Graves1e92cd72016-02-09 14:00:18 -070033#include "vulkan/vulkan.h"
Dustin Graves58c2f662016-03-08 17:48:20 -070034#include "vk_enum_string_helper.h"
Dustin Graves1e92cd72016-02-09 14:00:18 -070035#include "vk_layer_logging.h"
Karl Schultza9ef1e52016-10-06 17:53:48 -060036#include "vk_validation_error_messages.h"
Mark Lobodzinski89cdf722017-06-01 15:09:55 -060037#include "vk_extension_helper.h"
Mark Lobodzinski944ec372017-05-30 14:21:21 -060038
Dustin Graves1e92cd72016-02-09 14:00:18 -070039
Dustin Graves8ffbbf62016-07-22 13:19:46 -060040#include "parameter_name.h"
41
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060042namespace parameter_validation {
43
Mark Lobodzinskid4950072017-08-01 13:02:20 -060044extern const uint32_t GeneratedHeaderVersion;
45extern const std::unordered_map<std::string, void*> name_to_funcptr_map;
46
47extern const VkQueryPipelineStatisticFlags AllVkQueryPipelineStatisticFlagBits;
48extern const VkColorComponentFlags AllVkColorComponentFlagBits;
49extern const VkShaderStageFlags AllVkShaderStageFlagBits;
50extern const VkQueryControlFlags AllVkQueryControlFlagBits;
51
52extern const std::vector<VkCompareOp> AllVkCompareOpEnums;
53extern const std::vector<VkStencilOp> AllVkStencilOpEnums;
54extern const std::vector<VkBlendFactor> AllVkBlendFactorEnums;
55extern const std::vector<VkBlendOp> AllVkBlendOpEnums;
56extern const std::vector<VkLogicOp> AllVkLogicOpEnums;
57extern const std::vector<VkBorderColor> AllVkBorderColorEnums;
58extern const std::vector<VkImageLayout> AllVkImageLayoutEnums;
59
Mark Lobodzinski944ec372017-05-30 14:21:21 -060060struct instance_layer_data {
61 VkInstance instance = VK_NULL_HANDLE;
62
63 debug_report_data *report_data = nullptr;
64 std::vector<VkDebugReportCallbackEXT> logging_callback;
65
66 // The following are for keeping track of the temporary callbacks that can
67 // be used in vkCreateInstance and vkDestroyInstance:
68 uint32_t num_tmp_callbacks = 0;
69 VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos = nullptr;
70 VkDebugReportCallbackEXT *tmp_callbacks = nullptr;
71 InstanceExtensions extensions = {};
Mark Lobodzinski944ec372017-05-30 14:21:21 -060072 VkLayerInstanceDispatchTable dispatch_table = {};
73};
74
75struct layer_data {
76 debug_report_data *report_data = nullptr;
77 // Map for queue family index to queue count
78 std::unordered_map<uint32_t, uint32_t> queueFamilyIndexMap;
79 VkPhysicalDeviceLimits device_limits = {};
80 VkPhysicalDeviceFeatures physical_device_features = {};
81 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
82 VkDevice device = VK_NULL_HANDLE;
Mark Lobodzinskib8626db2017-06-01 08:44:53 -060083 DeviceExtensions extensions;
Mark Lobodzinski944ec372017-05-30 14:21:21 -060084
Petr Krause91f7a12017-12-14 20:57:36 +010085 struct SubpassesUsageStates {
86 std::unordered_set<uint32_t> subpasses_using_color_attachment;
87 std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
88 };
89
90 std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
91
Mark Lobodzinski944ec372017-05-30 14:21:21 -060092 VkLayerDispatchTable dispatch_table = {};
93};
94
Dustin Gravesf233e502016-05-05 13:44:21 -060095enum ErrorCode {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070096 NONE, // Used for INFO & other non-error messages
97 INVALID_USAGE, // The value of a parameter is not consistent
98 // with the valid usage criteria defined in
99 // the Vulkan specification.
100 INVALID_STRUCT_STYPE, // The sType field of a Vulkan structure does
101 // not contain the value expected for a structure
102 // of that type.
103 INVALID_STRUCT_PNEXT, // The pNext field of a Vulkan structure references
104 // a value that is not compatible with a structure of
105 // that type or is not NULL when a structure of that
106 // type has no compatible pNext values.
107 REQUIRED_PARAMETER, // A required parameter was specified as 0 or NULL.
108 RESERVED_PARAMETER, // A parameter reserved for future use was not
109 // specified as 0 or NULL.
110 UNRECOGNIZED_VALUE, // A Vulkan enumeration, VkFlags, or VkBool32 parameter
111 // contains a value that is not recognized as valid for
112 // that type.
113 DEVICE_LIMIT, // A specified parameter exceeds the limits returned
114 // by the physical device
115 DEVICE_FEATURE, // Use of a requested feature is not supported by
116 // the device
117 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
118 // was encountered.
119 EXTENSION_NOT_ENABLED, // An extension entrypoint was called, but the required
120 // extension was not enabled at CreateInstance or
121 // CreateDevice time.
Dustin Gravesf233e502016-05-05 13:44:21 -0600122};
123
Dustin Graves58c2f662016-03-08 17:48:20 -0700124struct GenericHeader {
125 VkStructureType sType;
126 const void *pNext;
127};
Dustin Graves58c2f662016-03-08 17:48:20 -0700128
Dustin Graves29148ff2016-03-23 19:44:00 -0600129// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600130const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -0600131
132// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -0700133const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
134
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600135// String returned by string_VkResult for an unrecognized type.
136const std::string UnsupportedResultString = "Unhandled VkResult";
137
Dustin Graves29148ff2016-03-23 19:44:00 -0600138// The base value used when computing the offset for an enumeration token value that is added by an extension.
139// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
140// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
141const uint32_t ExtEnumBaseValue = 1000000000;
142
Cort Strattonedbe9b82017-05-16 07:38:35 -0700143// The value of all VK_xxx_MAX_ENUM tokens
144const uint32_t MaxEnumValue = 0x7FFFFFFF;
145
Mark Lobodzinski26112592017-05-30 12:02:17 -0600146
Dustin Graves1e92cd72016-02-09 14:00:18 -0700147/**
Dustin Gravesf8032f22016-05-11 18:31:44 -0600148* Validate a minimum value.
149*
150* Verify that the specified value is greater than the specified lower bound.
151*
152* @param report_data debug_report_data object for routing validation messages.
153* @param api_name Name of API call being validated.
154* @param parameter_name Name of parameter being validated.
155* @param value Value to validate.
156* @param lower_bound Lower bound value to use for validation.
157* @return Boolean value indicating that the call should be skipped.
158*/
159template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600160bool ValidateGreaterThan(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, T value,
161 T lower_bound) {
Dustin Gravesf8032f22016-05-11 18:31:44 -0600162 bool skip_call = false;
163
164 if (value <= lower_bound) {
Mike Schuchardt52c3ce22017-12-13 09:45:36 -0700165 std::ostringstream ss;
166 ss << api_name << ": parameter " << parameter_name.get_name() << " is " << value << " but must be greater than "
167 << lower_bound;
168 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, 1,
169 LayerName, "%s", ss.str().c_str());
Dustin Gravesf8032f22016-05-11 18:31:44 -0600170 }
171
172 return skip_call;
173}
174
175/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700176 * Validate a required pointer.
177 *
Dustin Graves58c2f662016-03-08 17:48:20 -0700178 * Verify that a required pointer is not NULL.
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 parameterName Name of parameter being validated.
183 * @param value Pointer to validate.
184 * @return Boolean value indicating that the call should be skipped.
185 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600186static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinskidead0b62017-06-28 13:22:03 -0600187 const void *value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600188 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700189
190 if (value == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600191 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 -0600192 vuid, LayerName, "%s: required parameter %s specified as NULL. %s", apiName,
193 parameterName.get_name().c_str(), validation_error_map[vuid]);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700194 }
195
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600196 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700197}
198
199/**
200 * Validate array count and pointer to array.
201 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700202 * Verify that required count and array parameters are not 0 or NULL. If the
203 * count parameter is not optional, verify that it is not 0. If the array
204 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700205 *
206 * @param report_data debug_report_data object for routing validation messages.
207 * @param apiName Name of API call being validated.
208 * @param countName Name of count parameter.
209 * @param arrayName Name of array parameter.
210 * @param count Number of elements in the array.
211 * @param array Array to validate.
212 * @param countRequired The 'count' parameter may not be 0 when true.
213 * @param arrayRequired The 'array' parameter may not be NULL when true.
214 * @return Boolean value indicating that the call should be skipped.
215 */
216template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600217bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600218 const ParameterName &arrayName, T count, const void *array, bool countRequired, bool arrayRequired,
219 UNIQUE_VALIDATION_ERROR_CODE count_required_vuid, UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600220 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700221
222 // Count parameters not tagged as optional cannot be 0
Józef Kucia20bb8fb2016-09-23 12:45:04 +0200223 if (countRequired && (count == 0)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600224 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 -0600225 count_required_vuid, LayerName, "%s: parameter %s must be greater than 0. %s", apiName,
226 countName.get_name().c_str(), validation_error_map[count_required_vuid]);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700227 }
228
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600229 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600230 if ((array == NULL) && arrayRequired && (count != 0)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600231 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 -0600232 array_required_vuid, LayerName, "%s: required parameter %s specified as NULL. %s", apiName,
233 arrayName.get_name().c_str(), validation_error_map[array_required_vuid]);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600234 }
235
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600236 return skip_call;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600237}
238
239/**
240* Validate pointer to array count and pointer to array.
241*
242* Verify that required count and array parameters are not NULL. If count
243* is not NULL and its value is not optional, verify that it is not 0. If the
244* array parameter is NULL, and it is not optional, verify that count is 0.
245* The array parameter will typically be optional for this case (where count is
246* a pointer), allowing the caller to retrieve the available count.
247*
248* @param report_data debug_report_data object for routing validation messages.
249* @param apiName Name of API call being validated.
250* @param countName Name of count parameter.
251* @param arrayName Name of array parameter.
252* @param count Pointer to the number of elements in the array.
253* @param array Array to validate.
254* @param countPtrRequired The 'count' parameter may not be NULL when true.
255* @param countValueRequired The '*count' value may not be 0 when true.
256* @param arrayRequired The 'array' parameter may not be NULL when true.
257* @return Boolean value indicating that the call should be skipped.
258*/
259template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600260bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
261 const ParameterName &arrayName, const T *count, const void *array, bool countPtrRequired,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600262 bool countValueRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
263 UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600264 bool skip_call = false;
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600265
266 if (count == NULL) {
267 if (countPtrRequired) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600268 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 -0600269 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
270 countName.get_name().c_str());
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600271 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700272 } else {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600273 skip_call |= validate_array(report_data, apiName, countName, arrayName, array ? (*count) : 0, array, countValueRequired,
274 arrayRequired, count_required_vuid, array_required_vuid);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700275 }
276
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600277 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700278}
279
280/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600281 * Validate a pointer to a Vulkan structure.
282 *
283 * Verify that a required pointer to a structure is not NULL. If the pointer is
284 * not NULL, verify that each structure's sType field is set to the correct
285 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700286 *
287 * @param report_data debug_report_data object for routing validation messages.
288 * @param apiName Name of API call being validated.
289 * @param parameterName Name of struct parameter being validated.
290 * @param sTypeName Name of expected VkStructureType value.
291 * @param value Pointer to the struct to validate.
292 * @param sType VkStructureType for structure validation.
293 * @param required The parameter may not be NULL when true.
294 * @return Boolean value indicating that the call should be skipped.
295 */
296template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600297bool validate_struct_type(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600298 const char *sTypeName, const T *value, VkStructureType sType, bool required,
299 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600300 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700301
302 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600303 if (required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600304 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
305 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
306 parameterName.get_name().c_str());
Dustin Graves1e92cd72016-02-09 14:00:18 -0700307 }
308 } else if (value->sType != sType) {
Mark Lobodzinski06954ea2017-06-21 12:21:45 -0600309 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
310 LayerName, "%s: parameter %s->sType must be %s. %s", apiName, parameterName.get_name().c_str(),
311 sTypeName, validation_error_map[vuid]);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700312 }
313
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600314 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700315}
316
317/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700318 * Validate an array of Vulkan structures
319 *
320 * Verify that required count and array parameters are not 0 or NULL. If
321 * the array contains 1 or more structures, verify that each structure's
322 * sType field is set to the correct VkStructureType value.
323 *
324 * @param report_data debug_report_data object for routing validation messages.
325 * @param apiName Name of API call being validated.
326 * @param countName Name of count parameter.
327 * @param arrayName Name of array parameter.
328 * @param sTypeName Name of expected VkStructureType value.
329 * @param count Number of elements in the array.
330 * @param array Array to validate.
331 * @param sType VkStructureType for structure validation.
332 * @param countRequired The 'count' parameter may not be 0 when true.
333 * @param arrayRequired The 'array' parameter may not be NULL when true.
334 * @return Boolean value indicating that the call should be skipped.
335 */
336template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600337bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
338 const ParameterName &arrayName, const char *sTypeName, uint32_t count, const T *array,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600339 VkStructureType sType, bool countRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600340 bool skip_call = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700341
342 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600343 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600344 VALIDATION_ERROR_UNDEFINED, vuid);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700345 } else {
346 // Verify that all structs in the array have the correct type
347 for (uint32_t i = 0; i < count; ++i) {
348 if (array[i].sType != sType) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600349 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 -0600350 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
351 arrayName.get_name().c_str(), i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700352 }
353 }
354 }
355
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600356 return skip_call;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700357}
358
Dustin Graves58d114b2016-03-08 14:42:59 -0700359/**
Mark Young39389872017-01-19 21:10:49 -0700360 * Validate an array of Vulkan structures.
361 *
362 * Verify that required count and array parameters are not NULL. If count
363 * is not NULL and its value is not optional, verify that it is not 0.
364 * If the array contains 1 or more structures, verify that each structure's
365 * sType field is set to the correct VkStructureType value.
366 *
367 * @param report_data debug_report_data object for routing validation messages.
368 * @param apiName Name of API call being validated.
369 * @param countName Name of count parameter.
370 * @param arrayName Name of array parameter.
371 * @param sTypeName Name of expected VkStructureType value.
372 * @param count Pointer to the number of elements in the array.
373 * @param array Array to validate.
374 * @param sType VkStructureType for structure validation.
375 * @param countPtrRequired The 'count' parameter may not be NULL when true.
376 * @param countValueRequired The '*count' value may not be 0 when true.
377 * @param arrayRequired The 'array' parameter may not be NULL when true.
378 * @return Boolean value indicating that the call should be skipped.
379 */
380template <typename T>
381bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
382 const ParameterName &arrayName, const char *sTypeName, uint32_t *count, const T *array,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600383 VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired,
384 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Mark Young39389872017-01-19 21:10:49 -0700385 bool skip_call = false;
386
387 if (count == NULL) {
388 if (countPtrRequired) {
389 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
390 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
391 countName.get_name().c_str());
392 }
393 } else {
394 skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
Mark Lobodzinski9cf24dd2017-06-28 14:23:22 -0600395 countValueRequired, arrayRequired, vuid);
Mark Young39389872017-01-19 21:10:49 -0700396 }
397
398 return skip_call;
399}
400
401/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600402* Validate a Vulkan handle.
403*
404* Verify that the specified handle is not VK_NULL_HANDLE.
405*
406* @param report_data debug_report_data object for routing validation messages.
407* @param api_name Name of API call being validated.
408* @param parameter_name Name of struct parameter being validated.
409* @param value Handle to validate.
410* @return Boolean value indicating that the call should be skipped.
411*/
412template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600413bool 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 -0600414 bool skip_call = false;
415
416 if (value == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600417 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
418 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600419 parameter_name.get_name().c_str());
Dustin Graves20fd66f2016-04-18 18:33:21 -0600420 }
421
422 return skip_call;
423}
424
425/**
426* Validate an array of Vulkan handles.
427*
428* Verify that required count and array parameters are not NULL. If count
429* is not NULL and its value is not optional, verify that it is not 0.
430* If the array contains 1 or more handles, verify that no handle is set to
431* VK_NULL_HANDLE.
432*
433* @note This function is only intended to validate arrays of handles when none
434* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
435* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
436*
437* @param report_data debug_report_data object for routing validation messages.
438* @param api_name Name of API call being validated.
439* @param count_name Name of count parameter.
440* @param array_name Name of array parameter.
441* @param count Number of elements in the array.
442* @param array Array to validate.
443* @param count_required The 'count' parameter may not be 0 when true.
444* @param array_required The 'array' parameter may not be NULL when true.
445* @return Boolean value indicating that the call should be skipped.
446*/
447template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600448bool validate_handle_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
449 const ParameterName &array_name, uint32_t count, const T *array, bool count_required,
450 bool array_required) {
Dustin Graves20fd66f2016-04-18 18:33:21 -0600451 bool skip_call = false;
452
453 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600454 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
455 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600456 } else {
457 // Verify that no handles in the array are VK_NULL_HANDLE
458 for (uint32_t i = 0; i < count; ++i) {
459 if (array[i] == VK_NULL_HANDLE) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600460 skip_call |=
461 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
462 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name,
463 array_name.get_name().c_str(), i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600464 }
465 }
466 }
467
468 return skip_call;
469}
470
471/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700472 * Validate string array count and content.
473 *
474 * Verify that required count and array parameters are not 0 or NULL. If the
475 * count parameter is not optional, verify that it is not 0. If the array
476 * parameter is NULL, and it is not optional, verify that count is 0. If the
477 * array parameter is not NULL, verify that none of the strings are NULL.
478 *
479 * @param report_data debug_report_data object for routing validation messages.
480 * @param apiName Name of API call being validated.
481 * @param countName Name of count parameter.
482 * @param arrayName Name of array parameter.
483 * @param count Number of strings in the array.
484 * @param array Array of strings to validate.
485 * @param countRequired The 'count' parameter may not be 0 when true.
486 * @param arrayRequired The 'array' parameter may not be NULL when true.
487 * @return Boolean value indicating that the call should be skipped.
488 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600489static bool validate_string_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
490 const ParameterName &arrayName, uint32_t count, const char *const *array, bool countRequired,
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600491 bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
492 UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600493 bool skip_call = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700494
495 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600496 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
497 count_required_vuid, array_required_vuid);
Dustin Graves58d114b2016-03-08 14:42:59 -0700498 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600499 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700500 for (uint32_t i = 0; i < count; ++i) {
501 if (array[i] == NULL) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600502 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 -0600503 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
504 apiName, arrayName.get_name().c_str(), i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700505 }
506 }
507 }
508
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600509 return skip_call;
Dustin Graves58d114b2016-03-08 14:42:59 -0700510}
511
Dustin Graves58c2f662016-03-08 17:48:20 -0700512/**
513 * Validate a structure's pNext member.
514 *
515 * Verify that the specified pNext value points to the head of a list of
516 * allowed extension structures. If no extension structures are allowed,
517 * verify that pNext is null.
518 *
519 * @param report_data debug_report_data object for routing validation messages.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600520 * @param api_name Name of API call being validated.
521 * @param parameter_name Name of parameter being validated.
522 * @param allowed_struct_names Names of allowed structs.
Dustin Graves58c2f662016-03-08 17:48:20 -0700523 * @param next Pointer to validate.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600524 * @param allowed_type_count Total number of allowed structure types.
525 * @param allowed_types Array of strcuture types allowed for pNext.
526 * @param header_version Version of header defining the pNext validation rules.
Dustin Graves58c2f662016-03-08 17:48:20 -0700527 * @return Boolean value indicating that the call should be skipped.
528 */
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600529static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600530 const char *allowed_struct_names, const void *next, size_t allowed_type_count,
Mark Lobodzinski3c828522017-06-26 13:05:57 -0600531 const VkStructureType *allowed_types, uint32_t header_version,
532 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600533 bool skip_call = false;
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600534 std::unordered_set<const void *> cycle_check;
535 std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
536
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700537 const char disclaimer[] =
538 "This warning is based on the Valid Usage documentation for version %d of the Vulkan header. It "
539 "is possible that you are using a struct from a private extension or an extension that was added "
540 "to a later version of the Vulkan header, in which case your use of %s is perfectly valid but "
541 "is not guaranteed to work correctly with validation enabled";
Dustin Graves58c2f662016-03-08 17:48:20 -0700542
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600543 // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
544 // 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 -0700545 if (next != NULL) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600546 if (allowed_type_count == 0) {
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600547 std::string message = "%s: value of %s must be NULL. %s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600548 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600549 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 -0600550 vuid, LayerName, message.c_str(), api_name, parameter_name.get_name().c_str(),
551 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700552 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600553 const VkStructureType *start = allowed_types;
554 const VkStructureType *end = allowed_types + allowed_type_count;
Dustin Graves58c2f662016-03-08 17:48:20 -0700555 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
556
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600557 cycle_check.insert(next);
Dustin Graves58c2f662016-03-08 17:48:20 -0700558
Mark Lobodzinskic9b74d32017-03-27 11:52:02 -0600559 while (current != NULL) {
560 if (cycle_check.find(current->pNext) != cycle_check.end()) {
561 std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
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(), reinterpret_cast<uint64_t>(next));
565 break;
566 } else {
567 cycle_check.insert(current->pNext);
568 }
569
570 std::string type_name = string_VkStructureType(current->sType);
571 if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
572 std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
573 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
574 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
575 parameter_name.get_name().c_str(), type_name.c_str());
576 } else {
577 unique_stype_check.insert(current->sType);
578 }
579
580 if (std::find(start, end, current->sType) == end) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600581 if (type_name == UnsupportedStructureTypeString) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700582 std::string message =
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600583 "%s: %s chain includes a structure with unknown VkStructureType (%d); Allowed structures are [%s]. %s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600584 message += disclaimer;
585 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 -0600586 0, __LINE__, vuid, LayerName, message.c_str(), api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600587 parameter_name.get_name().c_str(), current->sType, allowed_struct_names,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600588 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700589 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600590 std::string message =
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600591 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]. "
592 "%s ";
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600593 message += disclaimer;
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600594 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 -0600595 0, __LINE__, vuid, LayerName, message.c_str(), api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600596 parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names,
Mark Lobodzinskia1400e12017-06-26 14:03:16 -0600597 validation_error_map[vuid], header_version, parameter_name.get_name().c_str());
Dustin Graves58c2f662016-03-08 17:48:20 -0700598 }
599 }
Dustin Graves58c2f662016-03-08 17:48:20 -0700600 current = reinterpret_cast<const GenericHeader *>(current->pNext);
601 }
602 }
603 }
604
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600605 return skip_call;
Dustin Graves58c2f662016-03-08 17:48:20 -0700606}
607
Dustin Graves29148ff2016-03-23 19:44:00 -0600608/**
609* Validate a VkBool32 value.
610*
611* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
612*
613* @param report_data debug_report_data object for routing validation messages.
614* @param apiName Name of API call being validated.
615* @param parameterName Name of parameter being validated.
616* @param value Boolean value to validate.
617* @return Boolean value indicating that the call should be skipped.
618*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600619static bool validate_bool32(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
620 VkBool32 value) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600621 bool skip_call = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600622
623 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600624 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 -0600625 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
626 parameterName.get_name().c_str(), value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600627 }
628
Mark Lobodzinski72ecd912016-08-11 13:25:38 -0600629 return skip_call;
Dustin Graves29148ff2016-03-23 19:44:00 -0600630}
631
632/**
633* Validate a Vulkan enumeration value.
634*
635* Generate a warning if an enumeration token value does not fall within the core enumeration
636* begin and end token values, and was not added to the enumeration by an extension. Extension
637* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
638* with 1,000,000,000 as the base token value.
639*
640* @note This function does not expect to process enumerations defining bitmask flag bits.
641*
642* @param report_data debug_report_data object for routing validation messages.
643* @param apiName Name of API call being validated.
644* @param parameterName Name of parameter being validated.
645* @param enumName Name of the enumeration being validated.
Mark Lobodzinskiff9db7c2017-07-25 15:32:11 -0600646* @param valid_values The list of valid values for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600647* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600648* @return Boolean value indicating that the call should be skipped.
649*/
650template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600651bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
Mark Lobodzinskib4d1ab72017-07-25 14:49:06 -0600652 const char *enumName, const std::vector<T> &valid_values, T value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
653 bool skip = false;
654
655 if (std::find(valid_values.begin(), valid_values.end(), value) == valid_values.end()) {
656 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, vuid,
657 LayerName,
658 "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
659 "enumeration tokens and is not an extension added token. %s",
660 apiName, parameterName.get_name().c_str(), value, enumName, validation_error_map[vuid]);
661 }
662
663 return skip;
664}
665
Dustin Graves29148ff2016-03-23 19:44:00 -0600666/**
667* Validate an array of Vulkan enumeration value.
668*
669* Process all enumeration token values in the specified array and generate a warning if a value
670* does not fall within the core enumeration begin and end token values, and was not added to
671* the enumeration by an extension. Extension provided enumerations use the equation specified
672* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
673*
674* @note This function does not expect to process enumerations defining bitmask flag bits.
675*
676* @param report_data debug_report_data object for routing validation messages.
677* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600678* @param countName Name of count parameter.
679* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600680* @param enumName Name of the enumeration being validated.
Mark Lobodzinskiff9db7c2017-07-25 15:32:11 -0600681* @param valid_values The list of valid values for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600682* @param count Number of enumeration values in the array.
683* @param array Array of enumeration values to validate.
684* @param countRequired The 'count' parameter may not be 0 when true.
685* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600686* @return Boolean value indicating that the call should be skipped.
687*/
688template <typename T>
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600689static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
Mark Lobodzinskibd72bec2017-07-25 15:29:36 -0600690 const ParameterName &arrayName, const char *enumName, const std::vector<T> &valid_values,
691 uint32_t count, const T *array, bool countRequired, bool arrayRequired) {
692 bool skip_call = false;
693
694 if ((count == 0) || (array == NULL)) {
695 skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
696 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
697 } else {
698 for (uint32_t i = 0; i < count; ++i) {
699 if (std::find(valid_values.begin(), valid_values.end(), array[i]) == valid_values.end()) {
700 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
701 __LINE__, UNRECOGNIZED_VALUE, LayerName,
702 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
703 "enumeration tokens and is not an extension added token",
704 apiName, arrayName.get_name().c_str(), i, array[i], enumName);
705 }
706 }
707 }
708
709 return skip_call;
710}
711
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600712/**
Dustin Graves78df8512016-04-28 17:58:59 -0600713* Verify that a reserved VkFlags value is zero.
714*
715* Verify that the specified value is zero, to check VkFlags values that are reserved for
716* future use.
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 value Value to validate.
722* @return Boolean value indicating that the call should be skipped.
723*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600724static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Mark Lobodzinskid0b0c512017-06-28 12:06:41 -0600725 VkFlags value, UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Graves78df8512016-04-28 17:58:59 -0600726 bool skip_call = false;
727
728 if (value != 0) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600729 skip_call |=
730 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 -0600731 vuid, LayerName, "%s: parameter %s must be 0. %s", api_name, parameter_name.get_name().c_str(),
732 validation_error_map[vuid]);
Dustin Graves78df8512016-04-28 17:58:59 -0600733 }
734
735 return skip_call;
736}
737
738/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600739* Validate a Vulkan bitmask value.
740*
741* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
742* for that type.
743*
744* @param report_data debug_report_data object for routing validation messages.
745* @param api_name Name of API call being validated.
746* @param parameter_name Name of parameter being validated.
747* @param flag_bits_name Name of the VkFlags type being validated.
748* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
749* @param value VkFlags value to validate.
750* @param flags_required The 'value' parameter may not be 0 when true.
Mike Schuchardt47619c82017-05-31 09:14:22 -0600751* @param singleFlag The 'value' parameter may not contain more than one bit from all_flags.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600752* @return Boolean value indicating that the call should be skipped.
753*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600754static bool validate_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
Mark Lobodzinskie643fcc2017-06-26 16:27:15 -0600755 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required, bool singleFlag,
756 UNIQUE_VALIDATION_ERROR_CODE vuid) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600757 bool skip_call = false;
758
759 if (value == 0) {
760 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600761 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 -0600762 vuid, LayerName, "%s: value of %s must not be 0. %s", api_name,
763 parameter_name.get_name().c_str(), validation_error_map[vuid]);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600764 }
765 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600766 skip_call |=
767 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
768 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600769 api_name, parameter_name.get_name().c_str(), flag_bits_name);
Mike Schuchardt47619c82017-05-31 09:14:22 -0600770 } else if (singleFlag && (std::bitset<sizeof(VkFlags) * 8>(value).count() > 1)) {
771 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
772 UNRECOGNIZED_VALUE, LayerName,
773 "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
774 parameter_name.get_name().c_str(), flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600775 }
776
777 return skip_call;
778}
779
780/**
781* Validate an array of Vulkan bitmask values.
782*
783* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
784* for that type.
785*
786* @param report_data debug_report_data object for routing validation messages.
787* @param api_name Name of API call being validated.
788* @param count_name Name of parameter being validated.
789* @param array_name Name of parameter being validated.
790* @param flag_bits_name Name of the VkFlags type being validated.
791* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
792* @param count Number of VkFlags values in the array.
793* @param array Array of VkFlags value to validate.
794* @param count_required The 'count' parameter may not be 0 when true.
795* @param array_required The 'array' parameter may not be NULL when true.
796* @return Boolean value indicating that the call should be skipped.
797*/
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600798static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
799 const ParameterName &array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
Dustin Graves78df8512016-04-28 17:58:59 -0600800 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600801 bool skip_call = false;
802
803 if ((count == 0) || (array == NULL)) {
Mark Lobodzinski1e707bd2017-06-28 10:54:55 -0600804 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
805 VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600806 } else {
807 // Verify that all VkFlags values in the array
808 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600809 if (array[i] == 0) {
810 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
811 // elements in the array are allowed be 0
812 if (array_required) {
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600813 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
814 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name,
815 array_name.get_name().c_str(), i);
Dustin Graves78df8512016-04-28 17:58:59 -0600816 }
817 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600818 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
819 __LINE__, UNRECOGNIZED_VALUE, LayerName,
820 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
Dustin Graves8ffbbf62016-07-22 13:19:46 -0600821 array_name.get_name().c_str(), i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600822 }
823 }
824 }
825
826 return skip_call;
827}
828
829/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600830* Get VkResult code description.
831*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600832* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
833* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600834*
835* @param value VkResult code to process.
836* @return String describing the specified VkResult code.
837*/
838static std::string get_result_description(VkResult result) {
839 // clang-format off
840 switch (result) {
841 case VK_SUCCESS: return "a command completed successfully";
842 case VK_NOT_READY: return "a fence or query has not yet completed";
843 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
844 case VK_EVENT_SET: return "an event is signaled";
845 case VK_EVENT_RESET: return "an event is unsignalled";
846 case VK_INCOMPLETE: return "a return array was too small for the result";
847 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
848 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
Dustin Graves2adca842016-05-16 18:35:55 -0600849 case VK_ERROR_INITIALIZATION_FAILED: return "initialization of an object has failed";
850 case VK_ERROR_DEVICE_LOST: return "the logical device has been lost";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600851 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
852 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
853 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
854 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
855 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
856 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
857 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
858 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
859 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
860 "VkSurfaceKHR object, or some other non-Vulkan surface object";
861 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
862 "matches the surface properties exactly, but can still be used to "
863 "present to the surface successfully.";
864 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
865 "longer compatible with the swapchain";
866 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
867 "presentable image layout, or is incompatible in a way that prevents "
868 "sharing an image";
869 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
870 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100871 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600872 };
873 // clang-format on
874}
875
876/**
877* Validate return code.
878*
879* Print a message describing the reason for failure when an error code is returned.
880*
881* @param report_data debug_report_data object for routing validation messages.
882* @param apiName Name of API call being validated.
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600883* @param ignore vector of VkResult return codes to be ignored
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600884* @param value VkResult value to validate.
885*/
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600886static void validate_result(debug_report_data *report_data, const char *apiName, std::vector<VkResult> const &ignore,
887 VkResult result) {
Chris Forbesf1f4e382016-10-13 14:44:03 +1300888 if (result < 0 && result != VK_ERROR_VALIDATION_FAILED_EXT) {
Mark Lobodzinskib42e51b2017-05-09 13:49:59 -0600889 if (std::find(ignore.begin(), ignore.end(), result) != ignore.end()) {
890 return;
891 }
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600892 std::string resultName = string_VkResult(result);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600893 if (resultName == UnsupportedResultString) {
894 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600895 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
896 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600897 } else {
898 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600899 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
900 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
901 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600902 }
903 }
904}
905
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700906} // namespace parameter_validation
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600907
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700908#endif // PARAMETER_VALIDATION_UTILS_H