blob: 29182bf8908ea38a634c114693645ce0e7415806 [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 Graves58c2f662016-03-08 17:48:20 -070034struct GenericHeader {
35 VkStructureType sType;
36 const void *pNext;
37};
Dustin Graves58c2f662016-03-08 17:48:20 -070038
Dustin Graves29148ff2016-03-23 19:44:00 -060039// Layer name string to be logged with validation messages.
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060040const char LayerName[] = "ParameterValidation";
Dustin Graves29148ff2016-03-23 19:44:00 -060041
42// String returned by string_VkStructureType for an unrecognized type.
Dustin Graves58c2f662016-03-08 17:48:20 -070043const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
44
Dustin Gravesca7aa7c2016-03-25 15:13:28 -060045// String returned by string_VkResult for an unrecognized type.
46const std::string UnsupportedResultString = "Unhandled VkResult";
47
Dustin Graves29148ff2016-03-23 19:44:00 -060048// The base value used when computing the offset for an enumeration token value that is added by an extension.
49// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
50// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
51const uint32_t ExtEnumBaseValue = 1000000000;
52
53template <typename T> bool is_extension_added_token(T value) {
54 return (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
55}
56
57// VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE token is a special case that was converted from a core token to an
58// extension added token. Its original value was intentionally preserved after the conversion, so it does not use
59// the base value that other extension added tokens use, and it does not fall within the enum's begin/end range.
60template <> bool is_extension_added_token(VkSamplerAddressMode value) {
61 bool result = (std::abs(static_cast<int32_t>(value)) >= ExtEnumBaseValue);
62 return (result || (value == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE));
63}
64
Dustin Graves1e92cd72016-02-09 14:00:18 -070065/**
66 * Validate a required pointer.
67 *
Dustin Graves58c2f662016-03-08 17:48:20 -070068 * Verify that a required pointer is not NULL.
Dustin Graves1e92cd72016-02-09 14:00:18 -070069 *
70 * @param report_data debug_report_data object for routing validation messages.
71 * @param apiName Name of API call being validated.
72 * @param parameterName Name of parameter being validated.
73 * @param value Pointer to validate.
74 * @return Boolean value indicating that the call should be skipped.
75 */
Dustin Graves080069b2016-04-05 13:48:15 -060076static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const char *parameterName,
77 const void *value) {
78 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -070079
80 if (value == NULL) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -060081 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
82 "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -070083 }
84
85 return skipCall;
86}
87
88/**
89 * Validate array count and pointer to array.
90 *
Dustin Graves58d114b2016-03-08 14:42:59 -070091 * Verify that required count and array parameters are not 0 or NULL. If the
92 * count parameter is not optional, verify that it is not 0. If the array
93 * parameter is NULL, and it is not optional, verify that count is 0.
Dustin Graves1e92cd72016-02-09 14:00:18 -070094 *
95 * @param report_data debug_report_data object for routing validation messages.
96 * @param apiName Name of API call being validated.
97 * @param countName Name of count parameter.
98 * @param arrayName Name of array parameter.
99 * @param count Number of elements in the array.
100 * @param array Array to validate.
101 * @param countRequired The 'count' parameter may not be 0 when true.
102 * @param arrayRequired The 'array' parameter may not be NULL when true.
103 * @return Boolean value indicating that the call should be skipped.
104 */
105template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600106bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName, T count,
107 const void *array, bool countRequired, bool arrayRequired) {
108 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700109
110 // Count parameters not tagged as optional cannot be 0
Dustin Graves080069b2016-04-05 13:48:15 -0600111 if ((count == 0) && countRequired) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600112 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
113 "%s: parameter %s must be greater than 0", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700114 }
115
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600116 // Array parameters not tagged as optional cannot be NULL, unless the count is 0
Dustin Graves080069b2016-04-05 13:48:15 -0600117 if ((array == NULL) && arrayRequired && (count != 0)) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600118 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
119 "%s: required parameter %s specified as NULL", apiName, arrayName);
120 }
121
122 return skipCall;
123}
124
125/**
126* Validate pointer to array count and pointer to array.
127*
128* Verify that required count and array parameters are not NULL. If count
129* is not NULL and its value is not optional, verify that it is not 0. If the
130* array parameter is NULL, and it is not optional, verify that count is 0.
131* The array parameter will typically be optional for this case (where count is
132* a pointer), allowing the caller to retrieve the available count.
133*
134* @param report_data debug_report_data object for routing validation messages.
135* @param apiName Name of API call being validated.
136* @param countName Name of count parameter.
137* @param arrayName Name of array parameter.
138* @param count Pointer to the number of elements in the array.
139* @param array Array to validate.
140* @param countPtrRequired The 'count' parameter may not be NULL when true.
141* @param countValueRequired The '*count' value may not be 0 when true.
142* @param arrayRequired The 'array' parameter may not be NULL when true.
143* @return Boolean value indicating that the call should be skipped.
144*/
145template <typename T>
146bool validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
147 const T *count, const void *array, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
148 bool skipCall = false;
149
150 if (count == NULL) {
151 if (countPtrRequired) {
152 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
153 LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
154 }
155 }
156 else {
157 skipCall |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700158 }
159
160 return skipCall;
161}
162
163/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600164 * Validate a pointer to a Vulkan structure.
165 *
166 * Verify that a required pointer to a structure is not NULL. If the pointer is
167 * not NULL, verify that each structure's sType field is set to the correct
168 * VkStructureType value.
Dustin Graves1e92cd72016-02-09 14:00:18 -0700169 *
170 * @param report_data debug_report_data object for routing validation messages.
171 * @param apiName Name of API call being validated.
172 * @param parameterName Name of struct parameter being validated.
173 * @param sTypeName Name of expected VkStructureType value.
174 * @param value Pointer to the struct to validate.
175 * @param sType VkStructureType for structure validation.
176 * @param required The parameter may not be NULL when true.
177 * @return Boolean value indicating that the call should be skipped.
178 */
179template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600180bool validate_struct_type(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *sTypeName,
181 const T *value, VkStructureType sType, bool required) {
182 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700183
184 if (value == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600185 if (required) {
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700186 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600187 LayerName, "%s: required parameter %s specified as NULL", apiName, parameterName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700188 }
189 } else if (value->sType != sType) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600190 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
191 "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700192 }
193
194 return skipCall;
195}
196
197/**
198 * Validate an array of Vulkan structures.
199 *
200 * Verify that required count and array parameters are not NULL. If count
201 * is not NULL and its value is not optional, verify that it is not 0.
202 * If the array contains 1 or more structures, verify that each structure's
203 * sType field is set to the correct VkStructureType value.
204 *
205 * @param report_data debug_report_data object for routing validation messages.
206 * @param apiName Name of API call being validated.
207 * @param countName Name of count parameter.
208 * @param arrayName Name of array parameter.
209 * @param sTypeName Name of expected VkStructureType value.
210 * @param count Pointer to the number of elements in the array.
211 * @param array Array to validate.
212 * @param sType VkStructureType for structure validation.
213 * @param countPtrRequired The 'count' parameter may not be NULL when true.
214 * @param countValueRequired The '*count' value may not be 0 when true.
215 * @param arrayRequired The 'array' parameter may not be NULL when true.
216 * @return Boolean value indicating that the call should be skipped.
217 */
218template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600219bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
220 const char *sTypeName, const uint32_t *count, const T *array, VkStructureType sType,
221 bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
222 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700223
224 if (count == NULL) {
Dustin Graves080069b2016-04-05 13:48:15 -0600225 if (countPtrRequired) {
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700226 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600227 LayerName, "%s: required parameter %s specified as NULL", apiName, countName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700228 }
229 } else {
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700230 skipCall |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
231 countValueRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700232 }
233
234 return skipCall;
235}
236
237/**
238 * Validate an array of Vulkan structures
239 *
240 * Verify that required count and array parameters are not 0 or NULL. If
241 * the array contains 1 or more structures, verify that each structure's
242 * sType field is set to the correct VkStructureType value.
243 *
244 * @param report_data debug_report_data object for routing validation messages.
245 * @param apiName Name of API call being validated.
246 * @param countName Name of count parameter.
247 * @param arrayName Name of array parameter.
248 * @param sTypeName Name of expected VkStructureType value.
249 * @param count Number of elements in the array.
250 * @param array Array to validate.
251 * @param sType VkStructureType for structure validation.
252 * @param countRequired The 'count' parameter may not be 0 when true.
253 * @param arrayRequired The 'array' parameter may not be NULL when true.
254 * @return Boolean value indicating that the call should be skipped.
255 */
256template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600257bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
258 const char *sTypeName, uint32_t count, const T *array, VkStructureType sType, bool countRequired,
259 bool arrayRequired) {
260 bool skipCall = false;
Dustin Graves1e92cd72016-02-09 14:00:18 -0700261
262 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600263 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700264 } else {
265 // Verify that all structs in the array have the correct type
266 for (uint32_t i = 0; i < count; ++i) {
267 if (array[i].sType != sType) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600268 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
269 LayerName, "%s: parameter %s[%d].sType must be %s", apiName, arrayName, i, sTypeName);
Dustin Graves1e92cd72016-02-09 14:00:18 -0700270 }
271 }
272 }
273
274 return skipCall;
275}
276
Dustin Graves58d114b2016-03-08 14:42:59 -0700277/**
Dustin Graves20fd66f2016-04-18 18:33:21 -0600278* Validate a Vulkan handle.
279*
280* Verify that the specified handle is not VK_NULL_HANDLE.
281*
282* @param report_data debug_report_data object for routing validation messages.
283* @param api_name Name of API call being validated.
284* @param parameter_name Name of struct parameter being validated.
285* @param value Handle to validate.
286* @return Boolean value indicating that the call should be skipped.
287*/
288template <typename T>
289bool validate_required_handle(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value) {
290 bool skip_call = false;
291
292 if (value == VK_NULL_HANDLE) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600293 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
294 "%s: required parameter %s specified as VK_NULL_HANDLE", api_name, parameter_name);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600295 }
296
297 return skip_call;
298}
299
300/**
301* Validate an array of Vulkan handles.
302*
303* Verify that required count and array parameters are not NULL. If count
304* is not NULL and its value is not optional, verify that it is not 0.
305* If the array contains 1 or more handles, verify that no handle is set to
306* VK_NULL_HANDLE.
307*
308* @note This function is only intended to validate arrays of handles when none
309* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles
310* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
311*
312* @param report_data debug_report_data object for routing validation messages.
313* @param api_name Name of API call being validated.
314* @param count_name Name of count parameter.
315* @param array_name Name of array parameter.
316* @param count Number of elements in the array.
317* @param array Array to validate.
318* @param count_required The 'count' parameter may not be 0 when true.
319* @param array_required The 'array' parameter may not be NULL when true.
320* @return Boolean value indicating that the call should be skipped.
321*/
322template <typename T>
323bool validate_handle_array(debug_report_data *report_data, const char *api_name, const char *count_name, const char *array_name,
324 uint32_t count, const T *array, bool count_required, bool array_required) {
325 bool skip_call = false;
326
327 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600328 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 -0600329 } else {
330 // Verify that no handles in the array are VK_NULL_HANDLE
331 for (uint32_t i = 0; i < count; ++i) {
332 if (array[i] == VK_NULL_HANDLE) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600333 skip_call |=
334 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
335 "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name, array_name, i);
Dustin Graves20fd66f2016-04-18 18:33:21 -0600336 }
337 }
338 }
339
340 return skip_call;
341}
342
343/**
Dustin Graves58d114b2016-03-08 14:42:59 -0700344 * Validate string array count and content.
345 *
346 * Verify that required count and array parameters are not 0 or NULL. If the
347 * count parameter is not optional, verify that it is not 0. If the array
348 * parameter is NULL, and it is not optional, verify that count is 0. If the
349 * array parameter is not NULL, verify that none of the strings are NULL.
350 *
351 * @param report_data debug_report_data object for routing validation messages.
352 * @param apiName Name of API call being validated.
353 * @param countName Name of count parameter.
354 * @param arrayName Name of array parameter.
355 * @param count Number of strings in the array.
356 * @param array Array of strings to validate.
357 * @param countRequired The 'count' parameter may not be 0 when true.
358 * @param arrayRequired The 'array' parameter may not be NULL when true.
359 * @return Boolean value indicating that the call should be skipped.
360 */
Dustin Graves080069b2016-04-05 13:48:15 -0600361static bool validate_string_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
362 uint32_t count, const char *const *array, bool countRequired, bool arrayRequired) {
363 bool skipCall = false;
Dustin Graves58d114b2016-03-08 14:42:59 -0700364
365 if ((count == 0) || (array == NULL)) {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600366 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
Dustin Graves58d114b2016-03-08 14:42:59 -0700367 } else {
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600368 // Verify that strings in the array are not NULL
Dustin Graves58d114b2016-03-08 14:42:59 -0700369 for (uint32_t i = 0; i < count; ++i) {
370 if (array[i] == NULL) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600371 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
372 LayerName, "%s: required parameter %s[%d] specified as NULL", apiName, arrayName, i);
Dustin Graves58d114b2016-03-08 14:42:59 -0700373 }
374 }
375 }
376
377 return skipCall;
378}
379
Dustin Graves58c2f662016-03-08 17:48:20 -0700380/**
381 * Validate a structure's pNext member.
382 *
383 * Verify that the specified pNext value points to the head of a list of
384 * allowed extension structures. If no extension structures are allowed,
385 * verify that pNext is null.
386 *
387 * @param report_data debug_report_data object for routing validation messages.
388 * @param apiName Name of API call being validated.
389 * @param parameterName Name of parameter being validated.
390 * @param allowedStructNames Names of allowed structs.
391 * @param next Pointer to validate.
392 * @param allowedTypeCount total number of allowed structure types.
393 * @param allowedTypes array of strcuture types allowed for pNext.
394 * @return Boolean value indicating that the call should be skipped.
395 */
Dustin Graves080069b2016-04-05 13:48:15 -0600396static bool validate_struct_pnext(debug_report_data *report_data, const char *apiName, const char *parameterName,
397 const char *allowedStructNames, const void *next, size_t allowedTypeCount,
398 const VkStructureType *allowedTypes) {
399 bool skipCall = false;
Dustin Graves58c2f662016-03-08 17:48:20 -0700400
401 if (next != NULL) {
402 if (allowedTypeCount == 0) {
403 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600404 LayerName, "%s: value of %s must be NULL", apiName, parameterName);
Dustin Graves58c2f662016-03-08 17:48:20 -0700405 } else {
406 const VkStructureType *start = allowedTypes;
407 const VkStructureType *end = allowedTypes + allowedTypeCount;
408 const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
409
410 while (current != NULL) {
411 if (std::find(start, end, current->sType) == end) {
412 std::string typeName = string_VkStructureType(current->sType);
413
414 if (typeName == UnsupportedStructureTypeString) {
415 skipCall |= log_msg(
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600416 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
Dustin Graves58c2f662016-03-08 17:48:20 -0700417 "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed structures are [%s]",
418 apiName, parameterName, current->sType, allowedStructNames);
419 } else {
420 skipCall |= log_msg(
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600421 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
Dustin Graves58c2f662016-03-08 17:48:20 -0700422 "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]",
423 apiName, parameterName, typeName.c_str(), allowedStructNames);
424 }
425 }
426
427 current = reinterpret_cast<const GenericHeader *>(current->pNext);
428 }
429 }
430 }
431
432 return skipCall;
433}
434
Dustin Graves29148ff2016-03-23 19:44:00 -0600435/**
436* Validate a VkBool32 value.
437*
438* Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
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 value Boolean value to validate.
444* @return Boolean value indicating that the call should be skipped.
445*/
Dustin Graves080069b2016-04-05 13:48:15 -0600446static bool validate_bool32(debug_report_data *report_data, const char *apiName, const char *parameterName, VkBool32 value) {
447 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600448
449 if ((value != VK_TRUE) && (value != VK_FALSE)) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600450 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
451 "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName, parameterName, value);
Dustin Graves29148ff2016-03-23 19:44:00 -0600452 }
453
454 return skipCall;
455}
456
457/**
458* Validate a Vulkan enumeration value.
459*
460* Generate a warning if an enumeration token value does not fall within the core enumeration
461* begin and end token values, and was not added to the enumeration by an extension. Extension
462* provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
463* with 1,000,000,000 as the base token value.
464*
465* @note This function does not expect to process enumerations defining bitmask flag bits.
466*
467* @param report_data debug_report_data object for routing validation messages.
468* @param apiName Name of API call being validated.
469* @param parameterName Name of parameter being validated.
470* @param enumName Name of the enumeration being validated.
471* @param begin The begin range value for the enumeration.
472* @param end The end range value for the enumeration.
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600473* @param value Enumeration value to validate.
Dustin Graves29148ff2016-03-23 19:44:00 -0600474* @return Boolean value indicating that the call should be skipped.
475*/
476template <typename T>
Dustin Graves080069b2016-04-05 13:48:15 -0600477bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *enumName,
478 T begin, T end, T value) {
479 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600480
481 if (((value < begin) || (value > end)) && !is_extension_added_token(value)) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600482 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
483 "%s: value of %s (%d) does not fall within the begin..end range of the core %s "
484 "enumeration tokens and is not an extension added token",
485 apiName, parameterName, value, enumName);
Dustin Graves29148ff2016-03-23 19:44:00 -0600486 }
487
488 return skipCall;
489}
490
491/**
492* Validate an array of Vulkan enumeration value.
493*
494* Process all enumeration token values in the specified array and generate a warning if a value
495* does not fall within the core enumeration begin and end token values, and was not added to
496* the enumeration by an extension. Extension provided enumerations use the equation specified
497* in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
498*
499* @note This function does not expect to process enumerations defining bitmask flag bits.
500*
501* @param report_data debug_report_data object for routing validation messages.
502* @param apiName Name of API call being validated.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600503* @param countName Name of count parameter.
504* @param arrayName Name of array parameter.
Dustin Graves29148ff2016-03-23 19:44:00 -0600505* @param enumName Name of the enumeration being validated.
506* @param begin The begin range value for the enumeration.
507* @param end The end range value for the enumeration.
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600508* @param count Number of enumeration values in the array.
509* @param array Array of enumeration values to validate.
510* @param countRequired The 'count' parameter may not be 0 when true.
511* @param arrayRequired The 'array' parameter may not be NULL when true.
Dustin Graves29148ff2016-03-23 19:44:00 -0600512* @return Boolean value indicating that the call should be skipped.
513*/
514template <typename T>
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600515static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const char *countName,
516 const char *arrayName, const char *enumName, T begin, T end, uint32_t count, const T *array,
517 bool countRequired, bool arrayRequired) {
Dustin Graves080069b2016-04-05 13:48:15 -0600518 bool skipCall = false;
Dustin Graves29148ff2016-03-23 19:44:00 -0600519
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600520 if ((count == 0) || (array == NULL)) {
521 skipCall |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired);
522 } else {
523 for (uint32_t i = 0; i < count; ++i) {
524 if (((array[i] < begin) || (array[i] > end)) && !is_extension_added_token(array[i])) {
Dustin Graves5a35e2e2016-05-06 10:17:12 -0600525 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600526 LayerName, "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
527 "enumeration tokens and is not an extension added token",
Dustin Graves0d15c6e2016-04-26 16:34:10 -0600528 apiName, arrayName, i, array[i], enumName);
529 }
Dustin Graves29148ff2016-03-23 19:44:00 -0600530 }
531 }
532
533 return skipCall;
534}
535
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600536/**
Dustin Graves78df8512016-04-28 17:58:59 -0600537* Verify that a reserved VkFlags value is zero.
538*
539* Verify that the specified value is zero, to check VkFlags values that are reserved for
540* future use.
541*
542* @param report_data debug_report_data object for routing validation messages.
543* @param api_name Name of API call being validated.
544* @param parameter_name Name of parameter being validated.
545* @param value Value to validate.
546* @return Boolean value indicating that the call should be skipped.
547*/
548static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
549 VkFlags value) {
550 bool skip_call = false;
551
552 if (value != 0) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600553 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
554 "%s: parameter %s must be 0", api_name, parameter_name);
Dustin Graves78df8512016-04-28 17:58:59 -0600555 }
556
557 return skip_call;
558}
559
560/**
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600561* Validate a Vulkan bitmask value.
562*
563* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
564* for that type.
565*
566* @param report_data debug_report_data object for routing validation messages.
567* @param api_name Name of API call being validated.
568* @param parameter_name Name of parameter being validated.
569* @param flag_bits_name Name of the VkFlags type being validated.
570* @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
571* @param value VkFlags value to validate.
572* @param flags_required The 'value' parameter may not be 0 when true.
573* @return Boolean value indicating that the call should be skipped.
574*/
Dustin Graves78df8512016-04-28 17:58:59 -0600575static bool validate_flags(debug_report_data *report_data, const char *api_name, const char *parameter_name,
576 const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600577 bool skip_call = false;
578
579 if (value == 0) {
580 if (flags_required) {
Dustin Graves5a35e2e2016-05-06 10:17:12 -0600581 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600582 LayerName, "%s: value of %s must not be 0", api_name, parameter_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600583 }
584 } else if ((value & (~all_flags)) != 0) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600585 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
586 "%s: value of %s contains flag bits that are not recognized members of %s", api_name, parameter_name,
587 flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600588 }
589
590 return skip_call;
591}
592
593/**
594* Validate an array of Vulkan bitmask values.
595*
596* Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
597* for that type.
598*
599* @param report_data debug_report_data object for routing validation messages.
600* @param api_name Name of API call being validated.
601* @param count_name Name of parameter being validated.
602* @param array_name Name of parameter being validated.
603* @param flag_bits_name Name of the VkFlags type being validated.
604* @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
605* @param count Number of VkFlags values in the array.
606* @param array Array of VkFlags value to validate.
607* @param count_required The 'count' parameter may not be 0 when true.
608* @param array_required The 'array' parameter may not be NULL when true.
609* @return Boolean value indicating that the call should be skipped.
610*/
Dustin Graves78df8512016-04-28 17:58:59 -0600611static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const char *count_name,
612 const char *array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
613 const VkFlags *array, bool count_required, bool array_required) {
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600614 bool skip_call = false;
615
616 if ((count == 0) || (array == NULL)) {
617 skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required);
618 } else {
619 // Verify that all VkFlags values in the array
620 for (uint32_t i = 0; i < count; ++i) {
Dustin Graves78df8512016-04-28 17:58:59 -0600621 if (array[i] == 0) {
622 // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
623 // elements in the array are allowed be 0
624 if (array_required) {
Dustin Graves5a35e2e2016-05-06 10:17:12 -0600625 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600626 1, LayerName, "%s: value of %s[%d] must not be 0", api_name, array_name, i);
Dustin Graves78df8512016-04-28 17:58:59 -0600627 }
628 } else if ((array[i] & (~all_flags)) != 0) {
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600629 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
630 LayerName, "%s: value of %s[%d] contains flag bits that are not recognized members of %s",
631 api_name, array_name, i, flag_bits_name);
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600632 }
633 }
634 }
635
636 return skip_call;
637}
638
639/**
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600640* Get VkResult code description.
641*
Dustin Graves9c6b62b2016-04-26 15:37:10 -0600642* Returns a string describing the specified VkResult code. The description is based on the language in the Vulkan API
643* specification.
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600644*
645* @param value VkResult code to process.
646* @return String describing the specified VkResult code.
647*/
648static std::string get_result_description(VkResult result) {
649 // clang-format off
650 switch (result) {
651 case VK_SUCCESS: return "a command completed successfully";
652 case VK_NOT_READY: return "a fence or query has not yet completed";
653 case VK_TIMEOUT: return "a wait operation has not completed in the specified time";
654 case VK_EVENT_SET: return "an event is signaled";
655 case VK_EVENT_RESET: return "an event is unsignalled";
656 case VK_INCOMPLETE: return "a return array was too small for the result";
657 case VK_ERROR_OUT_OF_HOST_MEMORY: return "a host memory allocation has failed";
658 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "a device memory allocation has failed";
659 case VK_ERROR_INITIALIZATION_FAILED: return "the logical device has been lost";
660 case VK_ERROR_DEVICE_LOST: return "initialization of an object has failed";
661 case VK_ERROR_MEMORY_MAP_FAILED: return "mapping of a memory object has failed";
662 case VK_ERROR_LAYER_NOT_PRESENT: return "the specified layer does not exist";
663 case VK_ERROR_EXTENSION_NOT_PRESENT: return "the specified extension does not exist";
664 case VK_ERROR_FEATURE_NOT_PRESENT: return "the requested feature is not available on this device";
665 case VK_ERROR_INCOMPATIBLE_DRIVER: return "a Vulkan driver could not be found";
666 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects of the type have already been created";
667 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "the requested format is not supported on this device";
668 case VK_ERROR_SURFACE_LOST_KHR: return "a surface is no longer available";
669 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
670 "VkSurfaceKHR object, or some other non-Vulkan surface object";
671 case VK_SUBOPTIMAL_KHR: return "an image became available, and the swapchain no longer "
672 "matches the surface properties exactly, but can still be used to "
673 "present to the surface successfully.";
674 case VK_ERROR_OUT_OF_DATE_KHR: return "a surface has changed in such a way that it is no "
675 "longer compatible with the swapchain";
676 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
677 "presentable image layout, or is incompatible in a way that prevents "
678 "sharing an image";
679 case VK_ERROR_VALIDATION_FAILED_EXT: return "API validation has detected an invalid use of the API";
680 case VK_ERROR_INVALID_SHADER_NV: return "one or more shaders failed to compile or link";
Eric Engestrombcbb0fd2016-04-02 22:06:13 +0100681 default: return "an error has occurred";
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600682 };
683 // clang-format on
684}
685
686/**
687* Validate return code.
688*
689* Print a message describing the reason for failure when an error code is returned.
690*
691* @param report_data debug_report_data object for routing validation messages.
692* @param apiName Name of API call being validated.
693* @param value VkResult value to validate.
694*/
695static void validate_result(debug_report_data *report_data, const char *apiName, VkResult result) {
696 if (result < 0) {
697 std::string resultName = string_VkResult(result);
698
699 if (resultName == UnsupportedResultString) {
700 // Unrecognized result code
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600701 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
702 "%s: returned a result code indicating that an error has occurred", apiName);
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600703 } else {
704 std::string resultDesc = get_result_description(result);
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600705 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
706 "%s: returned %s, indicating that %s", apiName, resultName.c_str(), resultDesc.c_str());
Dustin Gravesca7aa7c2016-03-25 15:13:28 -0600707 }
708 }
709}
710
Dustin Gravesb83fc2d2016-05-04 12:56:08 -0600711} // namespace parameter_validation
712
Mark Lobodzinski739391a2016-03-17 15:08:18 -0600713#endif // PARAMETER_VALIDATION_UTILS_H