blob: effd0530c569fde4ffd36c98e144e77f8c5559de [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>
27
Dustin Graves1e92cd72016-02-09 14:00:18 -070028#include "vulkan/vulkan.h"
Dustin Graves58c2f662016-03-08 17:48:20 -070029#include "vk_enum_string_helper.h"
Dustin Graves1e92cd72016-02-09 14:00:18 -070030#include "vk_layer_logging.h"
31
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060032namespace parameter_validation {
33
Dustin Gravesf233e502016-05-05 13:44:21 -060034enum ErrorCode {
35 NONE, // Used for INFO & other non-error messages
36 INVALID_USAGE, // The value of a parameter is not consistent
37 // with the valid usage criteria defined in
38 // the Vulkan specification.
39 INVALID_STRUCT_STYPE, // The sType field of a Vulkan structure does
40 // not contain the value expected for a structure
41 // of that type.
42 INVALID_STRUCT_PNEXT, // The pNext field of a Vulkan structure references
43 // a value that is not compatible with a structure of
44 // that type or is not NULL when a structure of that
45 // type has no compatible pNext values.
46 REQUIRED_PARAMETER, // A required parameter was specified as 0 or NULL.
47 RESERVED_PARAMETER, // A parameter reserved for future use was not
48 // specified as 0 or NULL.
49 UNRECOGNIZED_VALUE, // A Vulkan enumeration, VkFlags, or VkBool32 parameter
50 // contains a value that is not recognized as valid for
51 // that type.
52 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
53 // was encountered.
54};
55
Dustin Graves58c2f662016-03-08 17:48:20 -070056struct GenericHeader {
57 VkStructureType sType;
58 const void *pNext;
59};
Dustin Graves58c2f662016-03-08 17:48:20 -070060
Dustin Graves29148ff2016-03-23 19:44:00 -060061// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060062const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -060063
64// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -070065const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
66
Dustin Gravesca7aa7c2016-03-25 15:13:28 -060067// String returned by string_VkResult for an unrecognized type.
68const std::string UnsupportedResultString = "Unhandled VkResult";
69
Dustin Graves29148ff2016-03-23 19:44:00 -060070// The base value used when computing the offset for an enumeration token value that is added by an extension.
71// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
72// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
73const uint32_t ExtEnumBaseValue = 1000000000;
74
75template <typename T> bool is_extension_added_token(T value) {
76 return (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
77}
78
79// VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE token is a special case that was converted from a core token to an
80// extension added token. Its original value was intentionally preserved after the conversion, so it does not use
81// the base value that other extension added tokens use, and it does not fall within the enum's begin/end range.
82template <> bool is_extension_added_token(VkSamplerAddressMode value) {
83 bool result = (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
84 return (result || (value == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE));
85}
86
Dustin Graves1e92cd72016-02-09 14:00:18 -070087/**
Dustin Gravesf8032f22016-05-11 18:31:44 -060088* Validate a minimum value.
89*
90* Verify that the specified value is greater than the specified lower bound.
91*
92* @param report_data debug_report_data object for routing validation messages.
93* @param api_name Name of API call being validated.
94* @param parameter_name Name of parameter being validated.
95* @param value Value to validate.
96* @param lower_bound Lower bound value to use for validation.
97* @return Boolean value indicating that the call should be skipped.
98*/
99template <typename T>
100bool ValidateGreaterThan(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value,
101 T lower_bound) {
102 bool skip_call = false;
103
104 if (value <= lower_bound) {
105 skip_call |=
106 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
107 LayerName, "%s: parameter %s must be greater than %d", api_name, parameter_name, lower_bound);
108 }
109
110 return skip_call;
111}
112
113/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700114 * Validate a required pointer.
115 *
Dustin Graves58c2f662016-03-08 17:48:20 -0700116 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700117 *
118 * @param report_data debug_report_data object for routing validation messages.
119 * @param apiName Name of API call being validated.
120 * @param parameterName Name of parameter being validated.
121 * @param value Pointer to validate.
122 * @return Boolean value indicating that the call should be skipped.
123 */
Dustin Graves080069b2016-04-05 13:48:15 -0600124static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const char *parameterName,
125 const void *value) {
126 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700127
128 if (value == NULL) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600129 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
130 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700131 }
132
133 return skipCall;
134}
135
136/**
137 * Validate array count and pointer to array.
138 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700139 * Verify that required count and array parameters are not 0 or NULL. If the
140 * count parameter is not optional, verify that it is not 0. If the array
141 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700142 *
143 * @param report_data debug_report_data object for routing validation messages.
144 * @param apiName Name of API call being validated.
145 * @param countName Name of count parameter.
146 * @param arrayName Name of array parameter.
147 * @param count Number of elements in the array.
148 * @param array Array to validate.
149 * @param countRequired The 'count' parameter may not be 0 when true.
150 * @param arrayRequired The 'array' parameter may not be NULL when true.
151 * @return Boolean value indicating that the call should be skipped.
152 */
153template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600154bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName, T count,
155 const void *array, bool countRequired, bool arrayRequired) {
156 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700157
158 // Count parameters not tagged as optional cannot be 0
Dustin Graves080069b2016-04-05 13:48:15 -0600159 if ((count == 0) && countRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600160 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
161 REQUIRED_PARAMETER, LayerName, "%s: parameter %s must be greater than 0", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700162 }
163
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600164 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600165 if ((array == NULL) && arrayRequired && (count != 0)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600166 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
167 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, arrayName);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600168 }
169
170 return skipCall;
171}
172
173/**
174* Validate pointer to array count and pointer to array.
175*
176* Verify that required count and array parameters are not NULL. If count
177* is not NULL and its value is not optional, verify that it is not 0. If the
178* array parameter is NULL, and it is not optional, verify that count is 0.
179* The array parameter will typically be optional for this case (where count is
180* a pointer), allowing the caller to retrieve the available count.
181*
182* @param report_data debug_report_data object for routing validation messages.
183* @param apiName Name of API call being validated.
184* @param countName Name of count parameter.
185* @param arrayName Name of array parameter.
186* @param count Pointer to the number of elements in the array.
187* @param array Array to validate.
188* @param countPtrRequired The 'count' parameter may not be NULL when true.
189* @param countValueRequired The '*count' value may not be 0 when true.
190* @param arrayRequired The 'array' parameter may not be NULL when true.
191* @return Boolean value indicating that the call should be skipped.
192*/
193template <typename T>
194bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
195 const T *count, const void *array, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
196 bool skipCall = false;
197
198 if (count == NULL) {
199 if (countPtrRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600200 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
201 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600202 }
203 }
204 else {
205 skipCall |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700206 }
207
208 return skipCall;
209}
210
211/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600212 * Validate a pointer to a Vulkan structure.
213 *
214 * Verify that a required pointer to a structure is not NULL. If the pointer is
215 * not NULL, verify that each structure's sType field is set to the correct
216 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700217 *
218 * @param report_data debug_report_data object for routing validation messages.
219 * @param apiName Name of API call being validated.
220 * @param parameterName Name of struct parameter being validated.
221 * @param sTypeName Name of expected VkStructureType value.
222 * @param value Pointer to the struct to validate.
223 * @param sType VkStructureType for structure validation.
224 * @param required The parameter may not be NULL when true.
225 * @return Boolean value indicating that the call should be skipped.
226 */
227template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600228bool validate_struct_type(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *sTypeName,
229 const T *value, VkStructureType sType, bool required) {
230 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700231
232 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600233 if (required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600234 skipCall |=
235 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
236 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700237 }
238 } else if (value->sType != sType) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600239 skipCall |=
240 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
241 INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700242 }
243
244 return skipCall;
245}
246
247/**
248 * Validate an array of Vulkan structures.
249 *
250 * Verify that required count and array parameters are not NULL. If count
251 * is not NULL and its value is not optional, verify that it is not 0.
252 * If the array contains 1 or more structures, verify that each structure's
253 * sType field is set to the correct VkStructureType value.
254 *
255 * @param report_data debug_report_data object for routing validation messages.
256 * @param apiName Name of API call being validated.
257 * @param countName Name of count parameter.
258 * @param arrayName Name of array parameter.
259 * @param sTypeName Name of expected VkStructureType value.
260 * @param count Pointer to the number of elements in the array.
261 * @param array Array to validate.
262 * @param sType VkStructureType for structure validation.
263 * @param countPtrRequired The 'count' parameter may not be NULL when true.
264 * @param countValueRequired The '*count' value may not be 0 when true.
265 * @param arrayRequired The 'array' parameter may not be NULL when true.
266 * @return Boolean value indicating that the call should be skipped.
267 */
268template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600269bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
270 const char *sTypeName, const uint32_t *count, const T *array, VkStructureType sType,
271 bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
272 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700273
274 if (count == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600275 if (countPtrRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600276 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
277 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700278 }
279 } else {
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700280 skipCall |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
281 countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700282 }
283
284 return skipCall;
285}
286
287/**
288 * Validate an array of Vulkan structures
289 *
290 * Verify that required count and array parameters are not 0 or NULL. If
291 * the array contains 1 or more structures, verify that each structure's
292 * sType field is set to the correct VkStructureType value.
293 *
294 * @param report_data debug_report_data object for routing validation messages.
295 * @param apiName Name of API call being validated.
296 * @param countName Name of count parameter.
297 * @param arrayName Name of array parameter.
298 * @param sTypeName Name of expected VkStructureType value.
299 * @param count Number of elements in the array.
300 * @param array Array to validate.
301 * @param sType VkStructureType for structure validation.
302 * @param countRequired The 'count' parameter may not be 0 when true.
303 * @param arrayRequired The 'array' parameter may not be NULL when true.
304 * @return Boolean value indicating that the call should be skipped.
305 */
306template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600307bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
308 const char *sTypeName, uint32_t count, const T *array, VkStructureType sType, bool countRequired,
309 bool arrayRequired) {
310 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700311
312 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600313 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700314 } else {
315 // Verify that all structs in the array have the correct type
316 for (uint32_t i = 0; i < count; ++i) {
317 if (array[i].sType != sType) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600318 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
319 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
320 arrayName, i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700321 }
322 }
323 }
324
325 return skipCall;
326}
327
Dustin Graves58d114b2016-03-08 14:42:59 -0700328/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600329* Validate a Vulkan handle.
330*
331* Verify that the specified handle is not VK_NULL_HANDLE.
332*
333* @param report_data debug_report_data object for routing validation messages.
334* @param api_name Name of API call being validated.
335* @param parameter_name Name of struct parameter being validated.
336* @param value Handle to validate.
337* @return Boolean value indicating that the call should be skipped.
338*/
339template <typename T>
340bool validate_required_handle(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value) {
341 bool skip_call = false;
342
343 if (value == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600344 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
345 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
346 parameter_name);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600347 }
348
349 return skip_call;
350}
351
352/**
353* Validate an array of Vulkan handles.
354*
355* Verify that required count and array parameters are not NULL. If count
356* is not NULL and its value is not optional, verify that it is not 0.
357* If the array contains 1 or more handles, verify that no handle is set to
358* VK_NULL_HANDLE.
359*
360* @note This function is only intended to validate arrays of handles when none
361* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
362* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
363*
364* @param report_data debug_report_data object for routing validation messages.
365* @param api_name Name of API call being validated.
366* @param count_name Name of count parameter.
367* @param array_name Name of array parameter.
368* @param count Number of elements in the array.
369* @param array Array to validate.
370* @param count_required The 'count' parameter may not be 0 when true.
371* @param array_required The 'array' parameter may not be NULL when true.
372* @return Boolean value indicating that the call should be skipped.
373*/
374template <typename T>
375bool validate_handle_array(debug_report_data *report_data, const char *api_name, const char *count_name, const char *array_name,
376 uint32_t count, const T *array, bool count_required, bool array_required) {
377 bool skip_call = false;
378
379 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600380 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600381 } else {
382 // Verify that no handles in the array are VK_NULL_HANDLE
383 for (uint32_t i = 0; i < count; ++i) {
384 if (array[i] == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600385 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
386 __LINE__, REQUIRED_PARAMETER, LayerName,
387 "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name, array_name, i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600388 }
389 }
390 }
391
392 return skip_call;
393}
394
395/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700396 * Validate string array count and content.
397 *
398 * Verify that required count and array parameters are not 0 or NULL. If the
399 * count parameter is not optional, verify that it is not 0. If the array
400 * parameter is NULL, and it is not optional, verify that count is 0. If the
401 * array parameter is not NULL, verify that none of the strings are NULL.
402 *
403 * @param report_data debug_report_data object for routing validation messages.
404 * @param apiName Name of API call being validated.
405 * @param countName Name of count parameter.
406 * @param arrayName Name of array parameter.
407 * @param count Number of strings in the array.
408 * @param array Array of strings to validate.
409 * @param countRequired The 'count' parameter may not be 0 when true.
410 * @param arrayRequired The 'array' parameter may not be NULL when true.
411 * @return Boolean value indicating that the call should be skipped.
412 */
Dustin Graves080069b2016-04-05 13:48:15 -0600413static bool validate_string_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
414 uint32_t count, const char *const *array, bool countRequired, bool arrayRequired) {
415 bool skipCall = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700416
417 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600418 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves58d114b2016-03-08 14:42:59 -0700419 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600420 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700421 for (uint32_t i = 0; i < count; ++i) {
422 if (array[i] == NULL) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600423 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
424 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
425 apiName, arrayName, i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700426 }
427 }
428 }
429
430 return skipCall;
431}
432
Dustin Graves58c2f662016-03-08 17:48:20 -0700433/**
434 * Validate a structure's pNext member.
435 *
436 * Verify that the specified pNext value points to the head of a list of
437 * allowed extension structures. If no extension structures are allowed,
438 * verify that pNext is null.
439 *
440 * @param report_data debug_report_data object for routing validation messages.
441 * @param apiName Name of API call being validated.
442 * @param parameterName Name of parameter being validated.
443 * @param allowedStructNames Names of allowed structs.
444 * @param next Pointer to validate.
445 * @param allowedTypeCount total number of allowed structure types.
446 * @param allowedTypes array of strcuture types allowed for pNext.
447 * @return Boolean value indicating that the call should be skipped.
448 */
Dustin Graves080069b2016-04-05 13:48:15 -0600449static bool validate_struct_pnext(debug_report_data *report_data, const char *apiName, const char *parameterName,
450 const char *allowedStructNames, const void *next, size_t allowedTypeCount,
451 const VkStructureType *allowedTypes) {
452 bool skipCall = false;
Dustin Graves58c2f662016-03-08 17:48:20 -0700453
454 if (next != NULL) {
455 if (allowedTypeCount == 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600456 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
457 INVALID_STRUCT_PNEXT, LayerName, "%s: value of %s must be NULL", apiName, parameterName);
Dustin Graves58c2f662016-03-08 17:48:20 -0700458 } else {
459 const VkStructureType *start = allowedTypes;
460 const VkStructureType *end = allowedTypes + allowedTypeCount;
461 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
462
463 while (current != NULL) {
464 if (std::find(start, end, current->sType) == end) {
465 std::string typeName = string_VkStructureType(current->sType);
466
467 if (typeName == UnsupportedStructureTypeString) {
468 skipCall |= log_msg(
Dustin Gravesf233e502016-05-05 13:44:21 -0600469 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
470 INVALID_STRUCT_PNEXT, LayerName,
Dustin Graves58c2f662016-03-08 17:48:20 -0700471 "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed structures are [%s]",
472 apiName, parameterName, current->sType, allowedStructNames);
473 } else {
474 skipCall |= log_msg(
Dustin Gravesf233e502016-05-05 13:44:21 -0600475 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
476 INVALID_STRUCT_PNEXT, LayerName,
Dustin Graves58c2f662016-03-08 17:48:20 -0700477 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]",
478 apiName, parameterName, typeName.c_str(), allowedStructNames);
479 }
480 }
481
482 current = reinterpret_cast<const GenericHeader *>(current->pNext);
483 }
484 }
485 }
486
487 return skipCall;
488}
489
Dustin Graves29148ff2016-03-23 19:44:00 -0600490/**
491* Validate a VkBool32 value.
492*
493* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
494*
495* @param report_data debug_report_data object for routing validation messages.
496* @param apiName Name of API call being validated.
497* @param parameterName Name of parameter being validated.
498* @param value Boolean value to validate.
499* @return Boolean value indicating that the call should be skipped.
500*/
Dustin Graves080069b2016-04-05 13:48:15 -0600501static bool validate_bool32(debug_report_data *report_data, const char *apiName, const char *parameterName, VkBool32 value) {
502 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600503
504 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600505 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
506 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
507 parameterName, value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600508 }
509
510 return skipCall;
511}
512
513/**
514* Validate a Vulkan enumeration value.
515*
516* Generate a warning if an enumeration token value does not fall within the core enumeration
517* begin and end token values, and was not added to the enumeration by an extension. Extension
518* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
519* with 1,000,000,000 as the base token value.
520*
521* @note This function does not expect to process enumerations defining bitmask flag bits.
522*
523* @param report_data debug_report_data object for routing validation messages.
524* @param apiName Name of API call being validated.
525* @param parameterName Name of parameter being validated.
526* @param enumName Name of the enumeration being validated.
527* @param begin The begin range value for the enumeration.
528* @param end The end range value for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600529* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600530* @return Boolean value indicating that the call should be skipped.
531*/
532template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600533bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *enumName,
534 T begin, T end, T value) {
535 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600536
537 if (((value < begin) || (value > end)) && !is_extension_added_token(value)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600538 skipCall |=
539 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
540 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
541 "enumeration tokens and is not an extension added token",
542 apiName, parameterName, value, enumName);
Dustin Graves29148ff2016-03-23 19:44:00 -0600543 }
544
545 return skipCall;
546}
547
548/**
549* Validate an array of Vulkan enumeration value.
550*
551* Process all enumeration token values in the specified array and generate a warning if a value
552* does not fall within the core enumeration begin and end token values, and was not added to
553* the enumeration by an extension. Extension provided enumerations use the equation specified
554* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
555*
556* @note This function does not expect to process enumerations defining bitmask flag bits.
557*
558* @param report_data debug_report_data object for routing validation messages.
559* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600560* @param countName Name of count parameter.
561* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600562* @param enumName Name of the enumeration being validated.
563* @param begin The begin range value for the enumeration.
564* @param end The end range value for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600565* @param count Number of enumeration values in the array.
566* @param array Array of enumeration values to validate.
567* @param countRequired The 'count' parameter may not be 0 when true.
568* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600569* @return Boolean value indicating that the call should be skipped.
570*/
571template <typename T>
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600572static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const char *countName,
573 const char *arrayName, const char *enumName, T begin, T end, uint32_t count, const T *array,
574 bool countRequired, bool arrayRequired) {
Dustin Graves080069b2016-04-05 13:48:15 -0600575 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600576
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600577 if ((count == 0) || (array == NULL)) {
578 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
579 } else {
580 for (uint32_t i = 0; i < count; ++i) {
581 if (((array[i] < begin) || (array[i] > end)) && !is_extension_added_token(array[i])) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600582 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
583 __LINE__, UNRECOGNIZED_VALUE, LayerName,
584 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
585 "enumeration tokens and is not an extension added token",
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600586 apiName, arrayName, i, array[i], enumName);
587 }
Dustin Graves29148ff2016-03-23 19:44:00 -0600588 }
589 }
590
591 return skipCall;
592}
593
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600594/**
Dustin Graves78df8512016-04-28 17:58:59 -0600595* Verify that a reserved VkFlags value is zero.
596*
597* Verify that the specified value is zero, to check VkFlags values that are reserved for
598* future use.
599*
600* @param report_data debug_report_data object for routing validation messages.
601* @param api_name Name of API call being validated.
602* @param parameter_name Name of parameter being validated.
603* @param value Value to validate.
604* @return Boolean value indicating that the call should be skipped.
605*/
606static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
607 VkFlags value) {
608 bool skip_call = false;
609
610 if (value != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600611 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
612 RESERVED_PARAMETER, LayerName, "%s: parameter %s must be 0", api_name, parameter_name);
Dustin Graves78df8512016-04-28 17:58:59 -0600613 }
614
615 return skip_call;
616}
617
618/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600619* Validate a Vulkan bitmask value.
620*
621* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
622* for that type.
623*
624* @param report_data debug_report_data object for routing validation messages.
625* @param api_name Name of API call being validated.
626* @param parameter_name Name of parameter being validated.
627* @param flag_bits_name Name of the VkFlags type being validated.
628* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
629* @param value VkFlags value to validate.
630* @param flags_required The 'value' parameter may not be 0 when true.
631* @return Boolean value indicating that the call should be skipped.
632*/
Dustin Graves78df8512016-04-28 17:58:59 -0600633static bool validate_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
634 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600635 bool skip_call = false;
636
637 if (value == 0) {
638 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600639 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
640 REQUIRED_PARAMETER, LayerName, "%s: value of %s must not be 0", api_name, parameter_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600641 }
642 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600643 skip_call |=
644 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
645 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
646 api_name, parameter_name, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600647 }
648
649 return skip_call;
650}
651
652/**
653* Validate an array of Vulkan bitmask values.
654*
655* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
656* for that type.
657*
658* @param report_data debug_report_data object for routing validation messages.
659* @param api_name Name of API call being validated.
660* @param count_name Name of parameter being validated.
661* @param array_name Name of parameter being validated.
662* @param flag_bits_name Name of the VkFlags type being validated.
663* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
664* @param count Number of VkFlags values in the array.
665* @param array Array of VkFlags value to validate.
666* @param count_required The 'count' parameter may not be 0 when true.
667* @param array_required The 'array' parameter may not be NULL when true.
668* @return Boolean value indicating that the call should be skipped.
669*/
Dustin Graves78df8512016-04-28 17:58:59 -0600670static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const char *count_name,
671 const char *array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
672 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600673 bool skip_call = false;
674
675 if ((count == 0) || (array == NULL)) {
676 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
677 } else {
678 // Verify that all VkFlags values in the array
679 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600680 if (array[i] == 0) {
681 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
682 // elements in the array are allowed be 0
683 if (array_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600684 skip_call |=
685 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
686 REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name, array_name, i);
Dustin Graves78df8512016-04-28 17:58:59 -0600687 }
688 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600689 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] contains flag bits that are not recognized members of %s", api_name,
692 array_name, i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600693 }
694 }
695 }
696
697 return skip_call;
698}
699
700/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600701* Get VkResult code description.
702*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600703* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
704* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600705*
706* @param value VkResult code to process.
707* @return String describing the specified VkResult code.
708*/
709static std::string get_result_description(VkResult result) {
710 // clang-format off
711 switch (result) {
712 case VK_SUCCESS: return "a command completed successfully";
713 case VK_NOT_READY: return "a fence or query has not yet completed";
714 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
715 case VK_EVENT_SET: return "an event is signaled";
716 case VK_EVENT_RESET: return "an event is unsignalled";
717 case VK_INCOMPLETE: return "a return array was too small for the result";
718 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
719 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
Dustin Graves2adca842016-05-16 18:35:55 -0600720 case VK_ERROR_INITIALIZATION_FAILED: return "initialization of an object has failed";
721 case VK_ERROR_DEVICE_LOST: return "the logical device has been lost";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600722 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
723 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
724 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
725 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
726 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
727 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
728 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
729 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
730 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
731 "VkSurfaceKHR object, or some other non-Vulkan surface object";
732 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
733 "matches the surface properties exactly, but can still be used to "
734 "present to the surface successfully.";
735 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
736 "longer compatible with the swapchain";
737 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
738 "presentable image layout, or is incompatible in a way that prevents "
739 "sharing an image";
740 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
741 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100742 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600743 };
744 // clang-format on
745}
746
747/**
748* Validate return code.
749*
750* Print a message describing the reason for failure when an error code is returned.
751*
752* @param report_data debug_report_data object for routing validation messages.
753* @param apiName Name of API call being validated.
754* @param value VkResult value to validate.
755*/
756static void validate_result(debug_report_data *report_data, const char *apiName, VkResult result) {
757 if (result < 0) {
758 std::string resultName = string_VkResult(result);
759
760 if (resultName == UnsupportedResultString) {
761 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600762 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
763 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600764 } else {
765 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600766 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
767 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
768 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600769 }
770 }
771}
772
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600773} // namespace parameter_validation
774
Mark Lobodzinski739391a2016-03-17 15:08:18 -0600775#endif // PARAMETER_VALIDATION_UTILS_H