• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2015-2019 The Khronos Group Inc.
2  * Copyright (c) 2015-2019 Valve Corporation
3  * Copyright (c) 2015-2019 LunarG, Inc.
4  * Copyright (C) 2015-2019 Google Inc.
5  *
6  * 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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * 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.
17  *
18  * Author: Dustin Graves <dustin@lunarg.com>
19  * Author: Mark Lobodzinski <mark@lunarg.com>
20  */
21 
22 #pragma once
23 
24 #include "parameter_name.h"
25 #include "vk_typemap_helper.h"
26 
27 // Suppress unused warning on Linux
28 #if defined(__GNUC__)
29 #define DECORATE_UNUSED __attribute__((unused))
30 #else
31 #define DECORATE_UNUSED
32 #endif
33 
34 static const char DECORATE_UNUSED *kVUID_PVError_NONE = "UNASSIGNED-GeneralParameterError-Info";
35 static const char DECORATE_UNUSED *kVUID_PVError_InvalidUsage = "UNASSIGNED-GeneralParameterError-InvalidUsage";
36 static const char DECORATE_UNUSED *kVUID_PVError_InvalidStructSType = "UNASSIGNED-GeneralParameterError-InvalidStructSType";
37 static const char DECORATE_UNUSED *kVUID_PVError_InvalidStructPNext = "UNASSIGNED-GeneralParameterError-InvalidStructPNext";
38 static const char DECORATE_UNUSED *kVUID_PVError_RequiredParameter = "UNASSIGNED-GeneralParameterError-RequiredParameter";
39 static const char DECORATE_UNUSED *kVUID_PVError_ReservedParameter = "UNASSIGNED-GeneralParameterError-ReservedParameter";
40 static const char DECORATE_UNUSED *kVUID_PVError_UnrecognizedValue = "UNASSIGNED-GeneralParameterError-UnrecognizedValue";
41 static const char DECORATE_UNUSED *kVUID_PVError_DeviceLimit = "UNASSIGNED-GeneralParameterError-DeviceLimit";
42 static const char DECORATE_UNUSED *kVUID_PVError_DeviceFeature = "UNASSIGNED-GeneralParameterError-DeviceFeature";
43 static const char DECORATE_UNUSED *kVUID_PVError_FailureCode = "UNASSIGNED-GeneralParameterError-FailureCode";
44 static const char DECORATE_UNUSED *kVUID_PVError_ExtensionNotEnabled = "UNASSIGNED-GeneralParameterError-ExtensionNotEnabled";
45 static const char DECORATE_UNUSED *kVUID_PVPerfWarn_SuboptimalSwapchain = "UNASSIGNED-GeneralParameterPerfWarn-SuboptimalSwapchain";
46 
47 #undef DECORATE_UNUSED
48 
49 extern const uint32_t GeneratedVulkanHeaderVersion;
50 
51 extern const VkQueryPipelineStatisticFlags AllVkQueryPipelineStatisticFlagBits;
52 extern const VkColorComponentFlags AllVkColorComponentFlagBits;
53 extern const VkShaderStageFlags AllVkShaderStageFlagBits;
54 extern const VkQueryControlFlags AllVkQueryControlFlagBits;
55 extern const VkImageUsageFlags AllVkImageUsageFlagBits;
56 extern const VkSampleCountFlags AllVkSampleCountFlagBits;
57 
58 extern const std::vector<VkCompareOp> AllVkCompareOpEnums;
59 extern const std::vector<VkStencilOp> AllVkStencilOpEnums;
60 extern const std::vector<VkBlendFactor> AllVkBlendFactorEnums;
61 extern const std::vector<VkBlendOp> AllVkBlendOpEnums;
62 extern const std::vector<VkLogicOp> AllVkLogicOpEnums;
63 extern const std::vector<VkBorderColor> AllVkBorderColorEnums;
64 extern const std::vector<VkImageLayout> AllVkImageLayoutEnums;
65 extern const std::vector<VkFormat> AllVkFormatEnums;
66 extern const std::vector<VkVertexInputRate> AllVkVertexInputRateEnums;
67 extern const std::vector<VkPrimitiveTopology> AllVkPrimitiveTopologyEnums;
68 
69 // String returned by string_VkStructureType for an unrecognized type.
70 const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
71 
72 // String returned by string_VkResult for an unrecognized type.
73 const std::string UnsupportedResultString = "Unhandled VkResult";
74 
75 // The base value used when computing the offset for an enumeration token value that is added by an extension.
76 // When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
77 // See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
78 const uint32_t ExtEnumBaseValue = 1000000000;
79 
80 // The value of all VK_xxx_MAX_ENUM tokens
81 const uint32_t MaxEnumValue = 0x7FFFFFFF;
82 
83 // Misc parameters of log_msg that are likely constant per command (or low frequency change)
84 struct LogMiscParams {
85     VkDebugReportObjectTypeEXT objectType;
86     uint64_t srcObject;
87     const char *api_name;
88 };
89 
90 class StatelessValidation : public ValidationObject {
91    public:
92     VkPhysicalDeviceLimits device_limits = {};
93     safe_VkPhysicalDeviceFeatures2 physical_device_features2;
94     const VkPhysicalDeviceFeatures &physical_device_features = physical_device_features2.features;
95 
96     // Override chassis read/write locks for this validation object
97     // This override takes a deferred lock. i.e. it is not acquired.
write_lock()98     std::unique_lock<std::mutex> write_lock() { return std::unique_lock<std::mutex>(validation_object_mutex, std::defer_lock); }
99 
100     // Device extension properties -- storing properties gathered from VkPhysicalDeviceProperties2KHR::pNext chain
101     struct DeviceExtensionProperties {
102         VkPhysicalDeviceShadingRateImagePropertiesNV shading_rate_image_props;
103         VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_props;
104         VkPhysicalDeviceRayTracingPropertiesNV ray_tracing_props;
105     };
106     DeviceExtensionProperties phys_dev_ext_props = {};
107 
108     struct SubpassesUsageStates {
109         std::unordered_set<uint32_t> subpasses_using_color_attachment;
110         std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
111     };
112 
113     // Though this validation object is predominantly statless, the Framebuffer checks are greatly simplified by creating and
114     // updating a map of the renderpass usage states, and these accesses need thread protection. Use a mutex separate from the
115     // parent object's to maintain that functionality.
116     std::mutex renderpass_map_mutex;
117     std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
118 
119     // Constructor for stateles validation tracking
120     // StatelessValidation() : {}
121     /**
122      * Validate a minimum value.
123      *
124      * Verify that the specified value is greater than the specified lower bound.
125      *
126      * @param api_name Name of API call being validated.
127      * @param parameter_name Name of parameter being validated.
128      * @param value Value to validate.
129      * @param lower_bound Lower bound value to use for validation.
130      * @return Boolean value indicating that the call should be skipped.
131      */
132     template <typename T>
ValidateGreaterThan(const T value,const T lower_bound,const ParameterName & parameter_name,const std::string & vuid,const LogMiscParams & misc)133     bool ValidateGreaterThan(const T value, const T lower_bound, const ParameterName &parameter_name, const std::string &vuid,
134                              const LogMiscParams &misc) {
135         bool skip_call = false;
136 
137         if (value <= lower_bound) {
138             std::ostringstream ss;
139             ss << misc.api_name << ": parameter " << parameter_name.get_name() << " (= " << value << ") is greater than "
140                << lower_bound;
141             skip_call |=
142                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, misc.objectType, misc.srcObject, vuid, "%s", ss.str().c_str());
143         }
144 
145         return skip_call;
146     }
147 
148     template <typename T>
ValidateGreaterThanZero(const T value,const ParameterName & parameter_name,const std::string & vuid,const LogMiscParams & misc)149     bool ValidateGreaterThanZero(const T value, const ParameterName &parameter_name, const std::string &vuid,
150                                  const LogMiscParams &misc) {
151         return ValidateGreaterThan(value, T{0}, parameter_name, vuid, misc);
152     }
153     /**
154      * Validate a required pointer.
155      *
156      * Verify that a required pointer is not NULL.
157      *
158      * @param apiName Name of API call being validated.
159      * @param parameterName Name of parameter being validated.
160      * @param value Pointer to validate.
161      * @return Boolean value indicating that the call should be skipped.
162      */
validate_required_pointer(const char * apiName,const ParameterName & parameterName,const void * value,const std::string & vuid)163     bool validate_required_pointer(const char *apiName, const ParameterName &parameterName, const void *value,
164                                    const std::string &vuid) {
165         bool skip_call = false;
166 
167         if (value == NULL) {
168             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
169                                  "%s: required parameter %s specified as NULL.", apiName, parameterName.get_name().c_str());
170         }
171 
172         return skip_call;
173     }
174 
175     /**
176      * Validate array count and pointer to array.
177      *
178      * Verify that required count and array parameters are not 0 or NULL.  If the
179      * count parameter is not optional, verify that it is not 0.  If the array
180      * parameter is NULL, and it is not optional, verify that count is 0.
181      *
182      * @param apiName Name of API call being validated.
183      * @param countName Name of count parameter.
184      * @param arrayName Name of array parameter.
185      * @param count Number of elements in the array.
186      * @param array Array to validate.
187      * @param countRequired The 'count' parameter may not be 0 when true.
188      * @param arrayRequired The 'array' parameter may not be NULL when true.
189      * @return Boolean value indicating that the call should be skipped.
190      */
191     template <typename T1, typename T2>
validate_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,T1 count,const T2 * array,bool countRequired,bool arrayRequired,const char * count_required_vuid,const char * array_required_vuid)192     bool validate_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, T1 count,
193                         const T2 *array, bool countRequired, bool arrayRequired, const char *count_required_vuid,
194                         const char *array_required_vuid) {
195         bool skip_call = false;
196 
197         // Count parameters not tagged as optional cannot be 0
198         if (countRequired && (count == 0)) {
199             skip_call |=
200                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, count_required_vuid,
201                         "%s: parameter %s must be greater than 0.", apiName, countName.get_name().c_str());
202         }
203 
204         // Array parameters not tagged as optional cannot be NULL, unless the count is 0
205         if (arrayRequired && (count != 0) && (*array == NULL)) {
206             skip_call |=
207                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, array_required_vuid,
208                         "%s: required parameter %s specified as NULL.", apiName, arrayName.get_name().c_str());
209         }
210 
211         return skip_call;
212     }
213 
214     /**
215      * Validate pointer to array count and pointer to array.
216      *
217      * Verify that required count and array parameters are not NULL.  If count
218      * is not NULL and its value is not optional, verify that it is not 0.  If the
219      * array parameter is NULL, and it is not optional, verify that count is 0.
220      * The array parameter will typically be optional for this case (where count is
221      * a pointer), allowing the caller to retrieve the available count.
222      *
223      * @param apiName Name of API call being validated.
224      * @param countName Name of count parameter.
225      * @param arrayName Name of array parameter.
226      * @param count Pointer to the number of elements in the array.
227      * @param array Array to validate.
228      * @param countPtrRequired The 'count' parameter may not be NULL when true.
229      * @param countValueRequired The '*count' value may not be 0 when true.
230      * @param arrayRequired The 'array' parameter may not be NULL when true.
231      * @return Boolean value indicating that the call should be skipped.
232      */
233     template <typename T1, typename T2>
validate_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const T1 * count,const T2 * array,bool countPtrRequired,bool countValueRequired,bool arrayRequired,const char * count_required_vuid,const char * array_required_vuid)234     bool validate_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, const T1 *count,
235                         const T2 *array, bool countPtrRequired, bool countValueRequired, bool arrayRequired,
236                         const char *count_required_vuid, const char *array_required_vuid) {
237         bool skip_call = false;
238 
239         if (count == NULL) {
240             if (countPtrRequired) {
241                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
242                                      kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as NULL", apiName,
243                                      countName.get_name().c_str());
244             }
245         } else {
246             skip_call |= validate_array(apiName, countName, arrayName, *array ? (*count) : 0, &array, countValueRequired,
247                                         arrayRequired, count_required_vuid, array_required_vuid);
248         }
249 
250         return skip_call;
251     }
252 
253     /**
254      * Validate a pointer to a Vulkan structure.
255      *
256      * Verify that a required pointer to a structure is not NULL.  If the pointer is
257      * not NULL, verify that each structure's sType field is set to the correct
258      * VkStructureType value.
259      *
260      * @param apiName Name of API call being validated.
261      * @param parameterName Name of struct parameter being validated.
262      * @param sTypeName Name of expected VkStructureType value.
263      * @param value Pointer to the struct to validate.
264      * @param sType VkStructureType for structure validation.
265      * @param required The parameter may not be NULL when true.
266      * @return Boolean value indicating that the call should be skipped.
267      */
268     template <typename T>
validate_struct_type(const char * apiName,const ParameterName & parameterName,const char * sTypeName,const T * value,VkStructureType sType,bool required,const char * struct_vuid,const char * stype_vuid)269     bool validate_struct_type(const char *apiName, const ParameterName &parameterName, const char *sTypeName, const T *value,
270                               VkStructureType sType, bool required, const char *struct_vuid, const char *stype_vuid) {
271         bool skip_call = false;
272 
273         if (value == NULL) {
274             if (required) {
275                 skip_call |=
276                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, struct_vuid,
277                             "%s: required parameter %s specified as NULL", apiName, parameterName.get_name().c_str());
278             }
279         } else if (value->sType != sType) {
280             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, stype_vuid,
281                                  "%s: parameter %s->sType must be %s.", apiName, parameterName.get_name().c_str(), sTypeName);
282         }
283 
284         return skip_call;
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 apiName Name of API call being validated.
295      * @param countName Name of count parameter.
296      * @param arrayName Name of array parameter.
297      * @param sTypeName Name of expected VkStructureType value.
298      * @param count Number of elements in the array.
299      * @param array Array to validate.
300      * @param sType VkStructureType for structure validation.
301      * @param countRequired The 'count' parameter may not be 0 when true.
302      * @param arrayRequired The 'array' parameter may not be NULL when true.
303      * @return Boolean value indicating that the call should be skipped.
304      */
305     template <typename T>
validate_struct_type_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * sTypeName,uint32_t count,const T * array,VkStructureType sType,bool countRequired,bool arrayRequired,const char * stype_vuid,const char * param_vuid,const char * count_required_vuid)306     bool validate_struct_type_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName,
307                                     const char *sTypeName, uint32_t count, const T *array, VkStructureType sType,
308                                     bool countRequired, bool arrayRequired, const char *stype_vuid, const char *param_vuid,
309                                     const char *count_required_vuid) {
310         bool skip_call = false;
311 
312         if ((count == 0) || (array == NULL)) {
313             skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
314                                         count_required_vuid, param_vuid);
315         } else {
316             // Verify that all structs in the array have the correct type
317             for (uint32_t i = 0; i < count; ++i) {
318                 if (array[i].sType != sType) {
319                     skip_call |=
320                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, stype_vuid,
321                                 "%s: parameter %s[%d].sType must be %s", apiName, arrayName.get_name().c_str(), i, sTypeName);
322                 }
323             }
324         }
325 
326         return skip_call;
327     }
328 
329     /**
330      * Validate an array of Vulkan structures.
331      *
332      * Verify that required count and array parameters are not NULL.  If count
333      * is not NULL and its value is not optional, verify that it is not 0.
334      * If the array contains 1 or more structures, verify that each structure's
335      * sType field is set to the correct VkStructureType value.
336      *
337      * @param apiName Name of API call being validated.
338      * @param countName Name of count parameter.
339      * @param arrayName Name of array parameter.
340      * @param sTypeName Name of expected VkStructureType value.
341      * @param count Pointer to the number of elements in the array.
342      * @param array Array to validate.
343      * @param sType VkStructureType for structure validation.
344      * @param countPtrRequired The 'count' parameter may not be NULL when true.
345      * @param countValueRequired The '*count' value may not be 0 when true.
346      * @param arrayRequired The 'array' parameter may not be NULL when true.
347      * @return Boolean value indicating that the call should be skipped.
348      */
349     template <typename T>
validate_struct_type_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * sTypeName,uint32_t * count,const T * array,VkStructureType sType,bool countPtrRequired,bool countValueRequired,bool arrayRequired,const char * stype_vuid,const char * param_vuid,const char * count_required_vuid)350     bool validate_struct_type_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName,
351                                     const char *sTypeName, uint32_t *count, const T *array, VkStructureType sType,
352                                     bool countPtrRequired, bool countValueRequired, bool arrayRequired, const char *stype_vuid,
353                                     const char *param_vuid, const char *count_required_vuid) {
354         bool skip_call = false;
355 
356         if (count == NULL) {
357             if (countPtrRequired) {
358                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
359                                      kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as NULL", apiName,
360                                      countName.get_name().c_str());
361             }
362         } else {
363             skip_call |= validate_struct_type_array(apiName, countName, arrayName, sTypeName, (*count), array, sType,
364                                                     countValueRequired, arrayRequired, stype_vuid, param_vuid, count_required_vuid);
365         }
366 
367         return skip_call;
368     }
369 
370     /**
371      * Validate a Vulkan handle.
372      *
373      * Verify that the specified handle is not VK_NULL_HANDLE.
374      *
375      * @param api_name Name of API call being validated.
376      * @param parameter_name Name of struct parameter being validated.
377      * @param value Handle to validate.
378      * @return Boolean value indicating that the call should be skipped.
379      */
380     template <typename T>
validate_required_handle(const char * api_name,const ParameterName & parameter_name,T value)381     bool validate_required_handle(const char *api_name, const ParameterName &parameter_name, T value) {
382         bool skip_call = false;
383 
384         if (value == VK_NULL_HANDLE) {
385             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
386                                  kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
387                                  parameter_name.get_name().c_str());
388         }
389 
390         return skip_call;
391     }
392 
393     /**
394      * Validate an array of Vulkan handles.
395      *
396      * Verify that required count and array parameters are not NULL.  If count
397      * is not NULL and its value is not optional, verify that it is not 0.
398      * If the array contains 1 or more handles, verify that no handle is set to
399      * VK_NULL_HANDLE.
400      *
401      * @note This function is only intended to validate arrays of handles when none
402      *       of the handles are allowed to be VK_NULL_HANDLE.  For arrays of handles
403      *       that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
404      *
405      * @param api_name Name of API call being validated.
406      * @param count_name Name of count parameter.
407      * @param array_name Name of array parameter.
408      * @param count Number of elements in the array.
409      * @param array Array to validate.
410      * @param count_required The 'count' parameter may not be 0 when true.
411      * @param array_required The 'array' parameter may not be NULL when true.
412      * @return Boolean value indicating that the call should be skipped.
413      */
414     template <typename T>
validate_handle_array(const char * api_name,const ParameterName & count_name,const ParameterName & array_name,uint32_t count,const T * array,bool count_required,bool array_required)415     bool validate_handle_array(const char *api_name, const ParameterName &count_name, const ParameterName &array_name,
416                                uint32_t count, const T *array, bool count_required, bool array_required) {
417         bool skip_call = false;
418 
419         if ((count == 0) || (array == NULL)) {
420             skip_call |= validate_array(api_name, count_name, array_name, count, &array, count_required, array_required,
421                                         kVUIDUndefined, kVUIDUndefined);
422         } else {
423             // Verify that no handles in the array are VK_NULL_HANDLE
424             for (uint32_t i = 0; i < count; ++i) {
425                 if (array[i] == VK_NULL_HANDLE) {
426                     skip_call |=
427                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
428                                 kVUID_PVError_RequiredParameter, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE",
429                                 api_name, array_name.get_name().c_str(), i);
430                 }
431             }
432         }
433 
434         return skip_call;
435     }
436 
437     /**
438      * Validate string array count and content.
439      *
440      * Verify that required count and array parameters are not 0 or NULL.  If the
441      * count parameter is not optional, verify that it is not 0.  If the array
442      * parameter is NULL, and it is not optional, verify that count is 0.  If the
443      * array parameter is not NULL, verify that none of the strings are NULL.
444      *
445      * @param apiName Name of API call being validated.
446      * @param countName Name of count parameter.
447      * @param arrayName Name of array parameter.
448      * @param count Number of strings in the array.
449      * @param array Array of strings to validate.
450      * @param countRequired The 'count' parameter may not be 0 when true.
451      * @param arrayRequired The 'array' parameter may not be NULL when true.
452      * @return Boolean value indicating that the call should be skipped.
453      */
validate_string_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,uint32_t count,const char * const * array,bool countRequired,bool arrayRequired,const char * count_required_vuid,const char * array_required_vuid)454     bool validate_string_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, uint32_t count,
455                                const char *const *array, bool countRequired, bool arrayRequired, const char *count_required_vuid,
456                                const char *array_required_vuid) {
457         bool skip_call = false;
458 
459         if ((count == 0) || (array == NULL)) {
460             skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
461                                         count_required_vuid, array_required_vuid);
462         } else {
463             // Verify that strings in the array are not NULL
464             for (uint32_t i = 0; i < count; ++i) {
465                 if (array[i] == NULL) {
466                     skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
467                                          kVUID_PVError_RequiredParameter, "%s: required parameter %s[%d] specified as NULL",
468                                          apiName, arrayName.get_name().c_str(), i);
469                 }
470             }
471         }
472 
473         return skip_call;
474     }
475 
476     // Forward declaration for pNext validation
477     bool ValidatePnextStructContents(const char *api_name, const ParameterName &parameter_name, const VkBaseOutStructure *header);
478 
479     /**
480      * Validate a structure's pNext member.
481      *
482      * Verify that the specified pNext value points to the head of a list of
483      * allowed extension structures.  If no extension structures are allowed,
484      * verify that pNext is null.
485      *
486      * @param api_name Name of API call being validated.
487      * @param parameter_name Name of parameter being validated.
488      * @param allowed_struct_names Names of allowed structs.
489      * @param next Pointer to validate.
490      * @param allowed_type_count Total number of allowed structure types.
491      * @param allowed_types Array of structure types allowed for pNext.
492      * @param header_version Version of header defining the pNext validation rules.
493      * @return Boolean value indicating that the call should be skipped.
494      */
validate_struct_pnext(const char * api_name,const ParameterName & parameter_name,const char * allowed_struct_names,const void * next,size_t allowed_type_count,const VkStructureType * allowed_types,uint32_t header_version,const char * vuid)495     bool validate_struct_pnext(const char *api_name, const ParameterName &parameter_name, const char *allowed_struct_names,
496                                const void *next, size_t allowed_type_count, const VkStructureType *allowed_types,
497                                uint32_t header_version, const char *vuid) {
498         bool skip_call = false;
499 
500         // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
501         // Codegen a map of vectors containing the allowable pNext types for each struct and use that here -- also simplifies parms.
502         if (next != NULL) {
503             std::unordered_set<const void *> cycle_check;
504             std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
505 
506             const char *disclaimer =
507                 "This warning is based on the Valid Usage documentation for version %d of the Vulkan header.  It is possible that "
508                 "you "
509                 "are "
510                 "using a struct from a private extension or an extension that was added to a later version of the Vulkan header, "
511                 "in "
512                 "which "
513                 "case your use of %s is perfectly valid but is not guaranteed to work correctly with validation enabled";
514 
515             if (allowed_type_count == 0) {
516                 std::string message = "%s: value of %s must be NULL. ";
517                 message += disclaimer;
518                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
519                                      message.c_str(), api_name, parameter_name.get_name().c_str(), header_version,
520                                      parameter_name.get_name().c_str());
521             } else {
522                 const VkStructureType *start = allowed_types;
523                 const VkStructureType *end = allowed_types + allowed_type_count;
524                 const VkBaseOutStructure *current = reinterpret_cast<const VkBaseOutStructure *>(next);
525 
526                 cycle_check.insert(next);
527 
528                 while (current != NULL) {
529                     if (((strncmp(api_name, "vkCreateInstance", strlen(api_name)) != 0) ||
530                          (current->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)) &&
531                         ((strncmp(api_name, "vkCreateDevice", strlen(api_name)) != 0) ||
532                          (current->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO))) {
533                         if (cycle_check.find(current->pNext) != cycle_check.end()) {
534                             std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
535                             skip_call |=
536                                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
537                                         kVUID_PVError_InvalidStructPNext, message.c_str(), api_name,
538                                         parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next));
539                             break;
540                         } else {
541                             cycle_check.insert(current->pNext);
542                         }
543 
544                         std::string type_name = string_VkStructureType(current->sType);
545                         if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
546                             std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
547                             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
548                                                  VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_PVError_InvalidStructPNext,
549                                                  message.c_str(), api_name, parameter_name.get_name().c_str(), type_name.c_str());
550                         } else {
551                             unique_stype_check.insert(current->sType);
552                         }
553 
554                         if (std::find(start, end, current->sType) == end) {
555                             if (type_name == UnsupportedStructureTypeString) {
556                                 std::string message =
557                                     "%s: %s chain includes a structure with unknown VkStructureType (%d); Allowed structures are "
558                                     "[%s]. ";
559                                 message += disclaimer;
560                                 skip_call |=
561                                     log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
562                                             0, vuid, message.c_str(), api_name, parameter_name.get_name().c_str(), current->sType,
563                                             allowed_struct_names, header_version, parameter_name.get_name().c_str());
564                             } else {
565                                 std::string message =
566                                     "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are "
567                                     "[%s]. ";
568                                 message += disclaimer;
569                                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
570                                                      VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, message.c_str(), api_name,
571                                                      parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names,
572                                                      header_version, parameter_name.get_name().c_str());
573                             }
574                         }
575                         skip_call |= ValidatePnextStructContents(api_name, parameter_name, current);
576                     }
577                     current = reinterpret_cast<const VkBaseOutStructure *>(current->pNext);
578                 }
579             }
580         }
581 
582         return skip_call;
583     }
584 
585     /**
586      * Validate a VkBool32 value.
587      *
588      * Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
589      *
590      * @param apiName Name of API call being validated.
591      * @param parameterName Name of parameter being validated.
592      * @param value Boolean value to validate.
593      * @return Boolean value indicating that the call should be skipped.
594      */
validate_bool32(const char * apiName,const ParameterName & parameterName,VkBool32 value)595     bool validate_bool32(const char *apiName, const ParameterName &parameterName, VkBool32 value) {
596         bool skip_call = false;
597 
598         if ((value != VK_TRUE) && (value != VK_FALSE)) {
599             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
600                                  kVUID_PVError_UnrecognizedValue, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
601                                  parameterName.get_name().c_str(), value);
602         }
603 
604         return skip_call;
605     }
606 
607     /**
608      * Validate a Vulkan enumeration value.
609      *
610      * Generate a warning if an enumeration token value does not fall within the core enumeration
611      * begin and end token values, and was not added to the enumeration by an extension.  Extension
612      * provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
613      * with 1,000,000,000 as the base token value.
614      *
615      * @note This function does not expect to process enumerations defining bitmask flag bits.
616      *
617      * @param apiName Name of API call being validated.
618      * @param parameterName Name of parameter being validated.
619      * @param enumName Name of the enumeration being validated.
620      * @param valid_values The list of valid values for the enumeration.
621      * @param value Enumeration value to validate.
622      * @return Boolean value indicating that the call should be skipped.
623      */
624     template <typename T>
validate_ranged_enum(const char * apiName,const ParameterName & parameterName,const char * enumName,const std::vector<T> & valid_values,T value,const char * vuid)625     bool validate_ranged_enum(const char *apiName, const ParameterName &parameterName, const char *enumName,
626                               const std::vector<T> &valid_values, T value, const char *vuid) {
627         bool skip = false;
628 
629         if (std::find(valid_values.begin(), valid_values.end(), value) == valid_values.end()) {
630             skip |=
631                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
632                         "%s: value of %s (%d) does not fall within the begin..end range of the core %s enumeration tokens and is "
633                         "not an extension added token.",
634                         apiName, parameterName.get_name().c_str(), value, enumName);
635         }
636 
637         return skip;
638     }
639 
640     /**
641      * Validate an array of Vulkan enumeration value.
642      *
643      * Process all enumeration token values in the specified array and generate a warning if a value
644      * does not fall within the core enumeration begin and end token values, and was not added to
645      * the enumeration by an extension.  Extension provided enumerations use the equation specified
646      * in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
647      *
648      * @note This function does not expect to process enumerations defining bitmask flag bits.
649      *
650      * @param apiName Name of API call being validated.
651      * @param countName Name of count parameter.
652      * @param arrayName Name of array parameter.
653      * @param enumName Name of the enumeration being validated.
654      * @param valid_values The list of valid values for the enumeration.
655      * @param count Number of enumeration values in the array.
656      * @param array Array of enumeration values to validate.
657      * @param countRequired The 'count' parameter may not be 0 when true.
658      * @param arrayRequired The 'array' parameter may not be NULL when true.
659      * @return Boolean value indicating that the call should be skipped.
660      */
661     template <typename T>
validate_ranged_enum_array(const char * apiName,const ParameterName & countName,const ParameterName & arrayName,const char * enumName,const std::vector<T> & valid_values,uint32_t count,const T * array,bool countRequired,bool arrayRequired)662     bool validate_ranged_enum_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName,
663                                     const char *enumName, const std::vector<T> &valid_values, uint32_t count, const T *array,
664                                     bool countRequired, bool arrayRequired) {
665         bool skip_call = false;
666 
667         if ((count == 0) || (array == NULL)) {
668             skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired, kVUIDUndefined,
669                                         kVUIDUndefined);
670         } else {
671             for (uint32_t i = 0; i < count; ++i) {
672                 if (std::find(valid_values.begin(), valid_values.end(), array[i]) == valid_values.end()) {
673                     skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
674                                          kVUID_PVError_UnrecognizedValue,
675                                          "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
676                                          "enumeration tokens and is not an extension added token",
677                                          apiName, arrayName.get_name().c_str(), i, array[i], enumName);
678                 }
679             }
680         }
681 
682         return skip_call;
683     }
684 
685     /**
686      * Verify that a reserved VkFlags value is zero.
687      *
688      * Verify that the specified value is zero, to check VkFlags values that are reserved for
689      * future use.
690      *
691      * @param api_name Name of API call being validated.
692      * @param parameter_name Name of parameter being validated.
693      * @param value Value to validate.
694      * @return Boolean value indicating that the call should be skipped.
695      */
validate_reserved_flags(const char * api_name,const ParameterName & parameter_name,VkFlags value,const char * vuid)696     bool validate_reserved_flags(const char *api_name, const ParameterName &parameter_name, VkFlags value, const char *vuid) {
697         bool skip_call = false;
698 
699         if (value != 0) {
700             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
701                                  "%s: parameter %s must be 0.", api_name, parameter_name.get_name().c_str());
702         }
703 
704         return skip_call;
705     }
706 
707     enum FlagType { kRequiredFlags, kOptionalFlags, kRequiredSingleBit, kOptionalSingleBit };
708 
709     /**
710      * Validate a Vulkan bitmask value.
711      *
712      * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
713      * for that type.
714      *
715      * @param api_name Name of API call being validated.
716      * @param parameter_name Name of parameter being validated.
717      * @param flag_bits_name Name of the VkFlags type being validated.
718      * @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
719      * @param value VkFlags value to validate.
720      * @param flag_type The type of flag, like optional, or single bit.
721      * @param vuid VUID used for flag that is outside defined bits (or has more than one bit for Bits type).
722      * @param flags_zero_vuid VUID used for non-optional Flags that are zero.
723      * @return Boolean value indicating that the call should be skipped.
724      */
725     bool validate_flags(const char *api_name, const ParameterName &parameter_name, const char *flag_bits_name, VkFlags all_flags,
726                         VkFlags value, const FlagType flag_type, const char *vuid, const char *flags_zero_vuid = nullptr) {
727         bool skip_call = false;
728 
729         if ((value & ~all_flags) != 0) {
730             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
731                                  "%s: value of %s contains flag bits that are not recognized members of %s", api_name,
732                                  parameter_name.get_name().c_str(), flag_bits_name);
733         }
734 
735         const bool required = flag_type == kRequiredFlags || flag_type == kRequiredSingleBit;
736         const char *zero_vuid = flag_type == kRequiredFlags ? flags_zero_vuid : vuid;
737         if (required && value == 0) {
738             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, zero_vuid,
739                                  "%s: value of %s must not be 0.", api_name, parameter_name.get_name().c_str());
740         }
741 
742         const auto HasMaxOneBitSet = [](const VkFlags f) {
743             // Decrement flips bits from right upto first 1.
744             // Rest stays same, and if there was any other 1s &ded together they would be non-zero. QED
745             return f == 0 || !(f & (f - 1));
746         };
747 
748         const bool is_bits_type = flag_type == kRequiredSingleBit || flag_type == kOptionalSingleBit;
749         if (is_bits_type && !HasMaxOneBitSet(value)) {
750             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
751                                  "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
752                                  parameter_name.get_name().c_str(), flag_bits_name);
753         }
754 
755         return skip_call;
756     }
757 
758     /**
759      * Validate an array of Vulkan bitmask values.
760      *
761      * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
762      * for that type.
763      *
764      * @param api_name Name of API call being validated.
765      * @param count_name Name of parameter being validated.
766      * @param array_name Name of parameter being validated.
767      * @param flag_bits_name Name of the VkFlags type being validated.
768      * @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
769      * @param count Number of VkFlags values in the array.
770      * @param array Array of VkFlags value to validate.
771      * @param count_required The 'count' parameter may not be 0 when true.
772      * @param array_required The 'array' parameter may not be NULL when true.
773      * @return Boolean value indicating that the call should be skipped.
774      */
validate_flags_array(const char * api_name,const ParameterName & count_name,const ParameterName & array_name,const char * flag_bits_name,VkFlags all_flags,uint32_t count,const VkFlags * array,bool count_required,bool array_required)775     bool validate_flags_array(const char *api_name, const ParameterName &count_name, const ParameterName &array_name,
776                               const char *flag_bits_name, VkFlags all_flags, uint32_t count, const VkFlags *array,
777                               bool count_required, bool array_required) {
778         bool skip_call = false;
779 
780         if ((count == 0) || (array == NULL)) {
781             skip_call |= validate_array(api_name, count_name, array_name, count, &array, count_required, array_required,
782                                         kVUIDUndefined, kVUIDUndefined);
783         } else {
784             // Verify that all VkFlags values in the array
785             for (uint32_t i = 0; i < count; ++i) {
786                 if (array[i] == 0) {
787                     // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
788                     // elements in the array are allowed be 0
789                     if (array_required) {
790                         skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
791                                              kVUID_PVError_RequiredParameter, "%s: value of %s[%d] must not be 0", api_name,
792                                              array_name.get_name().c_str(), i);
793                     }
794                 } else if ((array[i] & (~all_flags)) != 0) {
795                     skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
796                                          kVUID_PVError_UnrecognizedValue,
797                                          "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
798                                          array_name.get_name().c_str(), i, flag_bits_name);
799                 }
800             }
801         }
802 
803         return skip_call;
804     }
805 
806     template <typename ExtensionState>
validate_extension_reqs(const ExtensionState & extensions,const char * vuid,const char * extension_type,const char * extension_name)807     bool validate_extension_reqs(const ExtensionState &extensions, const char *vuid, const char *extension_type,
808                                  const char *extension_name) {
809         bool skip = false;
810         if (!extension_name) {
811             return skip;  // Robust to invalid char *
812         }
813         auto info = ExtensionState::get_info(extension_name);
814 
815         if (!info.state) {
816             return skip;  // Unknown extensions cannot be checked so report OK
817         }
818 
819         // Check against the required list in the info
820         std::vector<const char *> missing;
821         for (const auto &req : info.requires) {
822             if (!(extensions.*(req.enabled))) {
823                 missing.push_back(req.name);
824             }
825         }
826 
827         // Report any missing requirements
828         if (missing.size()) {
829             std::string missing_joined_list = string_join(", ", missing);
830             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
831                             HandleToUint64(instance), vuid, "Missing extension%s required by the %s extension %s: %s.",
832                             ((missing.size() > 1) ? "s" : ""), extension_type, extension_name, missing_joined_list.c_str());
833         }
834         return skip;
835     }
836 
837     enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 };
838 
839     template <typename RenderPassCreateInfoGeneric>
ValidateSubpassGraphicsFlags(const debug_report_data * report_data,const RenderPassCreateInfoGeneric * pCreateInfo,uint32_t dependency_index,uint32_t subpass,VkPipelineStageFlags stages,const char * vuid,const char * target)840     bool ValidateSubpassGraphicsFlags(const debug_report_data *report_data, const RenderPassCreateInfoGeneric *pCreateInfo,
841                                       uint32_t dependency_index, uint32_t subpass, VkPipelineStageFlags stages, const char *vuid,
842                                       const char *target) {
843         const VkPipelineStageFlags kCommonStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
844         const VkPipelineStageFlags kFramebufferStages =
845             VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
846             VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
847         const VkPipelineStageFlags kPrimitiveShadingPipelineStages =
848             kCommonStages | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
849             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
850             VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |
851             VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT | VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV | kFramebufferStages;
852         const VkPipelineStageFlags kMeshShadingPipelineStages =
853             kCommonStages | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV |
854             VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV | kFramebufferStages;
855         const VkPipelineStageFlags kFragmentDensityStages = VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT;
856         const VkPipelineStageFlags kConditionalRenderingStages = VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT;
857         const VkPipelineStageFlags kCommandProcessingPipelineStages = kCommonStages | VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX;
858 
859         const VkPipelineStageFlags kGraphicsStages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | kPrimitiveShadingPipelineStages |
860                                                      kMeshShadingPipelineStages | kFragmentDensityStages |
861                                                      kConditionalRenderingStages | kCommandProcessingPipelineStages;
862 
863         bool skip = false;
864 
865         const auto IsPipeline = [pCreateInfo](uint32_t subpass, const VkPipelineBindPoint stage) {
866             if (subpass == VK_SUBPASS_EXTERNAL)
867                 return false;
868             else
869                 return pCreateInfo->pSubpasses[subpass].pipelineBindPoint == stage;
870         };
871 
872         const bool is_all_graphics_stages = (stages & ~kGraphicsStages) == 0;
873         if (IsPipeline(subpass, VK_PIPELINE_BIND_POINT_GRAPHICS) && !is_all_graphics_stages) {
874             skip |=
875                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, 0, vuid,
876                         "Dependency pDependencies[%" PRIu32
877                         "] specifies a %sStageMask that contains stages (%s) that are not part "
878                         "of the Graphics pipeline, as specified by the %sSubpass (= %" PRIu32 ") in pipelineBindPoint.",
879                         dependency_index, target, string_VkPipelineStageFlags(stages & ~kGraphicsStages).c_str(), target, subpass);
880         }
881 
882         return skip;
883     };
884 
885     template <typename RenderPassCreateInfoGeneric>
CreateRenderPassGeneric(VkDevice device,const RenderPassCreateInfoGeneric * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkRenderPass * pRenderPass,RenderPassCreateVersion rp_version)886     bool CreateRenderPassGeneric(VkDevice device, const RenderPassCreateInfoGeneric *pCreateInfo,
887                                  const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass,
888                                  RenderPassCreateVersion rp_version) {
889         bool skip = false;
890         uint32_t max_color_attachments = device_limits.maxColorAttachments;
891         bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
892         const char *vuid;
893 
894         for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
895             if (pCreateInfo->pAttachments[i].format == VK_FORMAT_UNDEFINED) {
896                 std::stringstream ss;
897                 ss << (use_rp2 ? "vkCreateRenderPass2KHR" : "vkCreateRenderPass") << ": pCreateInfo->pAttachments[" << i
898                    << "].format is VK_FORMAT_UNDEFINED. ";
899                 vuid =
900                     use_rp2 ? "VUID-VkAttachmentDescription2KHR-format-parameter" : "VUID-VkAttachmentDescription-format-parameter";
901                 skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
902                                 "%s", ss.str().c_str());
903             }
904             if (pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_UNDEFINED ||
905                 pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
906                 vuid = use_rp2 ? "VUID-VkAttachmentDescription2KHR-finalLayout-03061"
907                                : "VUID-VkAttachmentDescription-finalLayout-00843";
908                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
909                                 "pCreateInfo->pAttachments[%d].finalLayout must not be VK_IMAGE_LAYOUT_UNDEFINED or "
910                                 "VK_IMAGE_LAYOUT_PREINITIALIZED.",
911                                 i);
912             }
913         }
914 
915         for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
916             if (pCreateInfo->pSubpasses[i].colorAttachmentCount > max_color_attachments) {
917                 vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063"
918                                : "VUID-VkSubpassDescription-colorAttachmentCount-00845";
919                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
920                                 "Cannot create a render pass with %d color attachments. Max is %d.",
921                                 pCreateInfo->pSubpasses[i].colorAttachmentCount, max_color_attachments);
922             }
923         }
924 
925         for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
926             const auto &dependency = pCreateInfo->pDependencies[i];
927 
928             // Spec currently only supports Graphics pipeline in render pass -- so only that pipeline is currently checked
929             vuid =
930                 use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03054" : "VUID-VkRenderPassCreateInfo-pDependencies-00837";
931             skip |= ValidateSubpassGraphicsFlags(report_data, pCreateInfo, i, dependency.srcSubpass, dependency.srcStageMask, vuid,
932                                                  "src");
933 
934             vuid =
935                 use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03055" : "VUID-VkRenderPassCreateInfo-pDependencies-00838";
936             skip |= ValidateSubpassGraphicsFlags(report_data, pCreateInfo, i, dependency.dstSubpass, dependency.dstStageMask, vuid,
937                                                  "dst");
938         }
939 
940         return skip;
941     }
942 
943     template <typename T>
RecordRenderPass(VkRenderPass renderPass,const T * pCreateInfo)944     void RecordRenderPass(VkRenderPass renderPass, const T *pCreateInfo) {
945         std::unique_lock<std::mutex> lock(renderpass_map_mutex);
946         auto &renderpass_state = renderpasses_states[renderPass];
947         lock.unlock();
948 
949         for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
950             bool uses_color = false;
951             for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i)
952                 if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true;
953 
954             bool uses_depthstencil = false;
955             if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment)
956                 if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
957                     uses_depthstencil = true;
958 
959             if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass);
960             if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass);
961         }
962     }
963 
964     bool require_device_extension(bool flag, char const *function_name, char const *extension_name);
965 
966     bool validate_instance_extensions(const VkInstanceCreateInfo *pCreateInfo);
967 
968     bool validate_api_version(uint32_t api_version, uint32_t effective_api_version);
969 
970     bool validate_string(const char *apiName, const ParameterName &stringName, const std::string &vuid, const char *validateString);
971 
972     bool ValidateCoarseSampleOrderCustomNV(const VkCoarseSampleOrderCustomNV *order);
973 
974     bool ValidateQueueFamilies(uint32_t queue_family_count, const uint32_t *queue_families, const char *cmd_name,
975                                const char *array_parameter_name, const std::string &unique_error_code,
976                                const std::string &valid_error_code, bool optional);
977 
978     bool ValidateDeviceQueueFamily(uint32_t queue_family, const char *cmd_name, const char *parameter_name,
979                                    const std::string &error_code, bool optional);
980 
981     bool ValidateGeometryTrianglesNV(const VkGeometryTrianglesNV &triangles, VkDebugReportObjectTypeEXT object_type,
982                                      uint64_t object_handle, const char *func_name) const;
983     bool ValidateGeometryAABBNV(const VkGeometryAABBNV &geometry, VkDebugReportObjectTypeEXT object_type, uint64_t object_handle,
984                                 const char *func_name) const;
985     bool ValidateGeometryNV(const VkGeometryNV &geometry, VkDebugReportObjectTypeEXT object_type, uint64_t object_handle,
986                             const char *func_name) const;
987     bool ValidateAccelerationStructureInfoNV(const VkAccelerationStructureInfoNV &info, VkDebugReportObjectTypeEXT object_type,
988                                              uint64_t object_handle, const char *func_nam) const;
989 
990     bool OutputExtensionError(const std::string &api_name, const std::string &extension_name);
991 
992     void PostCallRecordCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
993                                         const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, VkResult result);
994     void PostCallRecordCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
995                                             const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, VkResult result);
996     void PostCallRecordDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator);
997     void PostCallRecordCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
998                                     const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result);
999 
1000     void PostCallRecordCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
1001                                       VkInstance *pInstance, VkResult result);
1002 
1003     void PostCallRecordQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo, VkResult result);
1004 
1005     bool manual_PreCallValidateCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
1006                                                const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool);
1007 
1008     bool manual_PreCallValidateCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
1009                                               VkInstance *pInstance);
1010 
1011     bool manual_PreCallValidateCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
1012                                             const VkAllocationCallbacks *pAllocator, VkDevice *pDevice);
1013 
1014     bool manual_PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
1015                                             const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer);
1016 
1017     bool manual_PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
1018                                            const VkAllocationCallbacks *pAllocator, VkImage *pImage);
1019 
1020     bool manual_PreCallValidateViewport(const VkViewport &viewport, const char *fn_name, const ParameterName &parameter_name,
1021                                         VkDebugReportObjectTypeEXT object_type, uint64_t object);
1022 
1023     bool manual_PreCallValidateCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
1024                                                        const VkGraphicsPipelineCreateInfo *pCreateInfos,
1025                                                        const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines);
1026     bool manual_PreCallValidateCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
1027                                                       const VkComputePipelineCreateInfo *pCreateInfos,
1028                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines);
1029 
1030     bool manual_PreCallValidateCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
1031                                              const VkAllocationCallbacks *pAllocator, VkSampler *pSampler);
1032     bool manual_PreCallValidateCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
1033                                                          const VkAllocationCallbacks *pAllocator,
1034                                                          VkDescriptorSetLayout *pSetLayout);
1035 
1036     bool manual_PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
1037                                                     const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
1038                                                     const VkCopyDescriptorSet *pDescriptorCopies);
1039 
1040     bool manual_PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount,
1041                                                   const VkDescriptorSet *pDescriptorSets);
1042 
1043     bool manual_PreCallValidateCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
1044                                                 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
1045 
1046     bool manual_PreCallValidateCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
1047                                                     const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
1048 
1049     bool manual_PreCallValidateFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
1050                                                   const VkCommandBuffer *pCommandBuffers);
1051 
1052     bool manual_PreCallValidateBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo);
1053 
1054     bool manual_PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
1055                                               const VkViewport *pViewports);
1056 
1057     bool manual_PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
1058                                              const VkRect2D *pScissors);
1059     bool manual_PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth);
1060 
1061     bool manual_PreCallValidateCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
1062                                        uint32_t firstVertex, uint32_t firstInstance);
1063 
1064     bool manual_PreCallValidateCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
1065                                                uint32_t stride);
1066 
1067     bool manual_PreCallValidateCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
1068                                                       uint32_t count, uint32_t stride);
1069 
1070     bool manual_PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
1071                                                    const VkClearAttachment *pAttachments, uint32_t rectCount,
1072                                                    const VkClearRect *pRects);
1073 
1074     bool manual_PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1075                                             VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1076                                             const VkImageCopy *pRegions);
1077 
1078     bool manual_PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1079                                             VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1080                                             const VkImageBlit *pRegions, VkFilter filter);
1081 
1082     bool manual_PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
1083                                                     VkImageLayout dstImageLayout, uint32_t regionCount,
1084                                                     const VkBufferImageCopy *pRegions);
1085 
1086     bool manual_PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1087                                                     VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions);
1088 
1089     bool manual_PreCallValidateCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
1090                                                VkDeviceSize dataSize, const void *pData);
1091 
1092     bool manual_PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
1093                                              VkDeviceSize size, uint32_t data);
1094 
1095     bool manual_PreCallValidateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
1096                                                   const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain);
1097     bool manual_PreCallValidateQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo);
1098 
1099 #ifdef VK_USE_PLATFORM_WIN32_KHR
1100     bool manual_PreCallValidateCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
1101                                                      const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface);
1102 #endif  // VK_USE_PLATFORM_WIN32_KHR
1103 
1104     bool manual_PreCallValidateCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
1105                                                     const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool);
1106     bool manual_PreCallValidateCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY,
1107                                            uint32_t groupCountZ);
1108 
1109     bool manual_PreCallValidateCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
1110 
1111     bool manual_PreCallValidateCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY,
1112                                                   uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY,
1113                                                   uint32_t groupCountZ);
1114     bool manual_PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor,
1115                                                         uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors);
1116     bool manual_PreCallValidateCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
1117                                                                   uint32_t viewportCount,
1118                                                                   const VkShadingRatePaletteNV *pShadingRatePalettes);
1119 
1120     bool manual_PreCallValidateCmdSetCoarseSampleOrderNV(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType,
1121                                                          uint32_t customSampleOrderCount,
1122                                                          const VkCoarseSampleOrderCustomNV *pCustomSampleOrders);
1123 
1124     bool manual_PreCallValidateCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask);
1125     bool manual_PreCallValidateCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
1126                                                           uint32_t drawCount, uint32_t stride);
1127 
1128     bool manual_PreCallValidateCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
1129                                                                VkBuffer countBuffer, VkDeviceSize countBufferOffset,
1130                                                                uint32_t maxDrawCount, uint32_t stride);
1131 
1132     bool manual_PreCallValidateEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
1133                                                                   uint32_t *pPropertyCount, VkExtensionProperties *pProperties);
1134     bool manual_PreCallValidateAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
1135                                               const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory);
1136 
1137     bool manual_PreCallValidateCreateAccelerationStructureNV(VkDevice device,
1138                                                              const VkAccelerationStructureCreateInfoNV *pCreateInfo,
1139                                                              const VkAllocationCallbacks *pAllocator,
1140                                                              VkAccelerationStructureNV *pAccelerationStructure);
1141     bool manual_PreCallValidateCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer,
1142                                                                const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData,
1143                                                                VkDeviceSize instanceOffset, VkBool32 update,
1144                                                                VkAccelerationStructureNV dst, VkAccelerationStructureNV src,
1145                                                                VkBuffer scratch, VkDeviceSize scratchOffset);
1146     bool manual_PreCallValidateGetAccelerationStructureHandleNV(VkDevice device, VkAccelerationStructureNV accelerationStructure,
1147                                                                 size_t dataSize, void *pData);
1148     bool manual_PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
1149                                                            const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
1150                                                            const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines);
1151 
1152 #ifdef VK_USE_PLATFORM_WIN32_KHR
1153     bool PreCallValidateGetDeviceGroupSurfacePresentModes2EXT(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
1154                                                               VkDeviceGroupPresentModeFlagsKHR *pModes);
1155 #endif  // VK_USE_PLATFORM_WIN32_KHR
1156 
1157     bool manual_PreCallValidateCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
1158                                                  const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer);
1159 
1160     bool manual_PreCallValidateCmdSetLineStippleEXT(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor,
1161                                                     uint16_t lineStipplePattern);
1162 
1163     bool manual_PreCallValidateCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
1164                                                   VkIndexType indexType);
1165 
1166 #include "parameter_validation.h"
1167 };  // Class StatelessValidation
1168