blob: 2d42f85c3dd68efcd02ee487505dddf22827df3d [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.
Mark Lobodzinski4dc6cb02016-06-28 11:23:08 -060052 DEVICE_LIMIT, // A specified parameter exceeds the limits returned
53 // by the physical device
54 DEVICE_FEATURE, // Use of a requested feature is not supported by
55 // the device
Dustin Gravesf233e502016-05-05 13:44:21 -060056 FAILURE_RETURN_CODE, // A Vulkan return code indicating a failure condition
57 // was encountered.
58};
59
Dustin Graves58c2f662016-03-08 17:48:20 -070060struct GenericHeader {
61 VkStructureType sType;
62 const void *pNext;
63};
Dustin Graves58c2f662016-03-08 17:48:20 -070064
Dustin Graves29148ff2016-03-23 19:44:00 -060065// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060066const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -060067
68// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -070069const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
70
Dustin Gravesca7aa7c2016-03-25 15:13:28 -060071// String returned by string_VkResult for an unrecognized type.
72const std::string UnsupportedResultString = "Unhandled VkResult";
73
Dustin Graves29148ff2016-03-23 19:44:00 -060074// The base value used when computing the offset for an enumeration token value that is added by an extension.
75// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
76// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
77const uint32_t ExtEnumBaseValue = 1000000000;
78
79template <typename T> bool is_extension_added_token(T value) {
80 return (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
81}
82
83// VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE token is a special case that was converted from a core token to an
84// extension added token. Its original value was intentionally preserved after the conversion, so it does not use
85// the base value that other extension added tokens use, and it does not fall within the enum's begin/end range.
86template <> bool is_extension_added_token(VkSamplerAddressMode value) {
87 bool result = (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
88 return (result || (value == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE));
89}
90
Dustin Graves1e92cd72016-02-09 14:00:18 -070091/**
Dustin Gravesf8032f22016-05-11 18:31:44 -060092* Validate a minimum value.
93*
94* Verify that the specified value is greater than the specified lower bound.
95*
96* @param report_data debug_report_data object for routing validation messages.
97* @param api_name Name of API call being validated.
98* @param parameter_name Name of parameter being validated.
99* @param value Value to validate.
100* @param lower_bound Lower bound value to use for validation.
101* @return Boolean value indicating that the call should be skipped.
102*/
103template <typename T>
104bool ValidateGreaterThan(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value,
105 T lower_bound) {
106 bool skip_call = false;
107
108 if (value <= lower_bound) {
109 skip_call |=
110 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
111 LayerName, "%s: parameter %s must be greater than %d", api_name, parameter_name, lower_bound);
112 }
113
114 return skip_call;
115}
116
117/**
Dustin Graves1e92cd72016-02-09 14:00:18 -0700118 * Validate a required pointer.
119 *
Dustin Graves58c2f662016-03-08 17:48:20 -0700120 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700121 *
122 * @param report_data debug_report_data object for routing validation messages.
123 * @param apiName Name of API call being validated.
124 * @param parameterName Name of parameter being validated.
125 * @param value Pointer to validate.
126 * @return Boolean value indicating that the call should be skipped.
127 */
Dustin Graves080069b2016-04-05 13:48:15 -0600128static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const char *parameterName,
129 const void *value) {
130 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700131
132 if (value == NULL) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600133 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
134 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700135 }
136
137 return skipCall;
138}
139
140/**
141 * Validate array count and pointer to array.
142 *
Dustin Graves58d114b2016-03-08 14:42:59 -0700143 * Verify that required count and array parameters are not 0 or NULL. If the
144 * count parameter is not optional, verify that it is not 0. If the array
145 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700146 *
147 * @param report_data debug_report_data object for routing validation messages.
148 * @param apiName Name of API call being validated.
149 * @param countName Name of count parameter.
150 * @param arrayName Name of array parameter.
151 * @param count Number of elements in the array.
152 * @param array Array to validate.
153 * @param countRequired The 'count' parameter may not be 0 when true.
154 * @param arrayRequired The 'array' parameter may not be NULL when true.
155 * @return Boolean value indicating that the call should be skipped.
156 */
157template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600158bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName, T count,
159 const void *array, bool countRequired, bool arrayRequired) {
160 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700161
162 // Count parameters not tagged as optional cannot be 0
Dustin Graves080069b2016-04-05 13:48:15 -0600163 if ((count == 0) && countRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600164 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
165 REQUIRED_PARAMETER, LayerName, "%s: parameter %s must be greater than 0", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700166 }
167
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600168 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600169 if ((array == NULL) && arrayRequired && (count != 0)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600170 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
171 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, arrayName);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600172 }
173
174 return skipCall;
175}
176
177/**
178* Validate pointer to array count and pointer to array.
179*
180* Verify that required count and array parameters are not NULL. If count
181* is not NULL and its value is not optional, verify that it is not 0. If the
182* array parameter is NULL, and it is not optional, verify that count is 0.
183* The array parameter will typically be optional for this case (where count is
184* a pointer), allowing the caller to retrieve the available count.
185*
186* @param report_data debug_report_data object for routing validation messages.
187* @param apiName Name of API call being validated.
188* @param countName Name of count parameter.
189* @param arrayName Name of array parameter.
190* @param count Pointer to the number of elements in the array.
191* @param array Array to validate.
192* @param countPtrRequired The 'count' parameter may not be NULL when true.
193* @param countValueRequired The '*count' value may not be 0 when true.
194* @param arrayRequired The 'array' parameter may not be NULL when true.
195* @return Boolean value indicating that the call should be skipped.
196*/
197template <typename T>
198bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
199 const T *count, const void *array, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
200 bool skipCall = false;
201
202 if (count == NULL) {
203 if (countPtrRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600204 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
205 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600206 }
207 }
208 else {
209 skipCall |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700210 }
211
212 return skipCall;
213}
214
215/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600216 * Validate a pointer to a Vulkan structure.
217 *
218 * Verify that a required pointer to a structure is not NULL. If the pointer is
219 * not NULL, verify that each structure's sType field is set to the correct
220 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700221 *
222 * @param report_data debug_report_data object for routing validation messages.
223 * @param apiName Name of API call being validated.
224 * @param parameterName Name of struct parameter being validated.
225 * @param sTypeName Name of expected VkStructureType value.
226 * @param value Pointer to the struct to validate.
227 * @param sType VkStructureType for structure validation.
228 * @param required The parameter may not be NULL when true.
229 * @return Boolean value indicating that the call should be skipped.
230 */
231template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600232bool validate_struct_type(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *sTypeName,
233 const T *value, VkStructureType sType, bool required) {
234 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700235
236 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600237 if (required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600238 skipCall |=
239 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
240 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700241 }
242 } else if (value->sType != sType) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600243 skipCall |=
244 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
245 INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700246 }
247
248 return skipCall;
249}
250
251/**
252 * Validate an array of Vulkan structures.
253 *
254 * Verify that required count and array parameters are not NULL. If count
255 * is not NULL and its value is not optional, verify that it is not 0.
256 * If the array contains 1 or more structures, verify that each structure's
257 * sType field is set to the correct VkStructureType value.
258 *
259 * @param report_data debug_report_data object for routing validation messages.
260 * @param apiName Name of API call being validated.
261 * @param countName Name of count parameter.
262 * @param arrayName Name of array parameter.
263 * @param sTypeName Name of expected VkStructureType value.
264 * @param count Pointer to the number of elements in the array.
265 * @param array Array to validate.
266 * @param sType VkStructureType for structure validation.
267 * @param countPtrRequired The 'count' parameter may not be NULL when true.
268 * @param countValueRequired The '*count' value may not be 0 when true.
269 * @param arrayRequired The 'array' parameter may not be NULL when true.
270 * @return Boolean value indicating that the call should be skipped.
271 */
272template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600273bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
274 const char *sTypeName, const uint32_t *count, const T *array, VkStructureType sType,
275 bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
276 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700277
278 if (count == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600279 if (countPtrRequired) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600280 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
281 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700282 }
283 } else {
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700284 skipCall |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
285 countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700286 }
287
288 return skipCall;
289}
290
291/**
292 * Validate an array of Vulkan structures
293 *
294 * Verify that required count and array parameters are not 0 or NULL. If
295 * the array contains 1 or more structures, verify that each structure's
296 * sType field is set to the correct VkStructureType value.
297 *
298 * @param report_data debug_report_data object for routing validation messages.
299 * @param apiName Name of API call being validated.
300 * @param countName Name of count parameter.
301 * @param arrayName Name of array parameter.
302 * @param sTypeName Name of expected VkStructureType value.
303 * @param count Number of elements in the array.
304 * @param array Array to validate.
305 * @param sType VkStructureType for structure validation.
306 * @param countRequired The 'count' parameter may not be 0 when true.
307 * @param arrayRequired The 'array' parameter may not be NULL when true.
308 * @return Boolean value indicating that the call should be skipped.
309 */
310template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600311bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
312 const char *sTypeName, uint32_t count, const T *array, VkStructureType sType, bool countRequired,
313 bool arrayRequired) {
314 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700315
316 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600317 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700318 } else {
319 // Verify that all structs in the array have the correct type
320 for (uint32_t i = 0; i < count; ++i) {
321 if (array[i].sType != sType) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600322 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
323 __LINE__, INVALID_STRUCT_STYPE, LayerName, "%s: parameter %s[%d].sType must be %s", apiName,
324 arrayName, i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700325 }
326 }
327 }
328
329 return skipCall;
330}
331
Dustin Graves58d114b2016-03-08 14:42:59 -0700332/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600333* Validate a Vulkan handle.
334*
335* Verify that the specified handle is not VK_NULL_HANDLE.
336*
337* @param report_data debug_report_data object for routing validation messages.
338* @param api_name Name of API call being validated.
339* @param parameter_name Name of struct parameter being validated.
340* @param value Handle to validate.
341* @return Boolean value indicating that the call should be skipped.
342*/
343template <typename T>
344bool validate_required_handle(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value) {
345 bool skip_call = false;
346
347 if (value == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600348 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
349 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
350 parameter_name);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600351 }
352
353 return skip_call;
354}
355
356/**
357* Validate an array of Vulkan handles.
358*
359* Verify that required count and array parameters are not NULL. If count
360* is not NULL and its value is not optional, verify that it is not 0.
361* If the array contains 1 or more handles, verify that no handle is set to
362* VK_NULL_HANDLE.
363*
364* @note This function is only intended to validate arrays of handles when none
365* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
366* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
367*
368* @param report_data debug_report_data object for routing validation messages.
369* @param api_name Name of API call being validated.
370* @param count_name Name of count parameter.
371* @param array_name Name of array parameter.
372* @param count Number of elements in the array.
373* @param array Array to validate.
374* @param count_required The 'count' parameter may not be 0 when true.
375* @param array_required The 'array' parameter may not be NULL when true.
376* @return Boolean value indicating that the call should be skipped.
377*/
378template <typename T>
379bool validate_handle_array(debug_report_data *report_data, const char *api_name, const char *count_name, const char *array_name,
380 uint32_t count, const T *array, bool count_required, bool array_required) {
381 bool skip_call = false;
382
383 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600384 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 -0600385 } else {
386 // Verify that no handles in the array are VK_NULL_HANDLE
387 for (uint32_t i = 0; i < count; ++i) {
388 if (array[i] == VK_NULL_HANDLE) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600389 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
390 __LINE__, REQUIRED_PARAMETER, LayerName,
391 "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name, array_name, i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600392 }
393 }
394 }
395
396 return skip_call;
397}
398
399/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700400 * Validate string array count and content.
401 *
402 * Verify that required count and array parameters are not 0 or NULL. If the
403 * count parameter is not optional, verify that it is not 0. If the array
404 * parameter is NULL, and it is not optional, verify that count is 0. If the
405 * array parameter is not NULL, verify that none of the strings are NULL.
406 *
407 * @param report_data debug_report_data object for routing validation messages.
408 * @param apiName Name of API call being validated.
409 * @param countName Name of count parameter.
410 * @param arrayName Name of array parameter.
411 * @param count Number of strings in the array.
412 * @param array Array of strings to validate.
413 * @param countRequired The 'count' parameter may not be 0 when true.
414 * @param arrayRequired The 'array' parameter may not be NULL when true.
415 * @return Boolean value indicating that the call should be skipped.
416 */
Dustin Graves080069b2016-04-05 13:48:15 -0600417static bool validate_string_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
418 uint32_t count, const char *const *array, bool countRequired, bool arrayRequired) {
419 bool skipCall = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700420
421 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600422 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves58d114b2016-03-08 14:42:59 -0700423 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600424 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700425 for (uint32_t i = 0; i < count; ++i) {
426 if (array[i] == NULL) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600427 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
428 __LINE__, REQUIRED_PARAMETER, LayerName, "%s: required parameter %s[%d] specified as NULL",
429 apiName, arrayName, i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700430 }
431 }
432 }
433
434 return skipCall;
435}
436
Dustin Graves58c2f662016-03-08 17:48:20 -0700437/**
438 * Validate a structure's pNext member.
439 *
440 * Verify that the specified pNext value points to the head of a list of
441 * allowed extension structures. If no extension structures are allowed,
442 * verify that pNext is null.
443 *
444 * @param report_data debug_report_data object for routing validation messages.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600445 * @param api_name Name of API call being validated.
446 * @param parameter_name Name of parameter being validated.
447 * @param allowed_struct_names Names of allowed structs.
Dustin Graves58c2f662016-03-08 17:48:20 -0700448 * @param next Pointer to validate.
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600449 * @param allowed_type_count Total number of allowed structure types.
450 * @param allowed_types Array of strcuture types allowed for pNext.
451 * @param header_version Version of header defining the pNext validation rules.
Dustin Graves58c2f662016-03-08 17:48:20 -0700452 * @return Boolean value indicating that the call should be skipped.
453 */
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600454static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const char *parameter_name,
455 const char *allowed_struct_names, const void *next, size_t allowed_type_count,
456 const VkStructureType *allowed_types, uint32_t header_version) {
457 bool skip_call = false;
458 const char disclaimer[] = "This warning is based on the Valid Usage documentation for version %d of the Vulkan header. It "
459 "is possible that you are using a struct from a private extension or an extension that was added "
460 "to a later version of the Vulkan header, in which case your use of %s is perfectly valid but "
461 "is not guaranteed to work correctly with validation enabled";
Dustin Graves58c2f662016-03-08 17:48:20 -0700462
463 if (next != NULL) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600464 if (allowed_type_count == 0) {
465 std::string message = "%s: value of %s must be NULL. ";
466 message += disclaimer;
467 skip_call |=
468 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
469 INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name, parameter_name, header_version, parameter_name);
Dustin Graves58c2f662016-03-08 17:48:20 -0700470 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600471 const VkStructureType *start = allowed_types;
472 const VkStructureType *end = allowed_types + allowed_type_count;
Dustin Graves58c2f662016-03-08 17:48:20 -0700473 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
474
475 while (current != NULL) {
476 if (std::find(start, end, current->sType) == end) {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600477 std::string type_name = string_VkStructureType(current->sType);
Dustin Graves58c2f662016-03-08 17:48:20 -0700478
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600479 if (type_name == UnsupportedStructureTypeString) {
480 std::string message = "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed "
481 "structures are [%s]. ";
482 message += disclaimer;
483 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
484 0, __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name,
485 parameter_name, current->sType, allowed_struct_names, header_version, parameter_name);
Dustin Graves58c2f662016-03-08 17:48:20 -0700486 } else {
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600487 std::string message =
488 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]. ";
489 message += disclaimer;
490 skip_call |=
491 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
492 __LINE__, INVALID_STRUCT_PNEXT, LayerName, message.c_str(), api_name, parameter_name,
493 type_name.c_str(), allowed_struct_names, header_version, parameter_name);
Dustin Graves58c2f662016-03-08 17:48:20 -0700494 }
495 }
496
497 current = reinterpret_cast<const GenericHeader *>(current->pNext);
498 }
499 }
500 }
501
Dustin Gravesaf5c0292016-07-19 13:43:53 -0600502 return skip_call;
Dustin Graves58c2f662016-03-08 17:48:20 -0700503}
504
Dustin Graves29148ff2016-03-23 19:44:00 -0600505/**
506* Validate a VkBool32 value.
507*
508* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
509*
510* @param report_data debug_report_data object for routing validation messages.
511* @param apiName Name of API call being validated.
512* @param parameterName Name of parameter being validated.
513* @param value Boolean value to validate.
514* @return Boolean value indicating that the call should be skipped.
515*/
Dustin Graves080069b2016-04-05 13:48:15 -0600516static bool validate_bool32(debug_report_data *report_data, const char *apiName, const char *parameterName, VkBool32 value) {
517 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600518
519 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600520 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
521 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
522 parameterName, value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600523 }
524
525 return skipCall;
526}
527
528/**
529* Validate a Vulkan enumeration value.
530*
531* Generate a warning if an enumeration token value does not fall within the core enumeration
532* begin and end token values, and was not added to the enumeration by an extension. Extension
533* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
534* with 1,000,000,000 as the base token value.
535*
536* @note This function does not expect to process enumerations defining bitmask flag bits.
537*
538* @param report_data debug_report_data object for routing validation messages.
539* @param apiName Name of API call being validated.
540* @param parameterName Name of parameter being validated.
541* @param enumName Name of the enumeration being validated.
542* @param begin The begin range value for the enumeration.
543* @param end The end range value for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600544* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600545* @return Boolean value indicating that the call should be skipped.
546*/
547template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600548bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *enumName,
549 T begin, T end, T value) {
550 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600551
552 if (((value < begin) || (value > end)) && !is_extension_added_token(value)) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600553 skipCall |=
554 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
555 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
556 "enumeration tokens and is not an extension added token",
557 apiName, parameterName, value, enumName);
Dustin Graves29148ff2016-03-23 19:44:00 -0600558 }
559
560 return skipCall;
561}
562
563/**
564* Validate an array of Vulkan enumeration value.
565*
566* Process all enumeration token values in the specified array and generate a warning if a value
567* does not fall within the core enumeration begin and end token values, and was not added to
568* the enumeration by an extension. Extension provided enumerations use the equation specified
569* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
570*
571* @note This function does not expect to process enumerations defining bitmask flag bits.
572*
573* @param report_data debug_report_data object for routing validation messages.
574* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600575* @param countName Name of count parameter.
576* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600577* @param enumName Name of the enumeration being validated.
578* @param begin The begin range value for the enumeration.
579* @param end The end range value for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600580* @param count Number of enumeration values in the array.
581* @param array Array of enumeration values to validate.
582* @param countRequired The 'count' parameter may not be 0 when true.
583* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600584* @return Boolean value indicating that the call should be skipped.
585*/
586template <typename T>
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600587static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const char *countName,
588 const char *arrayName, const char *enumName, T begin, T end, uint32_t count, const T *array,
589 bool countRequired, bool arrayRequired) {
Dustin Graves080069b2016-04-05 13:48:15 -0600590 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600591
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600592 if ((count == 0) || (array == NULL)) {
593 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
594 } else {
595 for (uint32_t i = 0; i < count; ++i) {
596 if (((array[i] < begin) || (array[i] > end)) && !is_extension_added_token(array[i])) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600597 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
598 __LINE__, UNRECOGNIZED_VALUE, LayerName,
599 "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
600 "enumeration tokens and is not an extension added token",
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600601 apiName, arrayName, i, array[i], enumName);
602 }
Dustin Graves29148ff2016-03-23 19:44:00 -0600603 }
604 }
605
606 return skipCall;
607}
608
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600609/**
Dustin Graves78df8512016-04-28 17:58:59 -0600610* Verify that a reserved VkFlags value is zero.
611*
612* Verify that the specified value is zero, to check VkFlags values that are reserved for
613* future use.
614*
615* @param report_data debug_report_data object for routing validation messages.
616* @param api_name Name of API call being validated.
617* @param parameter_name Name of parameter being validated.
618* @param value Value to validate.
619* @return Boolean value indicating that the call should be skipped.
620*/
621static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
622 VkFlags value) {
623 bool skip_call = false;
624
625 if (value != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600626 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
627 RESERVED_PARAMETER, LayerName, "%s: parameter %s must be 0", api_name, parameter_name);
Dustin Graves78df8512016-04-28 17:58:59 -0600628 }
629
630 return skip_call;
631}
632
633/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600634* Validate a Vulkan bitmask value.
635*
636* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
637* for that type.
638*
639* @param report_data debug_report_data object for routing validation messages.
640* @param api_name Name of API call being validated.
641* @param parameter_name Name of parameter being validated.
642* @param flag_bits_name Name of the VkFlags type being validated.
643* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
644* @param value VkFlags value to validate.
645* @param flags_required The 'value' parameter may not be 0 when true.
646* @return Boolean value indicating that the call should be skipped.
647*/
Dustin Graves78df8512016-04-28 17:58:59 -0600648static bool validate_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
649 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600650 bool skip_call = false;
651
652 if (value == 0) {
653 if (flags_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600654 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
655 REQUIRED_PARAMETER, LayerName, "%s: value of %s must not be 0", api_name, parameter_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600656 }
657 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600658 skip_call |=
659 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
660 UNRECOGNIZED_VALUE, LayerName, "%s: value of %s contains flag bits that are not recognized members of %s",
661 api_name, parameter_name, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600662 }
663
664 return skip_call;
665}
666
667/**
668* Validate an array of Vulkan bitmask values.
669*
670* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
671* for that type.
672*
673* @param report_data debug_report_data object for routing validation messages.
674* @param api_name Name of API call being validated.
675* @param count_name Name of parameter being validated.
676* @param array_name Name of parameter being validated.
677* @param flag_bits_name Name of the VkFlags type being validated.
678* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
679* @param count Number of VkFlags values in the array.
680* @param array Array of VkFlags value to validate.
681* @param count_required The 'count' parameter may not be 0 when true.
682* @param array_required The 'array' parameter may not be NULL when true.
683* @return Boolean value indicating that the call should be skipped.
684*/
Dustin Graves78df8512016-04-28 17:58:59 -0600685static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const char *count_name,
686 const char *array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
687 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600688 bool skip_call = false;
689
690 if ((count == 0) || (array == NULL)) {
691 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
692 } else {
693 // Verify that all VkFlags values in the array
694 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600695 if (array[i] == 0) {
696 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
697 // elements in the array are allowed be 0
698 if (array_required) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600699 skip_call |=
700 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
701 REQUIRED_PARAMETER, LayerName, "%s: value of %s[%d] must not be 0", api_name, array_name, i);
Dustin Graves78df8512016-04-28 17:58:59 -0600702 }
703 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesf233e502016-05-05 13:44:21 -0600704 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
705 __LINE__, UNRECOGNIZED_VALUE, LayerName,
706 "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
707 array_name, i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600708 }
709 }
710 }
711
712 return skip_call;
713}
714
715/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600716* Get VkResult code description.
717*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600718* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
719* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600720*
721* @param value VkResult code to process.
722* @return String describing the specified VkResult code.
723*/
724static std::string get_result_description(VkResult result) {
725 // clang-format off
726 switch (result) {
727 case VK_SUCCESS: return "a command completed successfully";
728 case VK_NOT_READY: return "a fence or query has not yet completed";
729 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
730 case VK_EVENT_SET: return "an event is signaled";
731 case VK_EVENT_RESET: return "an event is unsignalled";
732 case VK_INCOMPLETE: return "a return array was too small for the result";
733 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
734 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
Dustin Graves2adca842016-05-16 18:35:55 -0600735 case VK_ERROR_INITIALIZATION_FAILED: return "initialization of an object has failed";
736 case VK_ERROR_DEVICE_LOST: return "the logical device has been lost";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600737 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
738 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
739 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
740 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
741 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
742 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
743 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
744 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
745 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
746 "VkSurfaceKHR object, or some other non-Vulkan surface object";
747 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
748 "matches the surface properties exactly, but can still be used to "
749 "present to the surface successfully.";
750 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
751 "longer compatible with the swapchain";
752 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
753 "presentable image layout, or is incompatible in a way that prevents "
754 "sharing an image";
755 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
756 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100757 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600758 };
759 // clang-format on
760}
761
762/**
763* Validate return code.
764*
765* Print a message describing the reason for failure when an error code is returned.
766*
767* @param report_data debug_report_data object for routing validation messages.
768* @param apiName Name of API call being validated.
769* @param value VkResult value to validate.
770*/
771static void validate_result(debug_report_data *report_data, const char *apiName, VkResult result) {
772 if (result < 0) {
773 std::string resultName = string_VkResult(result);
774
775 if (resultName == UnsupportedResultString) {
776 // Unrecognized result code
Dustin Gravesf233e502016-05-05 13:44:21 -0600777 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
778 FAILURE_RETURN_CODE, LayerName, "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600779 } else {
780 std::string resultDesc = get_result_description(result);
Dustin Gravesf233e502016-05-05 13:44:21 -0600781 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
782 FAILURE_RETURN_CODE, LayerName, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
783 resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600784 }
785 }
786}
787
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600788} // namespace parameter_validation
789
Mark Lobodzinski739391a2016-03-17 15:08:18 -0600790#endif // PARAMETER_VALIDATION_UTILS_H