parameter_validation.cpp revision 059e07e5fff8ea8b6108fe900e573d845fb98bf0
1/* 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 *
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: Jeremy Hayes <jeremy@lunarg.com>
19 * Author: Tony Barbour <tony@LunarG.com>
20 * Author: Mark Lobodzinski <mark@LunarG.com>
21 * Author: Dustin Graves <dustin@lunarg.com>
22 */
23
24#define NOMINMAX
25
26#include <math.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include <iostream>
32#include <string>
33#include <sstream>
34#include <unordered_map>
35#include <unordered_set>
36#include <vector>
37
38#include "vk_loader_platform.h"
39#include "vulkan/vk_layer.h"
40#include "vk_layer_config.h"
41#include "vk_enum_validate_helper.h"
42#include "vk_struct_validate_helper.h"
43
44#include "vk_layer_table.h"
45#include "vk_layer_data.h"
46#include "vk_layer_logging.h"
47#include "vk_layer_extension_utils.h"
48#include "vk_layer_utils.h"
49
50#include "parameter_validation.h"
51
52namespace parameter_validation {
53
54struct layer_data {
55    VkInstance instance;
56
57    debug_report_data *report_data;
58    std::vector<VkDebugReportCallbackEXT> logging_callback;
59
60    // The following are for keeping track of the temporary callbacks that can
61    // be used in vkCreateInstance and vkDestroyInstance:
62    uint32_t num_tmp_callbacks;
63    VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
64    VkDebugReportCallbackEXT *tmp_callbacks;
65
66    // TODO: Split instance/device structs
67    // Device Data
68    // Map for queue family index to queue count
69    std::unordered_map<uint32_t, uint32_t> queueFamilyIndexMap;
70    VkPhysicalDeviceLimits device_limits;
71    VkPhysicalDeviceFeatures physical_device_features;
72    VkPhysicalDevice physical_device;
73
74    layer_data()
75        : report_data(nullptr), num_tmp_callbacks(0), tmp_dbg_create_infos(nullptr), tmp_callbacks(nullptr), device_limits{},
76          physical_device_features{}, physical_device{} {};
77};
78
79static std::unordered_map<void *, layer_data *> layer_data_map;
80static device_table_map pc_device_table_map;
81static instance_table_map pc_instance_table_map;
82
83// "my instance data"
84debug_report_data *mid(VkInstance object) {
85    dispatch_key key = get_dispatch_key(object);
86    layer_data *data = get_my_data_ptr(key, layer_data_map);
87#if DISPATCH_MAP_DEBUG
88    fprintf(stderr, "MID: map:  0x%p, object:  0x%p, key:  0x%p, data:  0x%p\n", &layer_data_map, object, key, data);
89#endif
90    assert(data != NULL);
91
92    return data->report_data;
93}
94
95// "my device data"
96debug_report_data *mdd(void *object) {
97    dispatch_key key = get_dispatch_key(object);
98    layer_data *data = get_my_data_ptr(key, layer_data_map);
99#if DISPATCH_MAP_DEBUG
100    fprintf(stderr, "MDD: map:  0x%p, object:  0x%p, key:  0x%p, data:  0x%p\n", &layer_data_map, object, key, data);
101#endif
102    assert(data != NULL);
103    return data->report_data;
104}
105
106static void init_parameter_validation(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
107
108    layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_parameter_validation");
109}
110
111VKAPI_ATTR VkResult VKAPI_CALL
112CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
113                             const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
114    VkLayerInstanceDispatchTable *pTable = get_dispatch_table(pc_instance_table_map, instance);
115    VkResult result = pTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
116
117    if (result == VK_SUCCESS) {
118        layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
119        result = layer_create_msg_callback(data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
120    }
121
122    return result;
123}
124
125VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance,
126                                                         VkDebugReportCallbackEXT msgCallback,
127                                                         const VkAllocationCallbacks *pAllocator) {
128    VkLayerInstanceDispatchTable *pTable = get_dispatch_table(pc_instance_table_map, instance);
129    pTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
130
131    layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
132    layer_destroy_msg_callback(data->report_data, msgCallback, pAllocator);
133}
134
135VKAPI_ATTR void VKAPI_CALL
136DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
137                      size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
138    VkLayerInstanceDispatchTable *pTable = get_dispatch_table(pc_instance_table_map, instance);
139    pTable->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
140}
141
142static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
143
144static const VkLayerProperties global_layer = {
145    "VK_LAYER_LUNARG_parameter_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
146};
147
148static bool ValidateEnumerator(VkFormatFeatureFlagBits const &enumerator) {
149    VkFormatFeatureFlagBits allFlags = (VkFormatFeatureFlagBits)(
150        VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
151        VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT |
152        VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT | VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT |
153        VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
154        VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT |
155        VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
156    if (enumerator & (~allFlags)) {
157        return false;
158    }
159
160    return true;
161}
162
163static std::string EnumeratorString(VkFormatFeatureFlagBits const &enumerator) {
164    if (!ValidateEnumerator(enumerator)) {
165        return "unrecognized enumerator";
166    }
167
168    std::vector<std::string> strings;
169    if (enumerator & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT) {
170        strings.push_back("VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT");
171    }
172    if (enumerator & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) {
173        strings.push_back("VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT");
174    }
175    if (enumerator & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT) {
176        strings.push_back("VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT");
177    }
178    if (enumerator & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT) {
179        strings.push_back("VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT");
180    }
181    if (enumerator & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
182        strings.push_back("VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT");
183    }
184    if (enumerator & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT) {
185        strings.push_back("VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT");
186    }
187    if (enumerator & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) {
188        strings.push_back("VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT");
189    }
190    if (enumerator & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) {
191        strings.push_back("VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT");
192    }
193    if (enumerator & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
194        strings.push_back("VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT");
195    }
196    if (enumerator & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
197        strings.push_back("VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT");
198    }
199    if (enumerator & VK_FORMAT_FEATURE_BLIT_SRC_BIT) {
200        strings.push_back("VK_FORMAT_FEATURE_BLIT_SRC_BIT");
201    }
202    if (enumerator & VK_FORMAT_FEATURE_BLIT_DST_BIT) {
203        strings.push_back("VK_FORMAT_FEATURE_BLIT_DST_BIT");
204    }
205    if (enumerator & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) {
206        strings.push_back("VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT");
207    }
208
209    std::string enumeratorString;
210    for (auto const &string : strings) {
211        enumeratorString += string;
212
213        if (string != strings.back()) {
214            enumeratorString += '|';
215        }
216    }
217
218    return enumeratorString;
219}
220
221static bool ValidateEnumerator(VkImageUsageFlagBits const &enumerator) {
222    VkImageUsageFlagBits allFlags = (VkImageUsageFlagBits)(
223        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
224        VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
225        VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
226    if (enumerator & (~allFlags)) {
227        return false;
228    }
229
230    return true;
231}
232
233static std::string EnumeratorString(VkImageUsageFlagBits const &enumerator) {
234    if (!ValidateEnumerator(enumerator)) {
235        return "unrecognized enumerator";
236    }
237
238    std::vector<std::string> strings;
239    if (enumerator & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
240        strings.push_back("VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT");
241    }
242    if (enumerator & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
243        strings.push_back("VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT");
244    }
245    if (enumerator & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
246        strings.push_back("VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT");
247    }
248    if (enumerator & VK_IMAGE_USAGE_STORAGE_BIT) {
249        strings.push_back("VK_IMAGE_USAGE_STORAGE_BIT");
250    }
251    if (enumerator & VK_IMAGE_USAGE_SAMPLED_BIT) {
252        strings.push_back("VK_IMAGE_USAGE_SAMPLED_BIT");
253    }
254    if (enumerator & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
255        strings.push_back("VK_IMAGE_USAGE_TRANSFER_DST_BIT");
256    }
257    if (enumerator & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
258        strings.push_back("VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT");
259    }
260    if (enumerator & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
261        strings.push_back("VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
262    }
263
264    std::string enumeratorString;
265    for (auto const &string : strings) {
266        enumeratorString += string;
267
268        if (string != strings.back()) {
269            enumeratorString += '|';
270        }
271    }
272
273    return enumeratorString;
274}
275
276static bool ValidateEnumerator(VkQueueFlagBits const &enumerator) {
277    VkQueueFlagBits allFlags =
278        (VkQueueFlagBits)(VK_QUEUE_TRANSFER_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_SPARSE_BINDING_BIT | VK_QUEUE_GRAPHICS_BIT);
279    if (enumerator & (~allFlags)) {
280        return false;
281    }
282
283    return true;
284}
285
286static std::string EnumeratorString(VkQueueFlagBits const &enumerator) {
287    if (!ValidateEnumerator(enumerator)) {
288        return "unrecognized enumerator";
289    }
290
291    std::vector<std::string> strings;
292    if (enumerator & VK_QUEUE_TRANSFER_BIT) {
293        strings.push_back("VK_QUEUE_TRANSFER_BIT");
294    }
295    if (enumerator & VK_QUEUE_COMPUTE_BIT) {
296        strings.push_back("VK_QUEUE_COMPUTE_BIT");
297    }
298    if (enumerator & VK_QUEUE_SPARSE_BINDING_BIT) {
299        strings.push_back("VK_QUEUE_SPARSE_BINDING_BIT");
300    }
301    if (enumerator & VK_QUEUE_GRAPHICS_BIT) {
302        strings.push_back("VK_QUEUE_GRAPHICS_BIT");
303    }
304
305    std::string enumeratorString;
306    for (auto const &string : strings) {
307        enumeratorString += string;
308
309        if (string != strings.back()) {
310            enumeratorString += '|';
311        }
312    }
313
314    return enumeratorString;
315}
316
317static bool ValidateEnumerator(VkMemoryPropertyFlagBits const &enumerator) {
318    VkMemoryPropertyFlagBits allFlags = (VkMemoryPropertyFlagBits)(
319        VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
320        VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
321    if (enumerator & (~allFlags)) {
322        return false;
323    }
324
325    return true;
326}
327
328static std::string EnumeratorString(VkMemoryPropertyFlagBits const &enumerator) {
329    if (!ValidateEnumerator(enumerator)) {
330        return "unrecognized enumerator";
331    }
332
333    std::vector<std::string> strings;
334    if (enumerator & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
335        strings.push_back("VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT");
336    }
337    if (enumerator & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
338        strings.push_back("VK_MEMORY_PROPERTY_HOST_COHERENT_BIT");
339    }
340    if (enumerator & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
341        strings.push_back("VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT");
342    }
343    if (enumerator & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
344        strings.push_back("VK_MEMORY_PROPERTY_HOST_CACHED_BIT");
345    }
346    if (enumerator & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
347        strings.push_back("VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT");
348    }
349
350    std::string enumeratorString;
351    for (auto const &string : strings) {
352        enumeratorString += string;
353
354        if (string != strings.back()) {
355            enumeratorString += '|';
356        }
357    }
358
359    return enumeratorString;
360}
361
362static bool ValidateEnumerator(VkMemoryHeapFlagBits const &enumerator) {
363    VkMemoryHeapFlagBits allFlags = (VkMemoryHeapFlagBits)(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT);
364    if (enumerator & (~allFlags)) {
365        return false;
366    }
367
368    return true;
369}
370
371static std::string EnumeratorString(VkMemoryHeapFlagBits const &enumerator) {
372    if (!ValidateEnumerator(enumerator)) {
373        return "unrecognized enumerator";
374    }
375
376    std::vector<std::string> strings;
377    if (enumerator & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
378        strings.push_back("VK_MEMORY_HEAP_DEVICE_LOCAL_BIT");
379    }
380
381    std::string enumeratorString;
382    for (auto const &string : strings) {
383        enumeratorString += string;
384
385        if (string != strings.back()) {
386            enumeratorString += '|';
387        }
388    }
389
390    return enumeratorString;
391}
392
393static bool ValidateEnumerator(VkSparseImageFormatFlagBits const &enumerator) {
394    VkSparseImageFormatFlagBits allFlags =
395        (VkSparseImageFormatFlagBits)(VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT |
396                                      VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT | VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT);
397    if (enumerator & (~allFlags)) {
398        return false;
399    }
400
401    return true;
402}
403
404static std::string EnumeratorString(VkSparseImageFormatFlagBits const &enumerator) {
405    if (!ValidateEnumerator(enumerator)) {
406        return "unrecognized enumerator";
407    }
408
409    std::vector<std::string> strings;
410    if (enumerator & VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT) {
411        strings.push_back("VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT");
412    }
413    if (enumerator & VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT) {
414        strings.push_back("VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT");
415    }
416    if (enumerator & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) {
417        strings.push_back("VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT");
418    }
419
420    std::string enumeratorString;
421    for (auto const &string : strings) {
422        enumeratorString += string;
423
424        if (string != strings.back()) {
425            enumeratorString += '|';
426        }
427    }
428
429    return enumeratorString;
430}
431
432static bool ValidateEnumerator(VkFenceCreateFlagBits const &enumerator) {
433    VkFenceCreateFlagBits allFlags = (VkFenceCreateFlagBits)(VK_FENCE_CREATE_SIGNALED_BIT);
434    if (enumerator & (~allFlags)) {
435        return false;
436    }
437
438    return true;
439}
440
441static std::string EnumeratorString(VkFenceCreateFlagBits const &enumerator) {
442    if (!ValidateEnumerator(enumerator)) {
443        return "unrecognized enumerator";
444    }
445
446    std::vector<std::string> strings;
447    if (enumerator & VK_FENCE_CREATE_SIGNALED_BIT) {
448        strings.push_back("VK_FENCE_CREATE_SIGNALED_BIT");
449    }
450
451    std::string enumeratorString;
452    for (auto const &string : strings) {
453        enumeratorString += string;
454
455        if (string != strings.back()) {
456            enumeratorString += '|';
457        }
458    }
459
460    return enumeratorString;
461}
462
463static bool ValidateEnumerator(VkQueryPipelineStatisticFlagBits const &enumerator) {
464    VkQueryPipelineStatisticFlagBits allFlags = (VkQueryPipelineStatisticFlagBits)(
465        VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT |
466        VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT |
467        VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT |
468        VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT |
469        VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT |
470        VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT |
471        VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT);
472    if (enumerator & (~allFlags)) {
473        return false;
474    }
475
476    return true;
477}
478
479static std::string EnumeratorString(VkQueryPipelineStatisticFlagBits const &enumerator) {
480    if (!ValidateEnumerator(enumerator)) {
481        return "unrecognized enumerator";
482    }
483
484    std::vector<std::string> strings;
485    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT) {
486        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT");
487    }
488    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT) {
489        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT");
490    }
491    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT) {
492        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT");
493    }
494    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT) {
495        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT");
496    }
497    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT) {
498        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT");
499    }
500    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT) {
501        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT");
502    }
503    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT) {
504        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT");
505    }
506    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT) {
507        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT");
508    }
509    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT) {
510        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT");
511    }
512    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT) {
513        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT");
514    }
515    if (enumerator & VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT) {
516        strings.push_back("VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT");
517    }
518
519    std::string enumeratorString;
520    for (auto const &string : strings) {
521        enumeratorString += string;
522
523        if (string != strings.back()) {
524            enumeratorString += '|';
525        }
526    }
527
528    return enumeratorString;
529}
530
531static bool ValidateEnumerator(VkQueryResultFlagBits const &enumerator) {
532    VkQueryResultFlagBits allFlags = (VkQueryResultFlagBits)(VK_QUERY_RESULT_PARTIAL_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT |
533                                                             VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT);
534    if (enumerator & (~allFlags)) {
535        return false;
536    }
537
538    return true;
539}
540
541static std::string EnumeratorString(VkQueryResultFlagBits const &enumerator) {
542    if (!ValidateEnumerator(enumerator)) {
543        return "unrecognized enumerator";
544    }
545
546    std::vector<std::string> strings;
547    if (enumerator & VK_QUERY_RESULT_PARTIAL_BIT) {
548        strings.push_back("VK_QUERY_RESULT_PARTIAL_BIT");
549    }
550    if (enumerator & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) {
551        strings.push_back("VK_QUERY_RESULT_WITH_AVAILABILITY_BIT");
552    }
553    if (enumerator & VK_QUERY_RESULT_WAIT_BIT) {
554        strings.push_back("VK_QUERY_RESULT_WAIT_BIT");
555    }
556    if (enumerator & VK_QUERY_RESULT_64_BIT) {
557        strings.push_back("VK_QUERY_RESULT_64_BIT");
558    }
559
560    std::string enumeratorString;
561    for (auto const &string : strings) {
562        enumeratorString += string;
563
564        if (string != strings.back()) {
565            enumeratorString += '|';
566        }
567    }
568
569    return enumeratorString;
570}
571
572static bool ValidateEnumerator(VkBufferUsageFlagBits const &enumerator) {
573    VkBufferUsageFlagBits allFlags = (VkBufferUsageFlagBits)(
574        VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT |
575        VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
576        VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
577    if (enumerator & (~allFlags)) {
578        return false;
579    }
580
581    return true;
582}
583
584static std::string EnumeratorString(VkBufferUsageFlagBits const &enumerator) {
585    if (!ValidateEnumerator(enumerator)) {
586        return "unrecognized enumerator";
587    }
588
589    std::vector<std::string> strings;
590    if (enumerator & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) {
591        strings.push_back("VK_BUFFER_USAGE_VERTEX_BUFFER_BIT");
592    }
593    if (enumerator & VK_BUFFER_USAGE_INDEX_BUFFER_BIT) {
594        strings.push_back("VK_BUFFER_USAGE_INDEX_BUFFER_BIT");
595    }
596    if (enumerator & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT) {
597        strings.push_back("VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT");
598    }
599    if (enumerator & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) {
600        strings.push_back("VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT");
601    }
602    if (enumerator & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
603        strings.push_back("VK_BUFFER_USAGE_STORAGE_BUFFER_BIT");
604    }
605    if (enumerator & VK_BUFFER_USAGE_TRANSFER_DST_BIT) {
606        strings.push_back("VK_BUFFER_USAGE_TRANSFER_DST_BIT");
607    }
608    if (enumerator & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) {
609        strings.push_back("VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT");
610    }
611    if (enumerator & VK_BUFFER_USAGE_TRANSFER_SRC_BIT) {
612        strings.push_back("VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
613    }
614    if (enumerator & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
615        strings.push_back("VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT");
616    }
617
618    std::string enumeratorString;
619    for (auto const &string : strings) {
620        enumeratorString += string;
621
622        if (string != strings.back()) {
623            enumeratorString += '|';
624        }
625    }
626
627    return enumeratorString;
628}
629
630static bool ValidateEnumerator(VkBufferCreateFlagBits const &enumerator) {
631    VkBufferCreateFlagBits allFlags = (VkBufferCreateFlagBits)(
632        VK_BUFFER_CREATE_SPARSE_ALIASED_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_BINDING_BIT);
633    if (enumerator & (~allFlags)) {
634        return false;
635    }
636
637    return true;
638}
639
640static std::string EnumeratorString(VkBufferCreateFlagBits const &enumerator) {
641    if (!ValidateEnumerator(enumerator)) {
642        return "unrecognized enumerator";
643    }
644
645    std::vector<std::string> strings;
646    if (enumerator & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) {
647        strings.push_back("VK_BUFFER_CREATE_SPARSE_ALIASED_BIT");
648    }
649    if (enumerator & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) {
650        strings.push_back("VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT");
651    }
652    if (enumerator & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) {
653        strings.push_back("VK_BUFFER_CREATE_SPARSE_BINDING_BIT");
654    }
655
656    std::string enumeratorString;
657    for (auto const &string : strings) {
658        enumeratorString += string;
659
660        if (string != strings.back()) {
661            enumeratorString += '|';
662        }
663    }
664
665    return enumeratorString;
666}
667
668static bool ValidateEnumerator(VkImageCreateFlagBits const &enumerator) {
669    VkImageCreateFlagBits allFlags = (VkImageCreateFlagBits)(
670        VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT |
671        VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT);
672    if (enumerator & (~allFlags)) {
673        return false;
674    }
675
676    return true;
677}
678
679static std::string EnumeratorString(VkImageCreateFlagBits const &enumerator) {
680    if (!ValidateEnumerator(enumerator)) {
681        return "unrecognized enumerator";
682    }
683
684    std::vector<std::string> strings;
685    if (enumerator & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) {
686        strings.push_back("VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT");
687    }
688    if (enumerator & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) {
689        strings.push_back("VK_IMAGE_CREATE_SPARSE_ALIASED_BIT");
690    }
691    if (enumerator & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) {
692        strings.push_back("VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT");
693    }
694    if (enumerator & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) {
695        strings.push_back("VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT");
696    }
697    if (enumerator & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) {
698        strings.push_back("VK_IMAGE_CREATE_SPARSE_BINDING_BIT");
699    }
700
701    std::string enumeratorString;
702    for (auto const &string : strings) {
703        enumeratorString += string;
704
705        if (string != strings.back()) {
706            enumeratorString += '|';
707        }
708    }
709
710    return enumeratorString;
711}
712
713static bool ValidateEnumerator(VkColorComponentFlagBits const &enumerator) {
714    VkColorComponentFlagBits allFlags = (VkColorComponentFlagBits)(VK_COLOR_COMPONENT_A_BIT | VK_COLOR_COMPONENT_B_BIT |
715                                                                   VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_R_BIT);
716    if (enumerator & (~allFlags)) {
717        return false;
718    }
719
720    return true;
721}
722
723static std::string EnumeratorString(VkColorComponentFlagBits const &enumerator) {
724    if (!ValidateEnumerator(enumerator)) {
725        return "unrecognized enumerator";
726    }
727
728    std::vector<std::string> strings;
729    if (enumerator & VK_COLOR_COMPONENT_A_BIT) {
730        strings.push_back("VK_COLOR_COMPONENT_A_BIT");
731    }
732    if (enumerator & VK_COLOR_COMPONENT_B_BIT) {
733        strings.push_back("VK_COLOR_COMPONENT_B_BIT");
734    }
735    if (enumerator & VK_COLOR_COMPONENT_G_BIT) {
736        strings.push_back("VK_COLOR_COMPONENT_G_BIT");
737    }
738    if (enumerator & VK_COLOR_COMPONENT_R_BIT) {
739        strings.push_back("VK_COLOR_COMPONENT_R_BIT");
740    }
741
742    std::string enumeratorString;
743    for (auto const &string : strings) {
744        enumeratorString += string;
745
746        if (string != strings.back()) {
747            enumeratorString += '|';
748        }
749    }
750
751    return enumeratorString;
752}
753
754static bool ValidateEnumerator(VkPipelineCreateFlagBits const &enumerator) {
755    VkPipelineCreateFlagBits allFlags = (VkPipelineCreateFlagBits)(
756        VK_PIPELINE_CREATE_DERIVATIVE_BIT | VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT | VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT);
757    if (enumerator & (~allFlags)) {
758        return false;
759    }
760
761    return true;
762}
763
764static std::string EnumeratorString(VkPipelineCreateFlagBits const &enumerator) {
765    if (!ValidateEnumerator(enumerator)) {
766        return "unrecognized enumerator";
767    }
768
769    std::vector<std::string> strings;
770    if (enumerator & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
771        strings.push_back("VK_PIPELINE_CREATE_DERIVATIVE_BIT");
772    }
773    if (enumerator & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT) {
774        strings.push_back("VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT");
775    }
776    if (enumerator & VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT) {
777        strings.push_back("VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT");
778    }
779
780    std::string enumeratorString;
781    for (auto const &string : strings) {
782        enumeratorString += string;
783
784        if (string != strings.back()) {
785            enumeratorString += '|';
786        }
787    }
788
789    return enumeratorString;
790}
791
792static bool ValidateEnumerator(VkShaderStageFlagBits const &enumerator) {
793    VkShaderStageFlagBits allFlags = (VkShaderStageFlagBits)(
794        VK_SHADER_STAGE_ALL | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_COMPUTE_BIT |
795        VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_VERTEX_BIT);
796    if (enumerator & (~allFlags)) {
797        return false;
798    }
799
800    return true;
801}
802
803static std::string EnumeratorString(VkShaderStageFlagBits const &enumerator) {
804    if (!ValidateEnumerator(enumerator)) {
805        return "unrecognized enumerator";
806    }
807
808    std::vector<std::string> strings;
809    if (enumerator & VK_SHADER_STAGE_ALL) {
810        strings.push_back("VK_SHADER_STAGE_ALL");
811    }
812    if (enumerator & VK_SHADER_STAGE_FRAGMENT_BIT) {
813        strings.push_back("VK_SHADER_STAGE_FRAGMENT_BIT");
814    }
815    if (enumerator & VK_SHADER_STAGE_GEOMETRY_BIT) {
816        strings.push_back("VK_SHADER_STAGE_GEOMETRY_BIT");
817    }
818    if (enumerator & VK_SHADER_STAGE_COMPUTE_BIT) {
819        strings.push_back("VK_SHADER_STAGE_COMPUTE_BIT");
820    }
821    if (enumerator & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
822        strings.push_back("VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT");
823    }
824    if (enumerator & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
825        strings.push_back("VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT");
826    }
827    if (enumerator & VK_SHADER_STAGE_VERTEX_BIT) {
828        strings.push_back("VK_SHADER_STAGE_VERTEX_BIT");
829    }
830
831    std::string enumeratorString;
832    for (auto const &string : strings) {
833        enumeratorString += string;
834
835        if (string != strings.back()) {
836            enumeratorString += '|';
837        }
838    }
839
840    return enumeratorString;
841}
842
843static bool ValidateEnumerator(VkPipelineStageFlagBits const &enumerator) {
844    VkPipelineStageFlagBits allFlags = (VkPipelineStageFlagBits)(
845        VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_HOST_BIT |
846        VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
847        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
848        VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
849        VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
850        VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
851        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
852    if (enumerator & (~allFlags)) {
853        return false;
854    }
855
856    return true;
857}
858
859static std::string EnumeratorString(VkPipelineStageFlagBits const &enumerator) {
860    if (!ValidateEnumerator(enumerator)) {
861        return "unrecognized enumerator";
862    }
863
864    std::vector<std::string> strings;
865    if (enumerator & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) {
866        strings.push_back("VK_PIPELINE_STAGE_ALL_COMMANDS_BIT");
867    }
868    if (enumerator & VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT) {
869        strings.push_back("VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT");
870    }
871    if (enumerator & VK_PIPELINE_STAGE_HOST_BIT) {
872        strings.push_back("VK_PIPELINE_STAGE_HOST_BIT");
873    }
874    if (enumerator & VK_PIPELINE_STAGE_TRANSFER_BIT) {
875        strings.push_back("VK_PIPELINE_STAGE_TRANSFER_BIT");
876    }
877    if (enumerator & VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT) {
878        strings.push_back("VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT");
879    }
880    if (enumerator & VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT) {
881        strings.push_back("VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT");
882    }
883    if (enumerator & VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) {
884        strings.push_back("VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT");
885    }
886    if (enumerator & VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT) {
887        strings.push_back("VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT");
888    }
889    if (enumerator & VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT) {
890        strings.push_back("VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT");
891    }
892    if (enumerator & VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT) {
893        strings.push_back("VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT");
894    }
895    if (enumerator & VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT) {
896        strings.push_back("VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT");
897    }
898    if (enumerator & VK_PIPELINE_STAGE_VERTEX_SHADER_BIT) {
899        strings.push_back("VK_PIPELINE_STAGE_VERTEX_SHADER_BIT");
900    }
901    if (enumerator & VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT) {
902        strings.push_back("VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT");
903    }
904    if (enumerator & VK_PIPELINE_STAGE_VERTEX_INPUT_BIT) {
905        strings.push_back("VK_PIPELINE_STAGE_VERTEX_INPUT_BIT");
906    }
907    if (enumerator & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT) {
908        strings.push_back("VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT");
909    }
910    if (enumerator & VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT) {
911        strings.push_back("VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT");
912    }
913    if (enumerator & VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) {
914        strings.push_back("VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT");
915    }
916
917    std::string enumeratorString;
918    for (auto const &string : strings) {
919        enumeratorString += string;
920
921        if (string != strings.back()) {
922            enumeratorString += '|';
923        }
924    }
925
926    return enumeratorString;
927}
928
929static bool ValidateEnumerator(VkAccessFlagBits const &enumerator) {
930    VkAccessFlagBits allFlags = (VkAccessFlagBits)(
931        VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
932        VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
933        VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
934        VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
935        VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT);
936
937    if (enumerator & (~allFlags)) {
938        return false;
939    }
940
941    return true;
942}
943
944static std::string EnumeratorString(VkAccessFlagBits const &enumerator) {
945    if (!ValidateEnumerator(enumerator)) {
946        return "unrecognized enumerator";
947    }
948
949    std::vector<std::string> strings;
950    if (enumerator & VK_ACCESS_INDIRECT_COMMAND_READ_BIT) {
951        strings.push_back("VK_ACCESS_INDIRECT_COMMAND_READ_BIT");
952    }
953    if (enumerator & VK_ACCESS_INDEX_READ_BIT) {
954        strings.push_back("VK_ACCESS_INDEX_READ_BIT");
955    }
956    if (enumerator & VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT) {
957        strings.push_back("VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT");
958    }
959    if (enumerator & VK_ACCESS_UNIFORM_READ_BIT) {
960        strings.push_back("VK_ACCESS_UNIFORM_READ_BIT");
961    }
962    if (enumerator & VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) {
963        strings.push_back("VK_ACCESS_INPUT_ATTACHMENT_READ_BIT");
964    }
965    if (enumerator & VK_ACCESS_SHADER_READ_BIT) {
966        strings.push_back("VK_ACCESS_SHADER_READ_BIT");
967    }
968    if (enumerator & VK_ACCESS_SHADER_WRITE_BIT) {
969        strings.push_back("VK_ACCESS_SHADER_WRITE_BIT");
970    }
971    if (enumerator & VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) {
972        strings.push_back("VK_ACCESS_COLOR_ATTACHMENT_READ_BIT");
973    }
974    if (enumerator & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) {
975        strings.push_back("VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT");
976    }
977    if (enumerator & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT) {
978        strings.push_back("VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT");
979    }
980    if (enumerator & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) {
981        strings.push_back("VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT");
982    }
983    if (enumerator & VK_ACCESS_TRANSFER_READ_BIT) {
984        strings.push_back("VK_ACCESS_TRANSFER_READ_BIT");
985    }
986    if (enumerator & VK_ACCESS_TRANSFER_WRITE_BIT) {
987        strings.push_back("VK_ACCESS_TRANSFER_WRITE_BIT");
988    }
989    if (enumerator & VK_ACCESS_HOST_READ_BIT) {
990        strings.push_back("VK_ACCESS_HOST_READ_BIT");
991    }
992    if (enumerator & VK_ACCESS_HOST_WRITE_BIT) {
993        strings.push_back("VK_ACCESS_HOST_WRITE_BIT");
994    }
995    if (enumerator & VK_ACCESS_MEMORY_READ_BIT) {
996        strings.push_back("VK_ACCESS_MEMORY_READ_BIT");
997    }
998    if (enumerator & VK_ACCESS_MEMORY_WRITE_BIT) {
999        strings.push_back("VK_ACCESS_MEMORY_WRITE_BIT");
1000    }
1001
1002    std::string enumeratorString;
1003    for (auto const &string : strings) {
1004        enumeratorString += string;
1005
1006        if (string != strings.back()) {
1007            enumeratorString += '|';
1008        }
1009    }
1010
1011    return enumeratorString;
1012}
1013
1014static bool ValidateEnumerator(VkCommandPoolCreateFlagBits const &enumerator) {
1015    VkCommandPoolCreateFlagBits allFlags =
1016        (VkCommandPoolCreateFlagBits)(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT);
1017    if (enumerator & (~allFlags)) {
1018        return false;
1019    }
1020
1021    return true;
1022}
1023
1024static std::string EnumeratorString(VkCommandPoolCreateFlagBits const &enumerator) {
1025    if (!ValidateEnumerator(enumerator)) {
1026        return "unrecognized enumerator";
1027    }
1028
1029    std::vector<std::string> strings;
1030    if (enumerator & VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT) {
1031        strings.push_back("VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT");
1032    }
1033    if (enumerator & VK_COMMAND_POOL_CREATE_TRANSIENT_BIT) {
1034        strings.push_back("VK_COMMAND_POOL_CREATE_TRANSIENT_BIT");
1035    }
1036
1037    std::string enumeratorString;
1038    for (auto const &string : strings) {
1039        enumeratorString += string;
1040
1041        if (string != strings.back()) {
1042            enumeratorString += '|';
1043        }
1044    }
1045
1046    return enumeratorString;
1047}
1048
1049static bool ValidateEnumerator(VkCommandPoolResetFlagBits const &enumerator) {
1050    VkCommandPoolResetFlagBits allFlags = (VkCommandPoolResetFlagBits)(VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1051    if (enumerator & (~allFlags)) {
1052        return false;
1053    }
1054
1055    return true;
1056}
1057
1058static std::string EnumeratorString(VkCommandPoolResetFlagBits const &enumerator) {
1059    if (!ValidateEnumerator(enumerator)) {
1060        return "unrecognized enumerator";
1061    }
1062
1063    std::vector<std::string> strings;
1064    if (enumerator & VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT) {
1065        strings.push_back("VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT");
1066    }
1067
1068    std::string enumeratorString;
1069    for (auto const &string : strings) {
1070        enumeratorString += string;
1071
1072        if (string != strings.back()) {
1073            enumeratorString += '|';
1074        }
1075    }
1076
1077    return enumeratorString;
1078}
1079
1080static bool ValidateEnumerator(VkCommandBufferUsageFlags const &enumerator) {
1081    VkCommandBufferUsageFlags allFlags =
1082        (VkCommandBufferUsageFlags)(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT |
1083                                    VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT);
1084    if (enumerator & (~allFlags)) {
1085        return false;
1086    }
1087
1088    return true;
1089}
1090
1091static std::string EnumeratorString(VkCommandBufferUsageFlags const &enumerator) {
1092    if (!ValidateEnumerator(enumerator)) {
1093        return "unrecognized enumerator";
1094    }
1095
1096    std::vector<std::string> strings;
1097    if (enumerator & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
1098        strings.push_back("VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT");
1099    }
1100    if (enumerator & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) {
1101        strings.push_back("VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT");
1102    }
1103    if (enumerator & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
1104        strings.push_back("VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT");
1105    }
1106
1107    std::string enumeratorString;
1108    for (auto const &string : strings) {
1109        enumeratorString += string;
1110
1111        if (string != strings.back()) {
1112            enumeratorString += '|';
1113        }
1114    }
1115
1116    return enumeratorString;
1117}
1118
1119static bool ValidateEnumerator(VkCommandBufferResetFlagBits const &enumerator) {
1120    VkCommandBufferResetFlagBits allFlags = (VkCommandBufferResetFlagBits)(VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1121    if (enumerator & (~allFlags)) {
1122        return false;
1123    }
1124
1125    return true;
1126}
1127
1128static std::string EnumeratorString(VkCommandBufferResetFlagBits const &enumerator) {
1129    if (!ValidateEnumerator(enumerator)) {
1130        return "unrecognized enumerator";
1131    }
1132
1133    std::vector<std::string> strings;
1134    if (enumerator & VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT) {
1135        strings.push_back("VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT");
1136    }
1137
1138    std::string enumeratorString;
1139    for (auto const &string : strings) {
1140        enumeratorString += string;
1141
1142        if (string != strings.back()) {
1143            enumeratorString += '|';
1144        }
1145    }
1146
1147    return enumeratorString;
1148}
1149
1150static bool ValidateEnumerator(VkImageAspectFlagBits const &enumerator) {
1151    VkImageAspectFlagBits allFlags = (VkImageAspectFlagBits)(VK_IMAGE_ASPECT_METADATA_BIT | VK_IMAGE_ASPECT_STENCIL_BIT |
1152                                                             VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_COLOR_BIT);
1153    if (enumerator & (~allFlags)) {
1154        return false;
1155    }
1156
1157    return true;
1158}
1159
1160static std::string EnumeratorString(VkImageAspectFlagBits const &enumerator) {
1161    if (!ValidateEnumerator(enumerator)) {
1162        return "unrecognized enumerator";
1163    }
1164
1165    std::vector<std::string> strings;
1166    if (enumerator & VK_IMAGE_ASPECT_METADATA_BIT) {
1167        strings.push_back("VK_IMAGE_ASPECT_METADATA_BIT");
1168    }
1169    if (enumerator & VK_IMAGE_ASPECT_STENCIL_BIT) {
1170        strings.push_back("VK_IMAGE_ASPECT_STENCIL_BIT");
1171    }
1172    if (enumerator & VK_IMAGE_ASPECT_DEPTH_BIT) {
1173        strings.push_back("VK_IMAGE_ASPECT_DEPTH_BIT");
1174    }
1175    if (enumerator & VK_IMAGE_ASPECT_COLOR_BIT) {
1176        strings.push_back("VK_IMAGE_ASPECT_COLOR_BIT");
1177    }
1178
1179    std::string enumeratorString;
1180    for (auto const &string : strings) {
1181        enumeratorString += string;
1182
1183        if (string != strings.back()) {
1184            enumeratorString += '|';
1185        }
1186    }
1187
1188    return enumeratorString;
1189}
1190
1191static bool ValidateEnumerator(VkQueryControlFlagBits const &enumerator) {
1192    VkQueryControlFlagBits allFlags = (VkQueryControlFlagBits)(VK_QUERY_CONTROL_PRECISE_BIT);
1193    if (enumerator & (~allFlags)) {
1194        return false;
1195    }
1196
1197    return true;
1198}
1199
1200static std::string EnumeratorString(VkQueryControlFlagBits const &enumerator) {
1201    if (!ValidateEnumerator(enumerator)) {
1202        return "unrecognized enumerator";
1203    }
1204
1205    std::vector<std::string> strings;
1206    if (enumerator & VK_QUERY_CONTROL_PRECISE_BIT) {
1207        strings.push_back("VK_QUERY_CONTROL_PRECISE_BIT");
1208    }
1209
1210    std::string enumeratorString;
1211    for (auto const &string : strings) {
1212        enumeratorString += string;
1213
1214        if (string != strings.back()) {
1215            enumeratorString += '|';
1216        }
1217    }
1218
1219    return enumeratorString;
1220}
1221
1222static const int MaxParamCheckerStringLength = 256;
1223
1224static bool validate_string(debug_report_data *report_data, const char *apiName, const char *stringName,
1225                            const char *validateString) {
1226    assert(apiName != nullptr);
1227    assert(stringName != nullptr);
1228    assert(validateString != nullptr);
1229
1230    bool skipCall = false;
1231
1232    VkStringErrorFlags result = vk_string_validate(MaxParamCheckerStringLength, validateString);
1233
1234    if (result == VK_STRING_ERROR_NONE) {
1235        return skipCall;
1236    } else if (result & VK_STRING_ERROR_LENGTH) {
1237        skipCall =
1238            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, INVALID_USAGE,
1239                    LayerName, "%s: string %s exceeds max length %d", apiName, stringName, MaxParamCheckerStringLength);
1240    } else if (result & VK_STRING_ERROR_BAD_DATA) {
1241        skipCall =
1242            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, INVALID_USAGE,
1243                    LayerName, "%s: string %s contains invalid characters or is badly formed", apiName, stringName);
1244    }
1245    return skipCall;
1246}
1247
1248static bool validate_queue_family_index(layer_data *device_data, const char *function_name, const char *parameter_name,
1249                                        uint32_t index) {
1250    assert(device_data != nullptr);
1251    debug_report_data *report_data = device_data->report_data;
1252    bool skip_call = false;
1253
1254    if (index == VK_QUEUE_FAMILY_IGNORED) {
1255        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
1256                             "%s: %s cannot be VK_QUEUE_FAMILY_IGNORED.", function_name, parameter_name);
1257    } else {
1258        const auto &queue_data = device_data->queueFamilyIndexMap.find(index);
1259        if (queue_data == device_data->queueFamilyIndexMap.end()) {
1260            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
1261                                 LayerName, "%s: %s (%d) must be one of the indices specified when the device was created, via "
1262                                            "the VkDeviceQueueCreateInfo structure.",
1263                                 function_name, parameter_name, index);
1264            return false;
1265        }
1266    }
1267
1268    return skip_call;
1269}
1270
1271static bool validate_queue_family_indices(layer_data *device_data, const char *function_name, const char *parameter_name,
1272                                          const uint32_t count, const uint32_t *indices) {
1273    assert(device_data != nullptr);
1274    debug_report_data *report_data = device_data->report_data;
1275    bool skip_call = false;
1276
1277    if (indices != nullptr) {
1278        for (uint32_t i = 0; i < count; i++) {
1279            if (indices[i] == VK_QUEUE_FAMILY_IGNORED) {
1280                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
1281                                     LayerName, "%s: %s[%d] cannot be VK_QUEUE_FAMILY_IGNORED.", function_name, parameter_name, i);
1282            } else {
1283                const auto &queue_data = device_data->queueFamilyIndexMap.find(indices[i]);
1284                if (queue_data == device_data->queueFamilyIndexMap.end()) {
1285                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
1286                                         LayerName, "%s: %s[%d] (%d) must be one of the indices specified when the device was "
1287                                                    "created, via the VkDeviceQueueCreateInfo structure.",
1288                                         function_name, parameter_name, i, indices[i]);
1289                    return false;
1290                }
1291            }
1292        }
1293    }
1294
1295    return skip_call;
1296}
1297
1298VKAPI_ATTR VkResult VKAPI_CALL
1299CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
1300    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1301
1302    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
1303    assert(chain_info != nullptr);
1304    assert(chain_info->u.pLayerInfo != nullptr);
1305
1306    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
1307    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
1308    if (fpCreateInstance == NULL) {
1309        return VK_ERROR_INITIALIZATION_FAILED;
1310    }
1311
1312    // Advance the link info for the next element on the chain
1313    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
1314
1315    result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
1316
1317    if (result == VK_SUCCESS) {
1318        layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
1319        assert(my_instance_data != nullptr);
1320
1321        VkLayerInstanceDispatchTable *pTable = initInstanceTable(*pInstance, fpGetInstanceProcAddr, pc_instance_table_map);
1322
1323        my_instance_data->instance = *pInstance;
1324        my_instance_data->report_data = debug_report_create_instance(pTable, *pInstance, pCreateInfo->enabledExtensionCount,
1325                                                                     pCreateInfo->ppEnabledExtensionNames);
1326
1327        // Look for one or more debug report create info structures
1328        // and setup a callback(s) for each one found.
1329        if (!layer_copy_tmp_callbacks(pCreateInfo->pNext, &my_instance_data->num_tmp_callbacks,
1330                                      &my_instance_data->tmp_dbg_create_infos, &my_instance_data->tmp_callbacks)) {
1331            if (my_instance_data->num_tmp_callbacks > 0) {
1332                // Setup the temporary callback(s) here to catch early issues:
1333                if (layer_enable_tmp_callbacks(my_instance_data->report_data, my_instance_data->num_tmp_callbacks,
1334                                               my_instance_data->tmp_dbg_create_infos, my_instance_data->tmp_callbacks)) {
1335                    // Failure of setting up one or more of the callback.
1336                    // Therefore, clean up and don't use those callbacks:
1337                    layer_free_tmp_callbacks(my_instance_data->tmp_dbg_create_infos, my_instance_data->tmp_callbacks);
1338                    my_instance_data->num_tmp_callbacks = 0;
1339                }
1340            }
1341        }
1342
1343        init_parameter_validation(my_instance_data, pAllocator);
1344
1345        // Ordinarily we'd check these before calling down the chain, but none of the layer
1346        // support is in place until now, if we survive we can report the issue now.
1347        parameter_validation_vkCreateInstance(my_instance_data->report_data, pCreateInfo, pAllocator, pInstance);
1348
1349        if (pCreateInfo->pApplicationInfo) {
1350            if (pCreateInfo->pApplicationInfo->pApplicationName) {
1351                validate_string(my_instance_data->report_data, "vkCreateInstance",
1352                                "pCreateInfo->VkApplicationInfo->pApplicationName",
1353                                pCreateInfo->pApplicationInfo->pApplicationName);
1354            }
1355
1356            if (pCreateInfo->pApplicationInfo->pEngineName) {
1357                validate_string(my_instance_data->report_data, "vkCreateInstance", "pCreateInfo->VkApplicationInfo->pEngineName",
1358                                pCreateInfo->pApplicationInfo->pEngineName);
1359            }
1360        }
1361
1362        // Disable the tmp callbacks:
1363        if (my_instance_data->num_tmp_callbacks > 0) {
1364            layer_disable_tmp_callbacks(my_instance_data->report_data, my_instance_data->num_tmp_callbacks,
1365                                        my_instance_data->tmp_callbacks);
1366        }
1367    }
1368
1369    return result;
1370}
1371
1372VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
1373    // Grab the key before the instance is destroyed.
1374    dispatch_key key = get_dispatch_key(instance);
1375    bool skipCall = false;
1376    layer_data *my_data = get_my_data_ptr(key, layer_data_map);
1377    assert(my_data != NULL);
1378
1379    // Enable the temporary callback(s) here to catch vkDestroyInstance issues:
1380    bool callback_setup = false;
1381    if (my_data->num_tmp_callbacks > 0) {
1382        if (!layer_enable_tmp_callbacks(my_data->report_data, my_data->num_tmp_callbacks, my_data->tmp_dbg_create_infos,
1383                                        my_data->tmp_callbacks)) {
1384            callback_setup = true;
1385        }
1386    }
1387
1388    skipCall |= parameter_validation_vkDestroyInstance(my_data->report_data, pAllocator);
1389
1390    // Disable and cleanup the temporary callback(s):
1391    if (callback_setup) {
1392        layer_disable_tmp_callbacks(my_data->report_data, my_data->num_tmp_callbacks, my_data->tmp_callbacks);
1393    }
1394    if (my_data->num_tmp_callbacks > 0) {
1395        layer_free_tmp_callbacks(my_data->tmp_dbg_create_infos, my_data->tmp_callbacks);
1396        my_data->num_tmp_callbacks = 0;
1397    }
1398
1399    if (!skipCall) {
1400        VkLayerInstanceDispatchTable *pTable = get_dispatch_table(pc_instance_table_map, instance);
1401        pTable->DestroyInstance(instance, pAllocator);
1402
1403        // Clean up logging callback, if any
1404        while (my_data->logging_callback.size() > 0) {
1405            VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
1406            layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
1407            my_data->logging_callback.pop_back();
1408        }
1409
1410        layer_debug_report_destroy_instance(mid(instance));
1411        layer_data_map.erase(pTable);
1412
1413        pc_instance_table_map.erase(key);
1414        layer_data_map.erase(key);
1415    }
1416}
1417
1418VKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
1419                                                        VkPhysicalDevice *pPhysicalDevices) {
1420    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1421    bool skipCall = false;
1422    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1423    assert(my_data != NULL);
1424
1425    skipCall |= parameter_validation_vkEnumeratePhysicalDevices(my_data->report_data, pPhysicalDeviceCount, pPhysicalDevices);
1426
1427    if (!skipCall) {
1428        result = get_dispatch_table(pc_instance_table_map, instance)
1429                     ->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
1430
1431        validate_result(my_data->report_data, "vkEnumeratePhysicalDevices", result);
1432        if ((result == VK_SUCCESS) && (NULL != pPhysicalDevices)) {
1433            for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
1434                layer_data *phy_dev_data = get_my_data_ptr(get_dispatch_key(pPhysicalDevices[i]), layer_data_map);
1435                // Save the supported features for each physical device
1436                VkLayerInstanceDispatchTable *disp_table = get_dispatch_table(pc_instance_table_map, pPhysicalDevices[i]);
1437                disp_table->GetPhysicalDeviceFeatures(pPhysicalDevices[i], &(phy_dev_data->physical_device_features));
1438            }
1439        }
1440    }
1441    return result;
1442}
1443
1444VKAPI_ATTR void VKAPI_CALL
1445GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures) {
1446    bool skipCall = false;
1447    layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
1448    assert(my_data != NULL);
1449
1450    skipCall |= parameter_validation_vkGetPhysicalDeviceFeatures(my_data->report_data, pFeatures);
1451
1452    if (!skipCall) {
1453        get_dispatch_table(pc_instance_table_map, physicalDevice)->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
1454    }
1455}
1456
1457VKAPI_ATTR void VKAPI_CALL
1458GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties) {
1459    bool skipCall = false;
1460    layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
1461    assert(my_data != NULL);
1462
1463    skipCall |= parameter_validation_vkGetPhysicalDeviceFormatProperties(my_data->report_data, format, pFormatProperties);
1464
1465    if (!skipCall) {
1466        get_dispatch_table(pc_instance_table_map, physicalDevice)
1467            ->GetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatProperties);
1468    }
1469}
1470
1471VKAPI_ATTR VkResult VKAPI_CALL
1472GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling,
1473                                       VkImageUsageFlags usage, VkImageCreateFlags flags,
1474                                       VkImageFormatProperties *pImageFormatProperties) {
1475    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1476    bool skipCall = false;
1477    layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
1478    assert(my_data != NULL);
1479
1480    skipCall |= parameter_validation_vkGetPhysicalDeviceImageFormatProperties(my_data->report_data, format, type, tiling, usage, flags,
1481                                                                     pImageFormatProperties);
1482
1483    if (!skipCall) {
1484        result = get_dispatch_table(pc_instance_table_map, physicalDevice)
1485                     ->GetPhysicalDeviceImageFormatProperties(physicalDevice, format, type, tiling, usage, flags,
1486                                                              pImageFormatProperties);
1487
1488        validate_result(my_data->report_data, "vkGetPhysicalDeviceImageFormatProperties", result);
1489    }
1490
1491    return result;
1492}
1493
1494VKAPI_ATTR void VKAPI_CALL
1495GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) {
1496    bool skipCall = false;
1497    layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
1498    assert(my_data != NULL);
1499
1500    skipCall |= parameter_validation_vkGetPhysicalDeviceProperties(my_data->report_data, pProperties);
1501
1502    if (!skipCall) {
1503        get_dispatch_table(pc_instance_table_map, physicalDevice)->GetPhysicalDeviceProperties(physicalDevice, pProperties);
1504    }
1505}
1506
1507VKAPI_ATTR void VKAPI_CALL
1508GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
1509                                       VkQueueFamilyProperties *pQueueFamilyProperties) {
1510    bool skipCall = false;
1511    layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
1512    assert(my_data != NULL);
1513
1514    skipCall |= parameter_validation_vkGetPhysicalDeviceQueueFamilyProperties(my_data->report_data, pQueueFamilyPropertyCount,
1515                                                                     pQueueFamilyProperties);
1516
1517    if (!skipCall) {
1518        get_dispatch_table(pc_instance_table_map, physicalDevice)
1519            ->GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
1520    }
1521}
1522
1523VKAPI_ATTR void VKAPI_CALL
1524GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties) {
1525    bool skipCall = false;
1526    layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
1527    assert(my_data != NULL);
1528
1529    skipCall |= parameter_validation_vkGetPhysicalDeviceMemoryProperties(my_data->report_data, pMemoryProperties);
1530
1531    if (!skipCall) {
1532        get_dispatch_table(pc_instance_table_map, physicalDevice)
1533            ->GetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties);
1534    }
1535}
1536
1537void validateDeviceCreateInfo(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
1538                              const std::vector<VkQueueFamilyProperties> properties) {
1539    std::unordered_set<uint32_t> set;
1540
1541    if ((pCreateInfo != nullptr) && (pCreateInfo->pQueueCreateInfos != nullptr)) {
1542        for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; ++i) {
1543            if (set.count(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex)) {
1544                log_msg(mdd(physicalDevice), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1545                        INVALID_USAGE, LayerName,
1546                        "VkDeviceCreateInfo parameter, uint32_t pQueueCreateInfos[%d]->queueFamilyIndex, is not unique within this "
1547                        "structure.",
1548                        i);
1549            } else {
1550                set.insert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex);
1551            }
1552
1553            if (pCreateInfo->pQueueCreateInfos[i].pQueuePriorities != nullptr) {
1554                for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; ++j) {
1555                    if ((pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[j] < 0.f) ||
1556                        (pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[j] > 1.f)) {
1557                        log_msg(mdd(physicalDevice), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1558                                __LINE__, INVALID_USAGE, LayerName,
1559                                "VkDeviceCreateInfo parameter, uint32_t pQueueCreateInfos[%d]->pQueuePriorities[%d], must be "
1560                                "between 0 and 1. Actual value is %f",
1561                                i, j, pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[j]);
1562                    }
1563                }
1564            }
1565
1566            if (pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex >= properties.size()) {
1567                log_msg(
1568                    mdd(physicalDevice), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1569                    INVALID_USAGE, LayerName,
1570                    "VkDeviceCreateInfo parameter, uint32_t pQueueCreateInfos[%d]->queueFamilyIndex cannot be more than the number "
1571                    "of queue families.",
1572                    i);
1573            } else if (pCreateInfo->pQueueCreateInfos[i].queueCount >
1574                       properties[pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex].queueCount) {
1575                log_msg(
1576                    mdd(physicalDevice), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1577                    INVALID_USAGE, LayerName,
1578                    "VkDeviceCreateInfo parameter, uint32_t pQueueCreateInfos[%d]->queueCount cannot be more than the number of "
1579                    "queues for the given family index.",
1580                    i);
1581            }
1582        }
1583    }
1584}
1585
1586void storeCreateDeviceData(VkDevice device, const VkDeviceCreateInfo *pCreateInfo) {
1587    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1588
1589    if ((pCreateInfo != nullptr) && (pCreateInfo->pQueueCreateInfos != nullptr)) {
1590        for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; ++i) {
1591            my_device_data->queueFamilyIndexMap.insert(
1592                std::make_pair(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, pCreateInfo->pQueueCreateInfos[i].queueCount));
1593        }
1594    }
1595}
1596
1597VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice physicalDevice,
1598                                            const VkDeviceCreateInfo *pCreateInfo,
1599                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
1600    /*
1601     * NOTE: We do not validate physicalDevice or any dispatchable
1602     * object as the first parameter. We couldn't get here if it was wrong!
1603     */
1604
1605    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1606    bool skipCall = false;
1607    layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
1608    assert(my_instance_data != nullptr);
1609
1610    skipCall |= parameter_validation_vkCreateDevice(my_instance_data->report_data, pCreateInfo, pAllocator, pDevice);
1611
1612    if (pCreateInfo != NULL) {
1613        if ((pCreateInfo->enabledLayerCount > 0) && (pCreateInfo->ppEnabledLayerNames != NULL)) {
1614            for (size_t i = 0; i < pCreateInfo->enabledLayerCount; i++) {
1615                skipCall |= validate_string(my_instance_data->report_data, "vkCreateDevice", "pCreateInfo->ppEnabledLayerNames",
1616                                            pCreateInfo->ppEnabledLayerNames[i]);
1617            }
1618        }
1619
1620        if ((pCreateInfo->enabledExtensionCount > 0) && (pCreateInfo->ppEnabledExtensionNames != NULL)) {
1621            for (size_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
1622                skipCall |= validate_string(my_instance_data->report_data, "vkCreateDevice", "pCreateInfo->ppEnabledExtensionNames",
1623                                            pCreateInfo->ppEnabledExtensionNames[i]);
1624            }
1625        }
1626    }
1627
1628    if (!skipCall) {
1629        VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
1630        assert(chain_info != nullptr);
1631        assert(chain_info->u.pLayerInfo != nullptr);
1632
1633        PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
1634        PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
1635        PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
1636        if (fpCreateDevice == NULL) {
1637            return VK_ERROR_INITIALIZATION_FAILED;
1638        }
1639
1640        // Advance the link info for the next element on the chain
1641        chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
1642
1643        result = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
1644
1645        validate_result(my_instance_data->report_data, "vkCreateDevice", result);
1646
1647        if (result == VK_SUCCESS) {
1648            layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
1649            assert(my_device_data != nullptr);
1650
1651            my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
1652            initDeviceTable(*pDevice, fpGetDeviceProcAddr, pc_device_table_map);
1653
1654
1655            uint32_t count;
1656            VkLayerInstanceDispatchTable *instance_dispatch_table = get_dispatch_table(pc_instance_table_map, physicalDevice);
1657            instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count, nullptr);
1658            std::vector<VkQueueFamilyProperties> properties(count);
1659            instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count, &properties[0]);
1660
1661            validateDeviceCreateInfo(physicalDevice, pCreateInfo, properties);
1662            storeCreateDeviceData(*pDevice, pCreateInfo);
1663
1664            // Query and save physical device limits for this device
1665            VkPhysicalDeviceProperties device_properties = {};
1666            instance_dispatch_table->GetPhysicalDeviceProperties(physicalDevice, &device_properties);
1667            memcpy(&my_device_data->device_limits, &device_properties.limits, sizeof(VkPhysicalDeviceLimits));
1668            my_device_data->physical_device = physicalDevice;
1669        }
1670    }
1671
1672    return result;
1673}
1674
1675VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
1676    dispatch_key key = get_dispatch_key(device);
1677    bool skipCall = false;
1678    layer_data *my_data = get_my_data_ptr(key, layer_data_map);
1679    assert(my_data != NULL);
1680
1681    skipCall |= parameter_validation_vkDestroyDevice(my_data->report_data, pAllocator);
1682
1683    if (!skipCall) {
1684        layer_debug_report_destroy_device(device);
1685
1686#if DISPATCH_MAP_DEBUG
1687        fprintf(stderr, "Device:  0x%p, key:  0x%p\n", device, key);
1688#endif
1689
1690        get_dispatch_table(pc_device_table_map, device)->DestroyDevice(device, pAllocator);
1691        pc_device_table_map.erase(key);
1692        layer_data_map.erase(key);
1693    }
1694}
1695
1696bool PreGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex) {
1697    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1698    assert(my_device_data != nullptr);
1699
1700    validate_queue_family_index(my_device_data, "vkGetDeviceQueue", "queueFamilyIndex", queueFamilyIndex);
1701
1702    const auto &queue_data = my_device_data->queueFamilyIndexMap.find(queueFamilyIndex);
1703    if (queue_data->second <= queueIndex) {
1704        log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, INVALID_USAGE,
1705            LayerName,
1706                "VkGetDeviceQueue parameter, uint32_t queueIndex %d, must be less than the number of queues given when the device "
1707                "was created.",
1708                queueIndex);
1709        return false;
1710    }
1711    return true;
1712}
1713
1714VKAPI_ATTR void VKAPI_CALL
1715GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
1716    bool skipCall = false;
1717    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1718    assert(my_data != NULL);
1719
1720    skipCall |= parameter_validation_vkGetDeviceQueue(my_data->report_data, queueFamilyIndex, queueIndex, pQueue);
1721
1722    if (!skipCall) {
1723        PreGetDeviceQueue(device, queueFamilyIndex, queueIndex);
1724
1725        get_dispatch_table(pc_device_table_map, device)->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
1726    }
1727}
1728
1729VKAPI_ATTR VkResult VKAPI_CALL
1730QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
1731    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1732    bool skipCall = false;
1733    layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
1734    assert(my_data != NULL);
1735
1736    skipCall |= parameter_validation_vkQueueSubmit(my_data->report_data, submitCount, pSubmits, fence);
1737
1738    if (!skipCall) {
1739        result = get_dispatch_table(pc_device_table_map, queue)->QueueSubmit(queue, submitCount, pSubmits, fence);
1740
1741        validate_result(my_data->report_data, "vkQueueSubmit", result);
1742    }
1743
1744    return result;
1745}
1746
1747VKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
1748    layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
1749    assert(my_data != NULL);
1750
1751    VkResult result = get_dispatch_table(pc_device_table_map, queue)->QueueWaitIdle(queue);
1752
1753    validate_result(my_data->report_data, "vkQueueWaitIdle", result);
1754
1755    return result;
1756}
1757
1758VKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
1759    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1760    assert(my_data != NULL);
1761
1762    VkResult result = get_dispatch_table(pc_device_table_map, device)->DeviceWaitIdle(device);
1763
1764    validate_result(my_data->report_data, "vkDeviceWaitIdle", result);
1765
1766    return result;
1767}
1768
1769VKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
1770                                                                const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
1771    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1772    bool skipCall = false;
1773    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1774    assert(my_data != NULL);
1775
1776    skipCall |= parameter_validation_vkAllocateMemory(my_data->report_data, pAllocateInfo, pAllocator, pMemory);
1777
1778    if (!skipCall) {
1779        result = get_dispatch_table(pc_device_table_map, device)->AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
1780
1781        validate_result(my_data->report_data, "vkAllocateMemory", result);
1782    }
1783
1784    return result;
1785}
1786
1787VKAPI_ATTR void VKAPI_CALL
1788FreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator) {
1789    bool skipCall = false;
1790    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1791    assert(my_data != NULL);
1792
1793    skipCall |= parameter_validation_vkFreeMemory(my_data->report_data, memory, pAllocator);
1794
1795    if (!skipCall) {
1796        get_dispatch_table(pc_device_table_map, device)->FreeMemory(device, memory, pAllocator);
1797    }
1798}
1799
1800VKAPI_ATTR VkResult VKAPI_CALL
1801MapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData) {
1802    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1803    bool skipCall = false;
1804    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1805    assert(my_data != NULL);
1806
1807    skipCall |= parameter_validation_vkMapMemory(my_data->report_data, memory, offset, size, flags, ppData);
1808
1809    if (!skipCall) {
1810        result = get_dispatch_table(pc_device_table_map, device)->MapMemory(device, memory, offset, size, flags, ppData);
1811
1812        validate_result(my_data->report_data, "vkMapMemory", result);
1813    }
1814
1815    return result;
1816}
1817
1818VKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory memory) {
1819    bool skipCall = false;
1820    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1821    assert(my_data != NULL);
1822
1823    skipCall |= parameter_validation_vkUnmapMemory(my_data->report_data, memory);
1824
1825    if (!skipCall) {
1826        get_dispatch_table(pc_device_table_map, device)->UnmapMemory(device, memory);
1827    }
1828}
1829
1830VKAPI_ATTR VkResult VKAPI_CALL
1831FlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges) {
1832    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1833    bool skipCall = false;
1834    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1835    assert(my_data != NULL);
1836
1837    skipCall |= parameter_validation_vkFlushMappedMemoryRanges(my_data->report_data, memoryRangeCount, pMemoryRanges);
1838
1839    if (!skipCall) {
1840        result = get_dispatch_table(pc_device_table_map, device)->FlushMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges);
1841
1842        validate_result(my_data->report_data, "vkFlushMappedMemoryRanges", result);
1843    }
1844
1845    return result;
1846}
1847
1848VKAPI_ATTR VkResult VKAPI_CALL
1849InvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges) {
1850    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1851    bool skipCall = false;
1852    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1853    assert(my_data != NULL);
1854
1855    skipCall |= parameter_validation_vkInvalidateMappedMemoryRanges(my_data->report_data, memoryRangeCount, pMemoryRanges);
1856
1857    if (!skipCall) {
1858        result =
1859            get_dispatch_table(pc_device_table_map, device)->InvalidateMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges);
1860
1861        validate_result(my_data->report_data, "vkInvalidateMappedMemoryRanges", result);
1862    }
1863
1864    return result;
1865}
1866
1867VKAPI_ATTR void VKAPI_CALL
1868GetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize *pCommittedMemoryInBytes) {
1869    bool skipCall = false;
1870    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1871    assert(my_data != NULL);
1872
1873    skipCall |= parameter_validation_vkGetDeviceMemoryCommitment(my_data->report_data, memory, pCommittedMemoryInBytes);
1874
1875    if (!skipCall) {
1876        get_dispatch_table(pc_device_table_map, device)->GetDeviceMemoryCommitment(device, memory, pCommittedMemoryInBytes);
1877    }
1878}
1879
1880VKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory,
1881                                                VkDeviceSize memoryOffset) {
1882    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1883    bool skipCall = false;
1884    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1885    assert(my_data != NULL);
1886
1887    skipCall |= parameter_validation_vkBindBufferMemory(my_data->report_data, buffer, memory, memoryOffset);
1888
1889    if (!skipCall) {
1890        result = get_dispatch_table(pc_device_table_map, device)->BindBufferMemory(device, buffer, memory, memoryOffset);
1891
1892        validate_result(my_data->report_data, "vkBindBufferMemory", result);
1893    }
1894
1895    return result;
1896}
1897
1898VKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory,
1899                                               VkDeviceSize memoryOffset) {
1900    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1901    bool skipCall = false;
1902    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1903    assert(my_data != NULL);
1904
1905    skipCall |= parameter_validation_vkBindImageMemory(my_data->report_data, image, memory, memoryOffset);
1906
1907    if (!skipCall) {
1908        result = get_dispatch_table(pc_device_table_map, device)->BindImageMemory(device, image, memory, memoryOffset);
1909
1910        validate_result(my_data->report_data, "vkBindImageMemory", result);
1911    }
1912
1913    return result;
1914}
1915
1916VKAPI_ATTR void VKAPI_CALL
1917GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) {
1918    bool skipCall = false;
1919    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1920    assert(my_data != NULL);
1921
1922    skipCall |= parameter_validation_vkGetBufferMemoryRequirements(my_data->report_data, buffer, pMemoryRequirements);
1923
1924    if (!skipCall) {
1925        get_dispatch_table(pc_device_table_map, device)->GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
1926    }
1927}
1928
1929VKAPI_ATTR void VKAPI_CALL
1930GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
1931    bool skipCall = false;
1932    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1933    assert(my_data != NULL);
1934
1935    skipCall |= parameter_validation_vkGetImageMemoryRequirements(my_data->report_data, image, pMemoryRequirements);
1936
1937    if (!skipCall) {
1938        get_dispatch_table(pc_device_table_map, device)->GetImageMemoryRequirements(device, image, pMemoryRequirements);
1939    }
1940}
1941
1942bool PostGetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t *pNumRequirements,
1943                                          VkSparseImageMemoryRequirements *pSparseMemoryRequirements) {
1944    if (pSparseMemoryRequirements != nullptr) {
1945        if ((pSparseMemoryRequirements->formatProperties.aspectMask &
1946             (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT |
1947              VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
1948            log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1949                    UNRECOGNIZED_VALUE, LayerName,
1950                    "vkGetImageSparseMemoryRequirements parameter, VkImageAspect "
1951                    "pSparseMemoryRequirements->formatProperties.aspectMask, is an unrecognized enumerator");
1952            return false;
1953        }
1954    }
1955
1956    return true;
1957}
1958
1959VKAPI_ATTR void VKAPI_CALL
1960GetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t *pSparseMemoryRequirementCount,
1961                                 VkSparseImageMemoryRequirements *pSparseMemoryRequirements) {
1962    bool skipCall = false;
1963    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1964    assert(my_data != NULL);
1965
1966    skipCall |= parameter_validation_vkGetImageSparseMemoryRequirements(my_data->report_data, image, pSparseMemoryRequirementCount,
1967                                                               pSparseMemoryRequirements);
1968
1969    if (!skipCall) {
1970        get_dispatch_table(pc_device_table_map, device)
1971            ->GetImageSparseMemoryRequirements(device, image, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
1972
1973        PostGetImageSparseMemoryRequirements(device, image, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
1974    }
1975}
1976
1977bool PostGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
1978                                                      VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling,
1979                                                      uint32_t *pNumProperties, VkSparseImageFormatProperties *pProperties) {
1980    if (pProperties != nullptr) {
1981        if ((pProperties->aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT |
1982                                        VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
1983            log_msg(mdd(physicalDevice), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, 1,
1984                    LayerName,
1985                    "vkGetPhysicalDeviceSparseImageFormatProperties parameter, VkImageAspect pProperties->aspectMask, is an "
1986                    "unrecognized enumerator");
1987            return false;
1988        }
1989    }
1990
1991    return true;
1992}
1993
1994VKAPI_ATTR void VKAPI_CALL
1995GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
1996                                             VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling,
1997                                             uint32_t *pPropertyCount, VkSparseImageFormatProperties *pProperties) {
1998    bool skipCall = false;
1999    layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
2000    assert(my_data != NULL);
2001
2002    skipCall |= parameter_validation_vkGetPhysicalDeviceSparseImageFormatProperties(my_data->report_data, format, type, samples, usage,
2003                                                                           tiling, pPropertyCount, pProperties);
2004
2005    if (!skipCall) {
2006        get_dispatch_table(pc_instance_table_map, physicalDevice)
2007            ->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pPropertyCount,
2008                                                           pProperties);
2009
2010        PostGetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pPropertyCount,
2011                                                         pProperties);
2012    }
2013}
2014
2015VKAPI_ATTR VkResult VKAPI_CALL
2016QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) {
2017    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2018    bool skipCall = false;
2019    layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
2020    assert(my_data != NULL);
2021
2022    skipCall |= parameter_validation_vkQueueBindSparse(my_data->report_data, bindInfoCount, pBindInfo, fence);
2023
2024    if (!skipCall) {
2025        result = get_dispatch_table(pc_device_table_map, queue)->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
2026
2027        validate_result(my_data->report_data, "vkQueueBindSparse", result);
2028    }
2029
2030    return result;
2031}
2032
2033VKAPI_ATTR VkResult VKAPI_CALL
2034CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
2035    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2036    bool skipCall = false;
2037    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2038    assert(my_data != NULL);
2039
2040    skipCall |= parameter_validation_vkCreateFence(my_data->report_data, pCreateInfo, pAllocator, pFence);
2041
2042    if (!skipCall) {
2043        result = get_dispatch_table(pc_device_table_map, device)->CreateFence(device, pCreateInfo, pAllocator, pFence);
2044
2045        validate_result(my_data->report_data, "vkCreateFence", result);
2046    }
2047
2048    return result;
2049}
2050
2051VKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
2052    bool skipCall = false;
2053    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2054    assert(my_data != NULL);
2055
2056    skipCall |= parameter_validation_vkDestroyFence(my_data->report_data, fence, pAllocator);
2057
2058    if (!skipCall) {
2059        get_dispatch_table(pc_device_table_map, device)->DestroyFence(device, fence, pAllocator);
2060    }
2061}
2062
2063VKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
2064    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2065    bool skipCall = false;
2066    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2067    assert(my_data != NULL);
2068
2069    skipCall |= parameter_validation_vkResetFences(my_data->report_data, fenceCount, pFences);
2070
2071    if (!skipCall) {
2072        result = get_dispatch_table(pc_device_table_map, device)->ResetFences(device, fenceCount, pFences);
2073
2074        validate_result(my_data->report_data, "vkResetFences", result);
2075    }
2076
2077    return result;
2078}
2079
2080VKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
2081    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2082    bool skipCall = false;
2083    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2084    assert(my_data != NULL);
2085
2086    skipCall |= parameter_validation_vkGetFenceStatus(my_data->report_data, fence);
2087
2088    if (!skipCall) {
2089        result = get_dispatch_table(pc_device_table_map, device)->GetFenceStatus(device, fence);
2090
2091        validate_result(my_data->report_data, "vkGetFenceStatus", result);
2092    }
2093
2094    return result;
2095}
2096
2097VKAPI_ATTR VkResult VKAPI_CALL
2098WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) {
2099    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2100    bool skipCall = false;
2101    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2102    assert(my_data != NULL);
2103
2104    skipCall |= parameter_validation_vkWaitForFences(my_data->report_data, fenceCount, pFences, waitAll, timeout);
2105
2106    if (!skipCall) {
2107        result = get_dispatch_table(pc_device_table_map, device)->WaitForFences(device, fenceCount, pFences, waitAll, timeout);
2108
2109        validate_result(my_data->report_data, "vkWaitForFences", result);
2110    }
2111
2112    return result;
2113}
2114
2115VKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
2116                                                                 const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
2117    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2118    bool skipCall = false;
2119    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2120    assert(my_data != NULL);
2121
2122    skipCall |= parameter_validation_vkCreateSemaphore(my_data->report_data, pCreateInfo, pAllocator, pSemaphore);
2123
2124    if (!skipCall) {
2125        result = get_dispatch_table(pc_device_table_map, device)->CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
2126
2127        validate_result(my_data->report_data, "vkCreateSemaphore", result);
2128    }
2129
2130    return result;
2131}
2132
2133VKAPI_ATTR void VKAPI_CALL
2134DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
2135    bool skipCall = false;
2136    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2137    assert(my_data != NULL);
2138
2139    skipCall |= parameter_validation_vkDestroySemaphore(my_data->report_data, semaphore, pAllocator);
2140
2141    if (!skipCall) {
2142        get_dispatch_table(pc_device_table_map, device)->DestroySemaphore(device, semaphore, pAllocator);
2143    }
2144}
2145
2146VKAPI_ATTR VkResult VKAPI_CALL
2147CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
2148    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2149    bool skipCall = false;
2150    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2151    assert(my_data != NULL);
2152
2153    skipCall |= parameter_validation_vkCreateEvent(my_data->report_data, pCreateInfo, pAllocator, pEvent);
2154
2155    if (!skipCall) {
2156        result = get_dispatch_table(pc_device_table_map, device)->CreateEvent(device, pCreateInfo, pAllocator, pEvent);
2157
2158        validate_result(my_data->report_data, "vkCreateEvent", result);
2159    }
2160
2161    return result;
2162}
2163
2164VKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
2165    bool skipCall = false;
2166    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2167    assert(my_data != NULL);
2168
2169    skipCall |= parameter_validation_vkDestroyEvent(my_data->report_data, event, pAllocator);
2170
2171    if (!skipCall) {
2172        get_dispatch_table(pc_device_table_map, device)->DestroyEvent(device, event, pAllocator);
2173    }
2174}
2175
2176VKAPI_ATTR VkResult VKAPI_CALL GetEventStatus(VkDevice device, VkEvent event) {
2177    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2178    bool skipCall = false;
2179    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2180    assert(my_data != NULL);
2181
2182    skipCall |= parameter_validation_vkGetEventStatus(my_data->report_data, event);
2183
2184    if (!skipCall) {
2185        result = get_dispatch_table(pc_device_table_map, device)->GetEventStatus(device, event);
2186
2187        validate_result(my_data->report_data, "vkGetEventStatus", result);
2188    }
2189
2190    return result;
2191}
2192
2193VKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
2194    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2195    bool skipCall = false;
2196    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2197    assert(my_data != NULL);
2198
2199    skipCall |= parameter_validation_vkSetEvent(my_data->report_data, event);
2200
2201    if (!skipCall) {
2202        result = get_dispatch_table(pc_device_table_map, device)->SetEvent(device, event);
2203
2204        validate_result(my_data->report_data, "vkSetEvent", result);
2205    }
2206
2207    return result;
2208}
2209
2210VKAPI_ATTR VkResult VKAPI_CALL ResetEvent(VkDevice device, VkEvent event) {
2211    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2212    bool skipCall = false;
2213    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2214    assert(my_data != NULL);
2215
2216    skipCall |= parameter_validation_vkResetEvent(my_data->report_data, event);
2217
2218    if (!skipCall) {
2219        result = get_dispatch_table(pc_device_table_map, device)->ResetEvent(device, event);
2220
2221        validate_result(my_data->report_data, "vkResetEvent", result);
2222    }
2223
2224    return result;
2225}
2226
2227VKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
2228                                                const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
2229    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2230    bool skip_call = false;
2231    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2232    assert(device_data != nullptr);
2233    debug_report_data *report_data = device_data->report_data;
2234
2235    skip_call |= parameter_validation_vkCreateQueryPool(device_data->report_data, pCreateInfo, pAllocator, pQueryPool);
2236
2237    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
2238    if (pCreateInfo != nullptr) {
2239        // If queryType is VK_QUERY_TYPE_PIPELINE_STATISTICS, pipelineStatistics must be a valid combination of
2240        // VkQueryPipelineStatisticFlagBits values
2241        if ((pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) && (pCreateInfo->pipelineStatistics != 0) &&
2242            ((pCreateInfo->pipelineStatistics & (~AllVkQueryPipelineStatisticFlagBits)) != 0)) {
2243            skip_call |=
2244                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2245                        UNRECOGNIZED_VALUE, LayerName, "vkCreateQueryPool: if pCreateInfo->queryType is "
2246                                                       "VK_QUERY_TYPE_PIPELINE_STATISTICS, pCreateInfo->pipelineStatistics must be "
2247                                                       "a valid combination of VkQueryPipelineStatisticFlagBits values");
2248        }
2249    }
2250
2251    if (!skip_call) {
2252        result = get_dispatch_table(pc_device_table_map, device)->CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
2253
2254        validate_result(report_data, "vkCreateQueryPool", result);
2255    }
2256
2257    return result;
2258}
2259
2260VKAPI_ATTR void VKAPI_CALL
2261DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
2262    bool skipCall = false;
2263    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2264    assert(my_data != NULL);
2265
2266    skipCall |= parameter_validation_vkDestroyQueryPool(my_data->report_data, queryPool, pAllocator);
2267
2268    if (!skipCall) {
2269        get_dispatch_table(pc_device_table_map, device)->DestroyQueryPool(device, queryPool, pAllocator);
2270    }
2271}
2272
2273VKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
2274                                                   uint32_t queryCount, size_t dataSize, void *pData,
2275                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
2276    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2277    bool skipCall = false;
2278    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2279    assert(my_data != NULL);
2280
2281    skipCall |=
2282        parameter_validation_vkGetQueryPoolResults(my_data->report_data, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
2283
2284    if (!skipCall) {
2285        result = get_dispatch_table(pc_device_table_map, device)
2286                     ->GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
2287
2288        validate_result(my_data->report_data, "vkGetQueryPoolResults", result);
2289    }
2290
2291    return result;
2292}
2293
2294VKAPI_ATTR VkResult VKAPI_CALL
2295CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
2296    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2297    bool skip_call = false;
2298    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2299    assert(device_data != nullptr);
2300    debug_report_data *report_data = device_data->report_data;
2301
2302    skip_call |= parameter_validation_vkCreateBuffer(report_data, pCreateInfo, pAllocator, pBuffer);
2303
2304    if (pCreateInfo != nullptr) {
2305        // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
2306        if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) {
2307            // If sharingMode is VK_SHARING_MODE_CONCURRENT, queueFamilyIndexCount must be greater than 1
2308            if (pCreateInfo->queueFamilyIndexCount <= 1) {
2309                skip_call |=
2310                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2311                            INVALID_USAGE, LayerName, "vkCreateBuffer: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, "
2312                                                      "pCreateInfo->queueFamilyIndexCount must be greater than 1");
2313            }
2314
2315            // If sharingMode is VK_SHARING_MODE_CONCURRENT, pQueueFamilyIndices must be a pointer to an array of
2316            // queueFamilyIndexCount uint32_t values
2317            if (pCreateInfo->pQueueFamilyIndices == nullptr) {
2318                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2319                                     __LINE__, REQUIRED_PARAMETER, LayerName,
2320                                     "vkCreateBuffer: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, "
2321                                     "pCreateInfo->pQueueFamilyIndices must be a pointer to an array of "
2322                                     "pCreateInfo->queueFamilyIndexCount uint32_t values");
2323            }
2324
2325            // Ensure that the queue family indices were specified at device creation
2326            skip_call |= validate_queue_family_indices(device_data, "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices",
2327                                                       pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices);
2328        }
2329    }
2330
2331    if (!skip_call) {
2332        result = get_dispatch_table(pc_device_table_map, device)->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
2333
2334        validate_result(report_data, "vkCreateBuffer", result);
2335    }
2336
2337    return result;
2338}
2339
2340VKAPI_ATTR void VKAPI_CALL
2341DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
2342    bool skipCall = false;
2343    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2344    assert(my_data != NULL);
2345
2346    skipCall |= parameter_validation_vkDestroyBuffer(my_data->report_data, buffer, pAllocator);
2347
2348    if (!skipCall) {
2349        get_dispatch_table(pc_device_table_map, device)->DestroyBuffer(device, buffer, pAllocator);
2350    }
2351}
2352
2353VKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
2354                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
2355    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2356    bool skipCall = false;
2357    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2358    assert(my_data != NULL);
2359
2360    skipCall |= parameter_validation_vkCreateBufferView(my_data->report_data, pCreateInfo, pAllocator, pView);
2361
2362    if (!skipCall) {
2363        result = get_dispatch_table(pc_device_table_map, device)->CreateBufferView(device, pCreateInfo, pAllocator, pView);
2364
2365        validate_result(my_data->report_data, "vkCreateBufferView", result);
2366    }
2367
2368    return result;
2369}
2370
2371VKAPI_ATTR void VKAPI_CALL
2372DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
2373    bool skipCall = false;
2374    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2375    assert(my_data != NULL);
2376
2377    skipCall |= parameter_validation_vkDestroyBufferView(my_data->report_data, bufferView, pAllocator);
2378
2379    if (!skipCall) {
2380        get_dispatch_table(pc_device_table_map, device)->DestroyBufferView(device, bufferView, pAllocator);
2381    }
2382}
2383
2384VKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
2385                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
2386    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2387    bool skip_call = false;
2388    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2389    assert(device_data != nullptr);
2390    debug_report_data *report_data = device_data->report_data;
2391
2392    skip_call |= parameter_validation_vkCreateImage(report_data, pCreateInfo, pAllocator, pImage);
2393
2394    if (pCreateInfo != nullptr) {
2395        // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
2396        if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) {
2397            // If sharingMode is VK_SHARING_MODE_CONCURRENT, queueFamilyIndexCount must be greater than 1
2398            if (pCreateInfo->queueFamilyIndexCount <= 1) {
2399                skip_call |=
2400                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2401                            INVALID_USAGE, LayerName, "vkCreateImage: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, "
2402                                                      "pCreateInfo->queueFamilyIndexCount must be greater than 1");
2403            }
2404
2405            // If sharingMode is VK_SHARING_MODE_CONCURRENT, pQueueFamilyIndices must be a pointer to an array of
2406            // queueFamilyIndexCount uint32_t values
2407            if (pCreateInfo->pQueueFamilyIndices == nullptr) {
2408                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2409                                     __LINE__, REQUIRED_PARAMETER, LayerName,
2410                                     "vkCreateImage: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, "
2411                                     "pCreateInfo->pQueueFamilyIndices must be a pointer to an array of "
2412                                     "pCreateInfo->queueFamilyIndexCount uint32_t values");
2413            }
2414
2415            skip_call |= validate_queue_family_indices(device_data, "vkCreateImage", "pCreateInfo->pQueueFamilyIndices",
2416                                                       pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices);
2417        }
2418
2419        // width, height, and depth members of extent must be greater than 0
2420        skip_call |= ValidateGreaterThan(report_data, "vkCreateImage", "pCreateInfo->extent.width", pCreateInfo->extent.width,
2421                                           0u);
2422        skip_call |= ValidateGreaterThan(report_data, "vkCreateImage", "pCreateInfo->extent.height", pCreateInfo->extent.height,
2423                                           0u);
2424        skip_call |= ValidateGreaterThan(report_data, "vkCreateImage", "pCreateInfo->extent.depth", pCreateInfo->extent.depth,
2425                                           0u);
2426
2427        // mipLevels must be greater than 0
2428        skip_call |= ValidateGreaterThan(report_data, "vkCreateImage", "pCreateInfo->mipLevels", pCreateInfo->mipLevels,
2429                                           0u);
2430
2431        // arrayLayers must be greater than 0
2432        skip_call |= ValidateGreaterThan(report_data, "vkCreateImage", "pCreateInfo->arrayLayers", pCreateInfo->arrayLayers,
2433                                           0u);
2434
2435        // If imageType is VK_IMAGE_TYPE_1D, both extent.height and extent.depth must be 1
2436        if ((pCreateInfo->imageType == VK_IMAGE_TYPE_1D) && (pCreateInfo->extent.height != 1) && (pCreateInfo->extent.depth != 1)) {
2437            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2438                                 LayerName, "vkCreateImage: if pCreateInfo->imageType is VK_IMAGE_TYPE_1D, both "
2439                                            "pCreateInfo->extent.height and pCreateInfo->extent.depth must be 1");
2440        }
2441
2442        if (pCreateInfo->imageType == VK_IMAGE_TYPE_2D) {
2443            // If imageType is VK_IMAGE_TYPE_2D and flags contains VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, extent.width and
2444            // extent.height must be equal
2445            if ((pCreateInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) &&
2446                (pCreateInfo->extent.width != pCreateInfo->extent.height)) {
2447                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2448                                     LayerName, "vkCreateImage: if pCreateInfo->imageType is VK_IMAGE_TYPE_2D and "
2449                                                "pCreateInfo->flags contains VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, "
2450                                                "pCreateInfo->extent.width and pCreateInfo->extent.height must be equal");
2451            }
2452
2453            if (pCreateInfo->extent.depth != 1) {
2454                skip_call |=
2455                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
2456                            "vkCreateImage: if pCreateInfo->imageType is VK_IMAGE_TYPE_2D, pCreateInfo->extent.depth must be 1");
2457            }
2458        }
2459
2460        // mipLevels must be less than or equal to floor(log2(max(extent.width,extent.height,extent.depth)))+1
2461        uint32_t maxDim = std::max(std::max(pCreateInfo->extent.width, pCreateInfo->extent.height), pCreateInfo->extent.depth);
2462        if (pCreateInfo->mipLevels > (floor(log2(maxDim)) + 1)) {
2463            skip_call |= log_msg(
2464                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, LayerName,
2465                "vkCreateImage: pCreateInfo->mipLevels must be less than or equal to "
2466                "floor(log2(max(pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth)))+1");
2467        }
2468
2469        // If flags contains VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT or VK_IMAGE_CREATE_SPARSE_ALIASED_BIT, it must also contain
2470        // VK_IMAGE_CREATE_SPARSE_BINDING_BIT
2471        if (((pCreateInfo->flags & (VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT)) != 0) &&
2472            ((pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) != VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
2473            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2474                                 LayerName,
2475                                 "vkCreateImage: pCreateInfo->flags contains VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT or "
2476                                 "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT, it must also contain VK_IMAGE_CREATE_SPARSE_BINDING_BIT");
2477        }
2478    }
2479
2480    if (!skip_call) {
2481        result = get_dispatch_table(pc_device_table_map, device)->CreateImage(device, pCreateInfo, pAllocator, pImage);
2482
2483        validate_result(report_data, "vkCreateImage", result);
2484    }
2485
2486    return result;
2487}
2488
2489VKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
2490    bool skipCall = false;
2491    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2492    assert(my_data != NULL);
2493
2494    skipCall |= parameter_validation_vkDestroyImage(my_data->report_data, image, pAllocator);
2495
2496    if (!skipCall) {
2497        get_dispatch_table(pc_device_table_map, device)->DestroyImage(device, image, pAllocator);
2498    }
2499}
2500
2501bool PreGetImageSubresourceLayout(VkDevice device, const VkImageSubresource *pSubresource) {
2502    if (pSubresource != nullptr) {
2503        if ((pSubresource->aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT |
2504                                         VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
2505            log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2506                    UNRECOGNIZED_VALUE, LayerName,
2507                    "vkGetImageSubresourceLayout parameter, VkImageAspect pSubresource->aspectMask, is an unrecognized enumerator");
2508            return false;
2509        }
2510    }
2511
2512    return true;
2513}
2514
2515VKAPI_ATTR void VKAPI_CALL
2516GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout) {
2517    bool skipCall = false;
2518    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2519    assert(my_data != NULL);
2520
2521    skipCall |= parameter_validation_vkGetImageSubresourceLayout(my_data->report_data, image, pSubresource, pLayout);
2522
2523    if (!skipCall) {
2524        PreGetImageSubresourceLayout(device, pSubresource);
2525
2526        get_dispatch_table(pc_device_table_map, device)->GetImageSubresourceLayout(device, image, pSubresource, pLayout);
2527    }
2528}
2529
2530VKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
2531                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
2532    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2533    bool skip_call = false;
2534    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2535    assert(my_data != NULL);
2536    debug_report_data *report_data = my_data->report_data;
2537
2538    skip_call |= parameter_validation_vkCreateImageView(report_data, pCreateInfo, pAllocator, pView);
2539
2540    if (pCreateInfo != nullptr) {
2541        if ((pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_1D) || (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D)) {
2542            if ((pCreateInfo->subresourceRange.layerCount != 1) &&
2543                (pCreateInfo->subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS)) {
2544                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2545                                     LayerName, "vkCreateImageView: if pCreateInfo->viewType is VK_IMAGE_TYPE_%dD, "
2546                                                "pCreateInfo->subresourceRange.layerCount must be 1",
2547                                     ((pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_1D) ? 1 : 2));
2548            }
2549        } else if ((pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY) ||
2550                   (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
2551            if ((pCreateInfo->subresourceRange.layerCount < 1) &&
2552                (pCreateInfo->subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS)) {
2553                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2554                                     LayerName, "vkCreateImageView: if pCreateInfo->viewType is VK_IMAGE_TYPE_%dD_ARRAY, "
2555                                                "pCreateInfo->subresourceRange.layerCount must be >= 1",
2556                                     ((pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? 1 : 2));
2557            }
2558        } else if (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_CUBE) {
2559            if ((pCreateInfo->subresourceRange.layerCount != 6) &&
2560                (pCreateInfo->subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS)) {
2561                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2562                                     LayerName, "vkCreateImageView: if pCreateInfo->viewType is VK_IMAGE_TYPE_CUBE, "
2563                                                "pCreateInfo->subresourceRange.layerCount must be 6");
2564            }
2565        } else if (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
2566            if (((pCreateInfo->subresourceRange.layerCount == 0) || ((pCreateInfo->subresourceRange.layerCount % 6) != 0)) &&
2567                (pCreateInfo->subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS)) {
2568                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2569                                     LayerName, "vkCreateImageView: if pCreateInfo->viewType is VK_IMAGE_TYPE_CUBE_ARRAY, "
2570                                                "pCreateInfo->subresourceRange.layerCount must be a multiple of 6");
2571            }
2572        } else if (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_3D) {
2573            if (pCreateInfo->subresourceRange.baseArrayLayer != 0) {
2574                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2575                                     LayerName, "vkCreateImageView: if pCreateInfo->viewType is VK_IMAGE_TYPE_3D, "
2576                                                "pCreateInfo->subresourceRange.baseArrayLayer must be 0");
2577            }
2578
2579            if ((pCreateInfo->subresourceRange.layerCount != 1) &&
2580                (pCreateInfo->subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS)) {
2581                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
2582                                     LayerName, "vkCreateImageView: if pCreateInfo->viewType is VK_IMAGE_TYPE_3D, "
2583                                                "pCreateInfo->subresourceRange.layerCount must be 1");
2584            }
2585        }
2586    }
2587
2588    if (!skip_call) {
2589        result = get_dispatch_table(pc_device_table_map, device)->CreateImageView(device, pCreateInfo, pAllocator, pView);
2590
2591        validate_result(my_data->report_data, "vkCreateImageView", result);
2592    }
2593
2594    return result;
2595}
2596
2597VKAPI_ATTR void VKAPI_CALL
2598DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
2599    bool skipCall = false;
2600    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2601    assert(my_data != NULL);
2602
2603    skipCall |= parameter_validation_vkDestroyImageView(my_data->report_data, imageView, pAllocator);
2604
2605    if (!skipCall) {
2606        get_dispatch_table(pc_device_table_map, device)->DestroyImageView(device, imageView, pAllocator);
2607    }
2608}
2609
2610VKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
2611                                                  const VkAllocationCallbacks *pAllocator,
2612                                                  VkShaderModule *pShaderModule) {
2613    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2614    bool skipCall = false;
2615    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2616    assert(my_data != NULL);
2617
2618    skipCall |= parameter_validation_vkCreateShaderModule(my_data->report_data, pCreateInfo, pAllocator, pShaderModule);
2619
2620    if (!skipCall) {
2621        result =
2622            get_dispatch_table(pc_device_table_map, device)->CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
2623
2624        validate_result(my_data->report_data, "vkCreateShaderModule", result);
2625    }
2626
2627    return result;
2628}
2629
2630VKAPI_ATTR void VKAPI_CALL
2631DestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) {
2632    bool skipCall = false;
2633    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2634    assert(my_data != NULL);
2635
2636    skipCall |= parameter_validation_vkDestroyShaderModule(my_data->report_data, shaderModule, pAllocator);
2637
2638    if (!skipCall) {
2639        get_dispatch_table(pc_device_table_map, device)->DestroyShaderModule(device, shaderModule, pAllocator);
2640    }
2641}
2642
2643VKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
2644                                                   const VkAllocationCallbacks *pAllocator,
2645                                                   VkPipelineCache *pPipelineCache) {
2646    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2647    bool skipCall = false;
2648    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2649    assert(my_data != NULL);
2650
2651    skipCall |= parameter_validation_vkCreatePipelineCache(my_data->report_data, pCreateInfo, pAllocator, pPipelineCache);
2652
2653    if (!skipCall) {
2654        result =
2655            get_dispatch_table(pc_device_table_map, device)->CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
2656
2657        validate_result(my_data->report_data, "vkCreatePipelineCache", result);
2658    }
2659
2660    return result;
2661}
2662
2663VKAPI_ATTR void VKAPI_CALL
2664DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator) {
2665    bool skipCall = false;
2666    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2667    assert(my_data != NULL);
2668
2669    skipCall |= parameter_validation_vkDestroyPipelineCache(my_data->report_data, pipelineCache, pAllocator);
2670
2671    if (!skipCall) {
2672        get_dispatch_table(pc_device_table_map, device)->DestroyPipelineCache(device, pipelineCache, pAllocator);
2673    }
2674}
2675
2676VKAPI_ATTR VkResult VKAPI_CALL
2677GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) {
2678    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2679    bool skipCall = false;
2680    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2681    assert(my_data != NULL);
2682
2683    skipCall |= parameter_validation_vkGetPipelineCacheData(my_data->report_data, pipelineCache, pDataSize, pData);
2684
2685    if (!skipCall) {
2686        result = get_dispatch_table(pc_device_table_map, device)->GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
2687
2688        validate_result(my_data->report_data, "vkGetPipelineCacheData", result);
2689    }
2690
2691    return result;
2692}
2693
2694VKAPI_ATTR VkResult VKAPI_CALL
2695MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches) {
2696    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2697    bool skipCall = false;
2698    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2699    assert(my_data != NULL);
2700
2701    skipCall |= parameter_validation_vkMergePipelineCaches(my_data->report_data, dstCache, srcCacheCount, pSrcCaches);
2702
2703    if (!skipCall) {
2704        result = get_dispatch_table(pc_device_table_map, device)->MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
2705
2706        validate_result(my_data->report_data, "vkMergePipelineCaches", result);
2707    }
2708
2709    return result;
2710}
2711
2712bool PreCreateGraphicsPipelines(VkDevice device, const VkGraphicsPipelineCreateInfo *pCreateInfos) {
2713    layer_data *data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2714
2715    // TODO: Handle count
2716    if (pCreateInfos != nullptr) {
2717        if (pCreateInfos->flags | VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
2718            if (pCreateInfos->basePipelineIndex != -1) {
2719                if (pCreateInfos->basePipelineHandle != VK_NULL_HANDLE) {
2720                    log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2721                            INVALID_USAGE, LayerName,
2722                            "vkCreateGraphicsPipelines parameter, pCreateInfos->basePipelineHandle, must be VK_NULL_HANDLE if "
2723                            "pCreateInfos->flags "
2724                            "contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag and pCreateInfos->basePipelineIndex is not -1");
2725                    return false;
2726                }
2727            }
2728
2729            if (pCreateInfos->basePipelineHandle != VK_NULL_HANDLE) {
2730                if (pCreateInfos->basePipelineIndex != -1) {
2731                    log_msg(
2732                        mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2733                        INVALID_USAGE, LayerName,
2734                        "vkCreateGraphicsPipelines parameter, pCreateInfos->basePipelineIndex, must be -1 if pCreateInfos->flags "
2735                        "contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag and pCreateInfos->basePipelineHandle is not "
2736                        "VK_NULL_HANDLE");
2737                    return false;
2738                }
2739            }
2740        }
2741
2742        if (pCreateInfos->pRasterizationState != nullptr) {
2743            if (pCreateInfos->pRasterizationState->cullMode & ~VK_CULL_MODE_FRONT_AND_BACK) {
2744                log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2745                        UNRECOGNIZED_VALUE, LayerName,
2746                        "vkCreateGraphicsPipelines parameter, VkCullMode pCreateInfos->pRasterizationState->cullMode, is an "
2747                        "unrecognized enumerator");
2748                return false;
2749            }
2750        }
2751
2752        int i = 0;
2753        for (size_t j = 0; j < pCreateInfos[i].stageCount; j++) {
2754            validate_string(data->report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pStages[j].pName",
2755                            pCreateInfos[i].pStages[j].pName);
2756        }
2757    }
2758
2759    return true;
2760}
2761
2762VKAPI_ATTR VkResult VKAPI_CALL
2763CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
2764                        const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
2765                        VkPipeline *pPipelines) {
2766    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
2767    bool skip_call = false;
2768    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
2769    assert(device_data != nullptr);
2770    debug_report_data *report_data = device_data->report_data;
2771
2772    skip_call |= parameter_validation_vkCreateGraphicsPipelines(report_data, pipelineCache, createInfoCount, pCreateInfos,
2773                                                                pAllocator, pPipelines);
2774
2775    if (pCreateInfos != nullptr) {
2776        for (uint32_t i = 0; i < createInfoCount; ++i) {
2777            // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
2778            if (pCreateInfos[i].pTessellationState == nullptr) {
2779                if (pCreateInfos[i].pStages != nullptr) {
2780                    // If pStages includes a tessellation control shader stage and a tessellation evaluation shader stage,
2781                    // pTessellationState must not be NULL
2782                    bool has_control = false;
2783                    bool has_eval = false;
2784
2785                    for (uint32_t stage_index = 0; stage_index < pCreateInfos[i].stageCount; ++stage_index) {
2786                        if (pCreateInfos[i].pStages[stage_index].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
2787                            has_control = true;
2788                        } else if (pCreateInfos[i].pStages[stage_index].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
2789                            has_eval = true;
2790                        }
2791                    }
2792
2793                    if (has_control && has_eval) {
2794                        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2795                                             __LINE__, REQUIRED_PARAMETER, LayerName,
2796                                             "vkCreateGraphicsPipelines: if pCreateInfos[%d].pStages includes a tessellation "
2797                                             "control shader stage and a tessellation evaluation shader stage, "
2798                                             "pCreateInfos[%d].pTessellationState must not be NULL",
2799                                             i, i);
2800                    }
2801                }
2802            } else {
2803                skip_call |=
2804                    validate_struct_pnext(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pTessellationState->pNext",
2805                                          NULL, pCreateInfos[i].pTessellationState->pNext, 0, NULL, GeneratedHeaderVersion);
2806
2807                skip_call |=
2808                    validate_reserved_flags(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pTessellationState->flags",
2809                                            pCreateInfos[i].pTessellationState->flags);
2810
2811                if (pCreateInfos[i].pTessellationState->sType != VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO) {
2812                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2813                                         __LINE__, INVALID_STRUCT_STYPE, LayerName,
2814                                         "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pTessellationState->sType must be "
2815                                         "VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO",
2816                                         i);
2817                }
2818            }
2819
2820            if (pCreateInfos[i].pViewportState == nullptr) {
2821                // If the rasterizerDiscardEnable member of pRasterizationState is VK_FALSE, pViewportState must be a pointer to a
2822                // valid VkPipelineViewportStateCreateInfo structure
2823                if ((pCreateInfos[i].pRasterizationState != nullptr) &&
2824                    (pCreateInfos[i].pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
2825                    skip_call |= log_msg(
2826                        report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2827                        REQUIRED_PARAMETER, LayerName,
2828                        "vkCreateGraphicsPipelines: if pCreateInfos[%d].pRasterizationState->rasterizerDiscardEnable is VK_FALSE, "
2829                        "pCreateInfos[%d].pViewportState must be a pointer to a valid VkPipelineViewportStateCreateInfo structure",
2830                        i, i);
2831                }
2832            } else {
2833                skip_call |=
2834                    validate_struct_pnext(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pViewportState->pNext", NULL,
2835                                          pCreateInfos[i].pViewportState->pNext, 0, NULL, GeneratedHeaderVersion);
2836
2837                skip_call |=
2838                    validate_reserved_flags(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pViewportState->flags",
2839                                            pCreateInfos[i].pViewportState->flags);
2840
2841                if (pCreateInfos[i].pViewportState->sType != VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO) {
2842                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2843                                         __LINE__, INVALID_STRUCT_STYPE, LayerName,
2844                                         "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pViewportState->sType must be "
2845                                         "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO",
2846                                         i);
2847                }
2848
2849                if (pCreateInfos[i].pDynamicState != nullptr) {
2850                    bool has_dynamic_viewport = false;
2851                    bool has_dynamic_scissor = false;
2852
2853                    for (uint32_t state_index = 0; state_index < pCreateInfos[i].pDynamicState->dynamicStateCount; ++state_index) {
2854                        if (pCreateInfos[i].pDynamicState->pDynamicStates[state_index] == VK_DYNAMIC_STATE_VIEWPORT) {
2855                            has_dynamic_viewport = true;
2856                        } else if (pCreateInfos[i].pDynamicState->pDynamicStates[state_index] == VK_DYNAMIC_STATE_SCISSOR) {
2857                            has_dynamic_scissor = true;
2858                        }
2859                    }
2860
2861                    // viewportCount must be greater than 0
2862                    // TODO: viewportCount must be 1 when multiple_viewport feature is not enabled
2863                    if (pCreateInfos[i].pViewportState->viewportCount == 0) {
2864                        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2865                                             __LINE__, REQUIRED_PARAMETER, LayerName,
2866                                             "vkCreateGraphicsPipelines: if pCreateInfos[%d].pDynamicState->pDynamicStates "
2867                                             "contains VK_DYNAMIC_STATE_VIEWPORT, pCreateInfos[%d].pViewportState->viewportCount "
2868                                             "must be greater than 0",
2869                                             i, i);
2870                    }
2871
2872                    // If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_VIEWPORT, the pViewports
2873                    // member of pViewportState must be a pointer to an array of pViewportState->viewportCount VkViewport structures
2874                    if (!has_dynamic_viewport && (pCreateInfos[i].pViewportState->pViewports == nullptr)) {
2875                        skip_call |=
2876                            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2877                                    __LINE__, REQUIRED_PARAMETER, LayerName,
2878                                    "vkCreateGraphicsPipelines: if pCreateInfos[%d].pDynamicState->pDynamicStates contains "
2879                                    "VK_DYNAMIC_STATE_VIEWPORT, pCreateInfos[%d].pViewportState->pViewports must not be NULL",
2880                                    i, i);
2881                    }
2882
2883                    // scissorCount must be greater than 0
2884                    // TODO: scissorCount must be 1 when multiple_viewport feature is not enabled
2885                    if (pCreateInfos[i].pViewportState->scissorCount == 0) {
2886                        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2887                                             __LINE__, REQUIRED_PARAMETER, LayerName,
2888                                             "vkCreateGraphicsPipelines: if pCreateInfos[%d].pDynamicState->pDynamicStates "
2889                                             "contains VK_DYNAMIC_STATE_SCISSOR, pCreateInfos[%d].pViewportState->scissorCount "
2890                                             "must be greater than 0",
2891                                             i, i);
2892                    }
2893
2894                    // If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_SCISSOR, the pScissors member
2895                    // of pViewportState must be a pointer to an array of pViewportState->scissorCount VkRect2D structures
2896                    if (!has_dynamic_scissor && (pCreateInfos[i].pViewportState->pScissors == nullptr)) {
2897                        skip_call |=
2898                            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2899                                    __LINE__, REQUIRED_PARAMETER, LayerName,
2900                                    "vkCreateGraphicsPipelines: if pCreateInfos[%d].pDynamicState->pDynamicStates contains "
2901                                    "VK_DYNAMIC_STATE_SCISSOR, pCreateInfos[%d].pViewportState->pScissors must not be NULL",
2902                                    i, i);
2903                    }
2904                }
2905            }
2906
2907            if (pCreateInfos[i].pMultisampleState == nullptr) {
2908                // If the rasterizerDiscardEnable member of pRasterizationState is VK_FALSE, pMultisampleState must be a pointer to
2909                // a valid VkPipelineMultisampleStateCreateInfo structure
2910                if ((pCreateInfos[i].pRasterizationState != nullptr) &&
2911                    pCreateInfos[i].pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
2912                    skip_call |=
2913                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2914                                REQUIRED_PARAMETER, LayerName, "vkCreateGraphicsPipelines: if "
2915                                                               "pCreateInfos[%d].pRasterizationState->rasterizerDiscardEnable is "
2916                                                               "VK_FALSE, pCreateInfos[%d].pMultisampleState must not be NULL",
2917                                i, i);
2918                }
2919            } else {
2920                skip_call |=
2921                    validate_struct_pnext(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pMultisampleState->pNext",
2922                                          NULL, pCreateInfos[i].pMultisampleState->pNext, 0, NULL, GeneratedHeaderVersion);
2923
2924                skip_call |=
2925                    validate_reserved_flags(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pMultisampleState->flags",
2926                                            pCreateInfos[i].pMultisampleState->flags);
2927
2928                skip_call |= validate_bool32(report_data, "vkCreateGraphicsPipelines",
2929                                             "pCreateInfos[i].pMultisampleState->sampleShadingEnable",
2930                                             pCreateInfos[i].pMultisampleState->sampleShadingEnable);
2931
2932                skip_call |= validate_array(
2933                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pMultisampleState->rasterizationSamples",
2934                    "pCreateInfos[i].pMultisampleState->pSampleMask", pCreateInfos[i].pMultisampleState->rasterizationSamples,
2935                    pCreateInfos[i].pMultisampleState->pSampleMask, true, false);
2936
2937                skip_call |= validate_bool32(report_data, "vkCreateGraphicsPipelines",
2938                                             "pCreateInfos[i].pMultisampleState->alphaToCoverageEnable",
2939                                             pCreateInfos[i].pMultisampleState->alphaToCoverageEnable);
2940
2941                skip_call |=
2942                    validate_bool32(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pMultisampleState->alphaToOneEnable",
2943                                    pCreateInfos[i].pMultisampleState->alphaToOneEnable);
2944
2945                if (pCreateInfos[i].pMultisampleState->sType != VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO) {
2946                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2947                                         __LINE__, INVALID_STRUCT_STYPE, LayerName,
2948                                         "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pMultisampleState->sType must be "
2949                                         "VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO",
2950                                         i);
2951                }
2952            }
2953
2954            // TODO: Conditional NULL check based on rasterizerDiscardEnable and subpass
2955            if (pCreateInfos[i].pDepthStencilState != nullptr) {
2956                skip_call |=
2957                    validate_struct_pnext(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->pNext",
2958                                          NULL, pCreateInfos[i].pDepthStencilState->pNext, 0, NULL, GeneratedHeaderVersion);
2959
2960                skip_call |=
2961                    validate_reserved_flags(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->flags",
2962                                            pCreateInfos[i].pDepthStencilState->flags);
2963
2964                skip_call |=
2965                    validate_bool32(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->depthTestEnable",
2966                                    pCreateInfos[i].pDepthStencilState->depthTestEnable);
2967
2968                skip_call |= validate_bool32(report_data, "vkCreateGraphicsPipelines",
2969                                             "pCreateInfos[i].pDepthStencilState->depthWriteEnable",
2970                                             pCreateInfos[i].pDepthStencilState->depthWriteEnable);
2971
2972                skip_call |= validate_ranged_enum(
2973                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->depthCompareOp", "VkCompareOp",
2974                    VK_COMPARE_OP_BEGIN_RANGE, VK_COMPARE_OP_END_RANGE, pCreateInfos[i].pDepthStencilState->depthCompareOp);
2975
2976                skip_call |= validate_bool32(report_data, "vkCreateGraphicsPipelines",
2977                                             "pCreateInfos[i].pDepthStencilState->depthBoundsTestEnable",
2978                                             pCreateInfos[i].pDepthStencilState->depthBoundsTestEnable);
2979
2980                skip_call |= validate_bool32(report_data, "vkCreateGraphicsPipelines",
2981                                             "pCreateInfos[i].pDepthStencilState->stencilTestEnable",
2982                                             pCreateInfos[i].pDepthStencilState->stencilTestEnable);
2983
2984                skip_call |= validate_ranged_enum(
2985                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->front.failOp", "VkStencilOp",
2986                    VK_STENCIL_OP_BEGIN_RANGE, VK_STENCIL_OP_END_RANGE, pCreateInfos[i].pDepthStencilState->front.failOp);
2987
2988                skip_call |= validate_ranged_enum(
2989                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->front.passOp", "VkStencilOp",
2990                    VK_STENCIL_OP_BEGIN_RANGE, VK_STENCIL_OP_END_RANGE, pCreateInfos[i].pDepthStencilState->front.passOp);
2991
2992                skip_call |= validate_ranged_enum(report_data, "vkCreateGraphicsPipelines",
2993                                                  "pCreateInfos[i].pDepthStencilState->front.depthFailOp", "VkStencilOp",
2994                                                  VK_STENCIL_OP_BEGIN_RANGE, VK_STENCIL_OP_END_RANGE,
2995                                                  pCreateInfos[i].pDepthStencilState->front.depthFailOp);
2996
2997                skip_call |= validate_ranged_enum(
2998                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->front.compareOp", "VkCompareOp",
2999                    VK_COMPARE_OP_BEGIN_RANGE, VK_COMPARE_OP_END_RANGE, pCreateInfos[i].pDepthStencilState->front.compareOp);
3000
3001                skip_call |= validate_ranged_enum(
3002                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->back.failOp", "VkStencilOp",
3003                    VK_STENCIL_OP_BEGIN_RANGE, VK_STENCIL_OP_END_RANGE, pCreateInfos[i].pDepthStencilState->back.failOp);
3004
3005                skip_call |= validate_ranged_enum(
3006                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->back.passOp", "VkStencilOp",
3007                    VK_STENCIL_OP_BEGIN_RANGE, VK_STENCIL_OP_END_RANGE, pCreateInfos[i].pDepthStencilState->back.passOp);
3008
3009                skip_call |= validate_ranged_enum(
3010                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->back.depthFailOp", "VkStencilOp",
3011                    VK_STENCIL_OP_BEGIN_RANGE, VK_STENCIL_OP_END_RANGE, pCreateInfos[i].pDepthStencilState->back.depthFailOp);
3012
3013                skip_call |= validate_ranged_enum(
3014                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pDepthStencilState->back.compareOp", "VkCompareOp",
3015                    VK_COMPARE_OP_BEGIN_RANGE, VK_COMPARE_OP_END_RANGE, pCreateInfos[i].pDepthStencilState->back.compareOp);
3016
3017                if (pCreateInfos[i].pDepthStencilState->sType != VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO) {
3018                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3019                                         __LINE__, INVALID_STRUCT_STYPE, LayerName,
3020                                         "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pDepthStencilState->sType must be "
3021                                         "VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO",
3022                                         i);
3023                }
3024            }
3025
3026            // TODO: Conditional NULL check based on rasterizerDiscardEnable and subpass
3027            if (pCreateInfos[i].pColorBlendState != nullptr) {
3028                skip_call |=
3029                    validate_struct_pnext(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pColorBlendState->pNext", NULL,
3030                                          pCreateInfos[i].pColorBlendState->pNext, 0, NULL, GeneratedHeaderVersion);
3031
3032                skip_call |=
3033                    validate_reserved_flags(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pColorBlendState->flags",
3034                                            pCreateInfos[i].pColorBlendState->flags);
3035
3036                skip_call |=
3037                    validate_bool32(report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pColorBlendState->logicOpEnable",
3038                                    pCreateInfos[i].pColorBlendState->logicOpEnable);
3039
3040                skip_call |= validate_array(
3041                    report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pColorBlendState->attachmentCount",
3042                    "pCreateInfos[i].pColorBlendState->pAttachments", pCreateInfos[i].pColorBlendState->attachmentCount,
3043                    pCreateInfos[i].pColorBlendState->pAttachments, false, true);
3044
3045                if (pCreateInfos[i].pColorBlendState->pAttachments != NULL) {
3046                    for (uint32_t attachmentIndex = 0; attachmentIndex < pCreateInfos[i].pColorBlendState->attachmentCount;
3047                         ++attachmentIndex) {
3048                        skip_call |= validate_bool32(report_data, "vkCreateGraphicsPipelines",
3049                                                     "pCreateInfos[i].pColorBlendState->pAttachments[i].blendEnable",
3050                                                     pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].blendEnable);
3051
3052                        skip_call |= validate_ranged_enum(
3053                            report_data, "vkCreateGraphicsPipelines",
3054                            "pCreateInfos[i].pColorBlendState->pAttachments[i].srcColorBlendFactor", "VkBlendFactor",
3055                            VK_BLEND_FACTOR_BEGIN_RANGE, VK_BLEND_FACTOR_END_RANGE,
3056                            pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].srcColorBlendFactor);
3057
3058                        skip_call |= validate_ranged_enum(
3059                            report_data, "vkCreateGraphicsPipelines",
3060                            "pCreateInfos[i].pColorBlendState->pAttachments[i].dstColorBlendFactor", "VkBlendFactor",
3061                            VK_BLEND_FACTOR_BEGIN_RANGE, VK_BLEND_FACTOR_END_RANGE,
3062                            pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].dstColorBlendFactor);
3063
3064                        skip_call |= validate_ranged_enum(
3065                            report_data, "vkCreateGraphicsPipelines",
3066                            "pCreateInfos[i].pColorBlendState->pAttachments[i].colorBlendOp", "VkBlendOp", VK_BLEND_OP_BEGIN_RANGE,
3067                            VK_BLEND_OP_END_RANGE, pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].colorBlendOp);
3068
3069                        skip_call |= validate_ranged_enum(
3070                            report_data, "vkCreateGraphicsPipelines",
3071                            "pCreateInfos[i].pColorBlendState->pAttachments[i].srcAlphaBlendFactor", "VkBlendFactor",
3072                            VK_BLEND_FACTOR_BEGIN_RANGE, VK_BLEND_FACTOR_END_RANGE,
3073                            pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].srcAlphaBlendFactor);
3074
3075                        skip_call |= validate_ranged_enum(
3076                            report_data, "vkCreateGraphicsPipelines",
3077                            "pCreateInfos[i].pColorBlendState->pAttachments[i].dstAlphaBlendFactor", "VkBlendFactor",
3078                            VK_BLEND_FACTOR_BEGIN_RANGE, VK_BLEND_FACTOR_END_RANGE,
3079                            pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].dstAlphaBlendFactor);
3080
3081                        skip_call |= validate_ranged_enum(
3082                            report_data, "vkCreateGraphicsPipelines",
3083                            "pCreateInfos[i].pColorBlendState->pAttachments[i].alphaBlendOp", "VkBlendOp", VK_BLEND_OP_BEGIN_RANGE,
3084                            VK_BLEND_OP_END_RANGE, pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].alphaBlendOp);
3085
3086                        skip_call |=
3087                            validate_flags(report_data, "vkCreateGraphicsPipelines",
3088                                           "pCreateInfos[i].pColorBlendState->pAttachments[i].colorWriteMask",
3089                                           "VkColorComponentFlagBits", AllVkColorComponentFlagBits,
3090                                           pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].colorWriteMask, false);
3091                    }
3092                }
3093
3094                if (pCreateInfos[i].pColorBlendState->sType != VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO) {
3095                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3096                                         __LINE__, INVALID_STRUCT_STYPE, LayerName,
3097                                         "vkCreateGraphicsPipelines: parameter pCreateInfos[%d].pColorBlendState->sType must be "
3098                                         "VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO",
3099                                         i);
3100                }
3101
3102                // If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value
3103                if (pCreateInfos[i].pColorBlendState->logicOpEnable == VK_TRUE) {
3104                    skip_call |= validate_ranged_enum(
3105                        report_data, "vkCreateGraphicsPipelines", "pCreateInfos[i].pColorBlendState->logicOp", "VkLogicOp",
3106                        VK_LOGIC_OP_BEGIN_RANGE, VK_LOGIC_OP_END_RANGE, pCreateInfos[i].pColorBlendState->logicOp);
3107                }
3108            }
3109        }
3110    }
3111
3112    if (!skip_call) {
3113        PreCreateGraphicsPipelines(device, pCreateInfos);
3114
3115        result = get_dispatch_table(pc_device_table_map, device)
3116                     ->CreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
3117
3118        validate_result(report_data, "vkCreateGraphicsPipelines", result);
3119    }
3120
3121    return result;
3122}
3123
3124bool PreCreateComputePipelines(VkDevice device, const VkComputePipelineCreateInfo *pCreateInfos) {
3125    layer_data *data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3126
3127    if (pCreateInfos != nullptr) {
3128        // TODO: Handle count!
3129        int i = 0;
3130        validate_string(data->report_data, "vkCreateComputePipelines", "pCreateInfos[i].stage.pName", pCreateInfos[i].stage.pName);
3131    }
3132
3133    return true;
3134}
3135
3136VKAPI_ATTR VkResult VKAPI_CALL
3137CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
3138                       const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
3139                       VkPipeline *pPipelines) {
3140    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3141    bool skipCall = false;
3142    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3143    assert(my_data != NULL);
3144
3145    skipCall |= parameter_validation_vkCreateComputePipelines(my_data->report_data, pipelineCache, createInfoCount, pCreateInfos, pAllocator,
3146                                                     pPipelines);
3147
3148    if (!skipCall) {
3149        PreCreateComputePipelines(device, pCreateInfos);
3150
3151        result = get_dispatch_table(pc_device_table_map, device)
3152                     ->CreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
3153
3154        validate_result(my_data->report_data, "vkCreateComputePipelines", result);
3155    }
3156
3157    return result;
3158}
3159
3160VKAPI_ATTR void VKAPI_CALL
3161DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
3162    bool skipCall = false;
3163    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3164    assert(my_data != NULL);
3165
3166    skipCall |= parameter_validation_vkDestroyPipeline(my_data->report_data, pipeline, pAllocator);
3167
3168    if (!skipCall) {
3169        get_dispatch_table(pc_device_table_map, device)->DestroyPipeline(device, pipeline, pAllocator);
3170    }
3171}
3172
3173VKAPI_ATTR VkResult VKAPI_CALL
3174CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
3175                     VkPipelineLayout *pPipelineLayout) {
3176    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3177    bool skipCall = false;
3178    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3179    assert(my_data != NULL);
3180
3181    skipCall |= parameter_validation_vkCreatePipelineLayout(my_data->report_data, pCreateInfo, pAllocator, pPipelineLayout);
3182
3183    if (!skipCall) {
3184        result =
3185            get_dispatch_table(pc_device_table_map, device)->CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
3186
3187        validate_result(my_data->report_data, "vkCreatePipelineLayout", result);
3188    }
3189
3190    return result;
3191}
3192
3193VKAPI_ATTR void VKAPI_CALL
3194DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) {
3195    bool skipCall = false;
3196    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3197    assert(my_data != NULL);
3198
3199    skipCall |= parameter_validation_vkDestroyPipelineLayout(my_data->report_data, pipelineLayout, pAllocator);
3200
3201    if (!skipCall) {
3202        get_dispatch_table(pc_device_table_map, device)->DestroyPipelineLayout(device, pipelineLayout, pAllocator);
3203    }
3204}
3205
3206VKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
3207                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
3208    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3209    bool skip_call = false;
3210    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3211    assert(device_data != NULL);
3212    debug_report_data *report_data = device_data->report_data;
3213
3214    skip_call |= parameter_validation_vkCreateSampler(report_data, pCreateInfo, pAllocator, pSampler);
3215
3216    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
3217    if (pCreateInfo != nullptr) {
3218        // If compareEnable is VK_TRUE, compareOp must be a valid VkCompareOp value
3219        if (pCreateInfo->compareEnable == VK_TRUE) {
3220            skip_call |= validate_ranged_enum(report_data, "vkCreateSampler", "pCreateInfo->compareOp", "VkCompareOp",
3221                                              VK_COMPARE_OP_BEGIN_RANGE, VK_COMPARE_OP_END_RANGE, pCreateInfo->compareOp);
3222        }
3223
3224        // If any of addressModeU, addressModeV or addressModeW are VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, borderColor must be a
3225        // valid VkBorderColor value
3226        if ((pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) ||
3227            (pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) ||
3228            (pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)) {
3229            skip_call |= validate_ranged_enum(report_data, "vkCreateSampler", "pCreateInfo->borderColor", "VkBorderColor",
3230                                              VK_BORDER_COLOR_BEGIN_RANGE, VK_BORDER_COLOR_END_RANGE, pCreateInfo->borderColor);
3231        }
3232    }
3233
3234    if (!skip_call) {
3235        result = get_dispatch_table(pc_device_table_map, device)->CreateSampler(device, pCreateInfo, pAllocator, pSampler);
3236
3237        validate_result(report_data, "vkCreateSampler", result);
3238    }
3239
3240    return result;
3241}
3242
3243VKAPI_ATTR void VKAPI_CALL
3244DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
3245    bool skipCall = false;
3246    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3247    assert(my_data != NULL);
3248
3249    skipCall |= parameter_validation_vkDestroySampler(my_data->report_data, sampler, pAllocator);
3250
3251    if (!skipCall) {
3252        get_dispatch_table(pc_device_table_map, device)->DestroySampler(device, sampler, pAllocator);
3253    }
3254}
3255
3256VKAPI_ATTR VkResult VKAPI_CALL
3257CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
3258                          const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) {
3259    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3260    bool skip_call = false;
3261    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3262    assert(device_data != nullptr);
3263    debug_report_data *report_data = device_data->report_data;
3264
3265    skip_call |= parameter_validation_vkCreateDescriptorSetLayout(report_data, pCreateInfo, pAllocator, pSetLayout);
3266
3267    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
3268    if ((pCreateInfo != nullptr) && (pCreateInfo->pBindings != nullptr)) {
3269        for (uint32_t i = 0; i < pCreateInfo->bindingCount; ++i) {
3270            if (pCreateInfo->pBindings[i].descriptorCount != 0) {
3271                // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, and descriptorCount
3272                // is not 0 and pImmutableSamplers is not NULL, pImmutableSamplers must be a pointer to an array of descriptorCount
3273                // valid VkSampler handles
3274                if (((pCreateInfo->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) ||
3275                     (pCreateInfo->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) &&
3276                    (pCreateInfo->pBindings[i].pImmutableSamplers != nullptr)) {
3277                    for (uint32_t descriptor_index = 0; descriptor_index < pCreateInfo->pBindings[i].descriptorCount;
3278                         ++descriptor_index) {
3279                        if (pCreateInfo->pBindings[i].pImmutableSamplers[descriptor_index] == VK_NULL_HANDLE) {
3280                            skip_call |=
3281                                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3282                                        __LINE__, REQUIRED_PARAMETER, LayerName, "vkCreateDescriptorSetLayout: required parameter "
3283                                                                                 "pCreateInfo->pBindings[%d].pImmutableSamplers[%d]"
3284                                                                                 " specified as VK_NULL_HANDLE",
3285                                        i, descriptor_index);
3286                        }
3287                    }
3288                }
3289
3290                // If descriptorCount is not 0, stageFlags must be a valid combination of VkShaderStageFlagBits values
3291                if ((pCreateInfo->pBindings[i].stageFlags != 0) &&
3292                    ((pCreateInfo->pBindings[i].stageFlags & (~AllVkShaderStageFlagBits)) != 0)) {
3293                    skip_call |=
3294                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
3295                                UNRECOGNIZED_VALUE, LayerName,
3296                                "vkCreateDescriptorSetLayout: if pCreateInfo->pBindings[%d].descriptorCount is not 0, "
3297                                "pCreateInfo->pBindings[%d].stageFlags must be a valid combination of VkShaderStageFlagBits values",
3298                                i, i);
3299                }
3300            }
3301        }
3302    }
3303
3304    if (!skip_call) {
3305        result =
3306            get_dispatch_table(pc_device_table_map, device)->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
3307
3308        validate_result(report_data, "vkCreateDescriptorSetLayout", result);
3309    }
3310
3311    return result;
3312}
3313
3314VKAPI_ATTR void VKAPI_CALL
3315DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) {
3316    bool skipCall = false;
3317    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3318    assert(my_data != NULL);
3319
3320    skipCall |= parameter_validation_vkDestroyDescriptorSetLayout(my_data->report_data, descriptorSetLayout, pAllocator);
3321
3322    if (!skipCall) {
3323        get_dispatch_table(pc_device_table_map, device)->DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
3324    }
3325}
3326
3327VKAPI_ATTR VkResult VKAPI_CALL
3328CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
3329                     VkDescriptorPool *pDescriptorPool) {
3330    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3331    bool skipCall = false;
3332    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3333    assert(my_data != NULL);
3334
3335    skipCall |= parameter_validation_vkCreateDescriptorPool(my_data->report_data, pCreateInfo, pAllocator, pDescriptorPool);
3336
3337    /* TODOVV: How do we validate maxSets? Probably belongs in the limits layer? */
3338
3339    if (!skipCall) {
3340        result =
3341            get_dispatch_table(pc_device_table_map, device)->CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
3342
3343        validate_result(my_data->report_data, "vkCreateDescriptorPool", result);
3344    }
3345
3346    return result;
3347}
3348
3349VKAPI_ATTR void VKAPI_CALL
3350DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) {
3351    bool skipCall = false;
3352    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3353    assert(my_data != NULL);
3354
3355    skipCall |= parameter_validation_vkDestroyDescriptorPool(my_data->report_data, descriptorPool, pAllocator);
3356
3357    if (!skipCall) {
3358        get_dispatch_table(pc_device_table_map, device)->DestroyDescriptorPool(device, descriptorPool, pAllocator);
3359    }
3360}
3361
3362VKAPI_ATTR VkResult VKAPI_CALL
3363ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) {
3364    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3365    bool skipCall = false;
3366    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3367    assert(my_data != NULL);
3368
3369    skipCall |= parameter_validation_vkResetDescriptorPool(my_data->report_data, descriptorPool, flags);
3370
3371    if (!skipCall) {
3372        result = get_dispatch_table(pc_device_table_map, device)->ResetDescriptorPool(device, descriptorPool, flags);
3373
3374        validate_result(my_data->report_data, "vkResetDescriptorPool", result);
3375    }
3376
3377    return result;
3378}
3379
3380VKAPI_ATTR VkResult VKAPI_CALL
3381AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) {
3382    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3383    bool skipCall = false;
3384    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3385    assert(my_data != NULL);
3386
3387    skipCall |= parameter_validation_vkAllocateDescriptorSets(my_data->report_data, pAllocateInfo, pDescriptorSets);
3388
3389    if (!skipCall) {
3390        result = get_dispatch_table(pc_device_table_map, device)->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
3391
3392        validate_result(my_data->report_data, "vkAllocateDescriptorSets", result);
3393    }
3394
3395    return result;
3396}
3397
3398VKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool,
3399                                                  uint32_t descriptorSetCount,
3400                                                  const VkDescriptorSet *pDescriptorSets) {
3401    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3402    bool skip_call = false;
3403    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3404    assert(device_data != nullptr);
3405    debug_report_data *report_data = device_data->report_data;
3406
3407    skip_call |= parameter_validation_vkFreeDescriptorSets(report_data, descriptorPool, descriptorSetCount, pDescriptorSets);
3408
3409    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
3410    // This is an array of handles, where the elements are allowed to be VK_NULL_HANDLE, and does not require any validation beyond
3411    // validate_array()
3412    skip_call |= validate_array(report_data, "vkFreeDescriptorSets", "descriptorSetCount", "pDescriptorSets", descriptorSetCount,
3413                                pDescriptorSets, true, true);
3414
3415    if (!skip_call) {
3416        result = get_dispatch_table(pc_device_table_map, device)
3417                     ->FreeDescriptorSets(device, descriptorPool, descriptorSetCount, pDescriptorSets);
3418
3419        validate_result(report_data, "vkFreeDescriptorSets", result);
3420    }
3421
3422    return result;
3423}
3424
3425VKAPI_ATTR void VKAPI_CALL
3426UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites,
3427                     uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) {
3428    bool skip_call = false;
3429    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3430    assert(device_data != NULL);
3431    debug_report_data *report_data = device_data->report_data;
3432
3433    skip_call |= parameter_validation_vkUpdateDescriptorSets(report_data, descriptorWriteCount, pDescriptorWrites,
3434                                                             descriptorCopyCount, pDescriptorCopies);
3435
3436    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
3437    if (pDescriptorWrites != NULL) {
3438        for (uint32_t i = 0; i < descriptorWriteCount; ++i) {
3439            // descriptorCount must be greater than 0
3440            if (pDescriptorWrites[i].descriptorCount == 0) {
3441                skip_call |=
3442                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
3443                            REQUIRED_PARAMETER, LayerName,
3444                            "vkUpdateDescriptorSets: parameter pDescriptorWrites[%d].descriptorCount must be greater than 0", i);
3445            }
3446
3447            if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) ||
3448                (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
3449                (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
3450                (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
3451                (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
3452                // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
3453                // VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE or VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
3454                // pImageInfo must be a pointer to an array of descriptorCount valid VkDescriptorImageInfo structures
3455                if (pDescriptorWrites[i].pImageInfo == nullptr) {
3456                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3457                                         __LINE__, REQUIRED_PARAMETER, LayerName,
3458                                         "vkUpdateDescriptorSets: if pDescriptorWrites[%d].descriptorType is "
3459                                         "VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, "
3460                                         "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE or "
3461                                         "VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, pDescriptorWrites[%d].pImageInfo must not be NULL",
3462                                         i, i);
3463                } else if (pDescriptorWrites[i].descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) {
3464                    // If descriptorType is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
3465                    // VK_DESCRIPTOR_TYPE_STORAGE_IMAGE or VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, the imageView and imageLayout
3466                    // members of any given element of pImageInfo must be a valid VkImageView and VkImageLayout, respectively
3467                    for (uint32_t descriptor_index = 0; descriptor_index < pDescriptorWrites[i].descriptorCount;
3468                         ++descriptor_index) {
3469                        skip_call |= validate_required_handle(report_data, "vkUpdateDescriptorSets",
3470                                                              "pDescriptorWrites[i].pImageInfo[i].imageView",
3471                                                              pDescriptorWrites[i].pImageInfo[descriptor_index].imageView);
3472                        skip_call |= validate_ranged_enum(report_data, "vkUpdateDescriptorSets",
3473                                                          "pDescriptorWrites[i].pImageInfo[i].imageLayout", "VkImageLayout",
3474                                                          VK_IMAGE_LAYOUT_BEGIN_RANGE, VK_IMAGE_LAYOUT_END_RANGE,
3475                                                          pDescriptorWrites[i].pImageInfo[descriptor_index].imageLayout);
3476                    }
3477                }
3478            } else if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
3479                       (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
3480                       (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
3481                       (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
3482                // If descriptorType is VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
3483                // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, pBufferInfo must be a
3484                // pointer to an array of descriptorCount valid VkDescriptorBufferInfo structures
3485                if (pDescriptorWrites[i].pBufferInfo == nullptr) {
3486                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3487                                         __LINE__, REQUIRED_PARAMETER, LayerName,
3488                                         "vkUpdateDescriptorSets: if pDescriptorWrites[%d].descriptorType is "
3489                                         "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, "
3490                                         "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, "
3491                                         "pDescriptorWrites[%d].pBufferInfo must not be NULL",
3492                                         i, i);
3493                } else {
3494                    for (uint32_t descriptorIndex = 0; descriptorIndex < pDescriptorWrites[i].descriptorCount; ++descriptorIndex) {
3495                        skip_call |= validate_required_handle(report_data, "vkUpdateDescriptorSets",
3496                                                              "pDescriptorWrites[i].pBufferInfo[i].buffer",
3497                                                              pDescriptorWrites[i].pBufferInfo[descriptorIndex].buffer);
3498                    }
3499                }
3500            } else if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
3501                       (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)) {
3502                // If descriptorType is VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
3503                // pTexelBufferView must be a pointer to an array of descriptorCount valid VkBufferView handles
3504                if (pDescriptorWrites[i].pTexelBufferView == nullptr) {
3505                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3506                                         __LINE__, REQUIRED_PARAMETER, LayerName,
3507                                         "vkUpdateDescriptorSets: if pDescriptorWrites[%d].descriptorType is "
3508                                         "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, "
3509                                         "pDescriptorWrites[%d].pTexelBufferView must not be NULL",
3510                                         i, i);
3511                } else {
3512                    for (uint32_t descriptor_index = 0; descriptor_index < pDescriptorWrites[i].descriptorCount;
3513                         ++descriptor_index) {
3514                        skip_call |= validate_required_handle(report_data, "vkUpdateDescriptorSets",
3515                                                              "pDescriptorWrites[i].pTexelBufferView[i]",
3516                                                              pDescriptorWrites[i].pTexelBufferView[descriptor_index]);
3517                    }
3518                }
3519            }
3520
3521            if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
3522                (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)) {
3523                VkDeviceSize uniformAlignment = device_data->device_limits.minUniformBufferOffsetAlignment;
3524                for (uint32_t j = 0; j < pDescriptorWrites[i].descriptorCount; j++) {
3525                    if (pDescriptorWrites[i].pBufferInfo != NULL) {
3526                        if (vk_safe_modulo(pDescriptorWrites[i].pBufferInfo[j].offset, uniformAlignment) != 0) {
3527                            skip_call |=
3528                                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3529                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVICE_LIMIT, LayerName,
3530                                        "vkUpdateDescriptorSets(): pDescriptorWrites[%d].pBufferInfo[%d].offset (0x%" PRIxLEAST64
3531                                        ") must be a multiple of device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64,
3532                                        i, j, pDescriptorWrites[i].pBufferInfo[j].offset, uniformAlignment);
3533                        }
3534                    }
3535                }
3536            } else if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
3537                       (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
3538                VkDeviceSize storageAlignment = device_data->device_limits.minStorageBufferOffsetAlignment;
3539                for (uint32_t j = 0; j < pDescriptorWrites[i].descriptorCount; j++) {
3540                    if (pDescriptorWrites[i].pBufferInfo != NULL) {
3541                        if (vk_safe_modulo(pDescriptorWrites[i].pBufferInfo[j].offset, storageAlignment) != 0) {
3542                            skip_call |=
3543                                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3544                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVICE_LIMIT, LayerName,
3545                                        "vkUpdateDescriptorSets(): pDescriptorWrites[%d].pBufferInfo[%d].offset (0x%" PRIxLEAST64
3546                                        ") must be a multiple of device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64,
3547                                        i, j, pDescriptorWrites[i].pBufferInfo[j].offset, storageAlignment);
3548                        }
3549                    }
3550                }
3551            }
3552        }
3553    }
3554
3555    if (!skip_call) {
3556        get_dispatch_table(pc_device_table_map, device)
3557            ->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies);
3558    }
3559}
3560
3561VKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
3562                                                 const VkAllocationCallbacks *pAllocator,
3563                                                                   VkFramebuffer *pFramebuffer) {
3564    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3565    bool skipCall = false;
3566    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3567    assert(my_data != NULL);
3568
3569    skipCall |= parameter_validation_vkCreateFramebuffer(my_data->report_data, pCreateInfo, pAllocator, pFramebuffer);
3570
3571    if (!skipCall) {
3572        result = get_dispatch_table(pc_device_table_map, device)->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
3573
3574        validate_result(my_data->report_data, "vkCreateFramebuffer", result);
3575    }
3576
3577    return result;
3578}
3579
3580VKAPI_ATTR void VKAPI_CALL
3581DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
3582    bool skipCall = false;
3583    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3584    assert(my_data != NULL);
3585
3586    skipCall |= parameter_validation_vkDestroyFramebuffer(my_data->report_data, framebuffer, pAllocator);
3587
3588    if (!skipCall) {
3589        get_dispatch_table(pc_device_table_map, device)->DestroyFramebuffer(device, framebuffer, pAllocator);
3590    }
3591}
3592
3593bool PreCreateRenderPass(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
3594    bool skip_call = false;
3595    uint32_t max_color_attachments = dev_data->device_limits.maxColorAttachments;
3596
3597    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
3598        if (pCreateInfo->pSubpasses[i].colorAttachmentCount > max_color_attachments) {
3599            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3600                                 __LINE__, DEVICE_LIMIT, "DL",
3601                                 "Cannot create a render pass with %d color attachments. Max is %d.",
3602                                 pCreateInfo->pSubpasses[i].colorAttachmentCount, max_color_attachments);
3603        }
3604    }
3605    return skip_call;
3606}
3607
3608VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
3609                                                const VkAllocationCallbacks *pAllocator,
3610                                                VkRenderPass *pRenderPass) {
3611    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3612    bool skipCall = false;
3613    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3614    assert(my_data != NULL);
3615
3616    skipCall |= parameter_validation_vkCreateRenderPass(my_data->report_data, pCreateInfo, pAllocator, pRenderPass);
3617    skipCall |= PreCreateRenderPass(my_data, pCreateInfo);
3618
3619    if (!skipCall) {
3620        result = get_dispatch_table(pc_device_table_map, device)->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
3621
3622        validate_result(my_data->report_data, "vkCreateRenderPass", result);
3623    }
3624
3625    return result;
3626}
3627
3628VKAPI_ATTR void VKAPI_CALL
3629DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
3630    bool skipCall = false;
3631    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3632    assert(my_data != NULL);
3633
3634    skipCall |= parameter_validation_vkDestroyRenderPass(my_data->report_data, renderPass, pAllocator);
3635
3636    if (!skipCall) {
3637        get_dispatch_table(pc_device_table_map, device)->DestroyRenderPass(device, renderPass, pAllocator);
3638    }
3639}
3640
3641VKAPI_ATTR void VKAPI_CALL
3642GetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D *pGranularity) {
3643    bool skipCall = false;
3644    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3645    assert(my_data != NULL);
3646
3647    skipCall |= parameter_validation_vkGetRenderAreaGranularity(my_data->report_data, renderPass, pGranularity);
3648
3649    if (!skipCall) {
3650        get_dispatch_table(pc_device_table_map, device)->GetRenderAreaGranularity(device, renderPass, pGranularity);
3651    }
3652}
3653
3654VKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
3655                                                 const VkAllocationCallbacks *pAllocator,
3656                                                 VkCommandPool *pCommandPool) {
3657    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3658    bool skipCall = false;
3659    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3660    assert(my_data != NULL);
3661
3662    skipCall |=
3663        validate_queue_family_index(my_data, "vkCreateCommandPool", "pCreateInfo->queueFamilyIndex", pCreateInfo->queueFamilyIndex);
3664
3665    skipCall |= parameter_validation_vkCreateCommandPool(my_data->report_data, pCreateInfo, pAllocator, pCommandPool);
3666
3667    if (!skipCall) {
3668        result = get_dispatch_table(pc_device_table_map, device)->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
3669
3670        validate_result(my_data->report_data, "vkCreateCommandPool", result);
3671    }
3672
3673    return result;
3674}
3675
3676VKAPI_ATTR void VKAPI_CALL
3677DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
3678    bool skipCall = false;
3679    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3680    assert(my_data != NULL);
3681
3682    skipCall |= parameter_validation_vkDestroyCommandPool(my_data->report_data, commandPool, pAllocator);
3683
3684    if (!skipCall) {
3685        get_dispatch_table(pc_device_table_map, device)->DestroyCommandPool(device, commandPool, pAllocator);
3686    }
3687}
3688
3689VKAPI_ATTR VkResult VKAPI_CALL
3690ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
3691    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3692    bool skipCall = false;
3693    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3694    assert(my_data != NULL);
3695
3696    skipCall |= parameter_validation_vkResetCommandPool(my_data->report_data, commandPool, flags);
3697
3698    if (!skipCall) {
3699        result = get_dispatch_table(pc_device_table_map, device)->ResetCommandPool(device, commandPool, flags);
3700
3701        validate_result(my_data->report_data, "vkResetCommandPool", result);
3702    }
3703
3704    return result;
3705}
3706
3707VKAPI_ATTR VkResult VKAPI_CALL
3708AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers) {
3709    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3710    bool skipCall = false;
3711    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3712    assert(my_data != NULL);
3713
3714    skipCall |= parameter_validation_vkAllocateCommandBuffers(my_data->report_data, pAllocateInfo, pCommandBuffers);
3715
3716    if (!skipCall) {
3717        result = get_dispatch_table(pc_device_table_map, device)->AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers);
3718
3719        validate_result(my_data->report_data, "vkAllocateCommandBuffers", result);
3720    }
3721
3722    return result;
3723}
3724
3725VKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool,
3726                                              uint32_t commandBufferCount,
3727                                              const VkCommandBuffer *pCommandBuffers) {
3728    bool skip_call = false;
3729    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
3730    assert(device_data != nullptr);
3731    debug_report_data *report_data = device_data->report_data;
3732
3733    skip_call |= parameter_validation_vkFreeCommandBuffers(report_data, commandPool, commandBufferCount, pCommandBuffers);
3734
3735    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
3736    // This is an array of handles, where the elements are allowed to be VK_NULL_HANDLE, and does not require any validation beyond
3737    // validate_array()
3738    skip_call |= validate_array(report_data, "vkFreeCommandBuffers", "commandBufferCount", "pCommandBuffers", commandBufferCount,
3739                                pCommandBuffers, true, true);
3740
3741    if (!skip_call) {
3742        get_dispatch_table(pc_device_table_map, device)
3743            ->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
3744    }
3745}
3746
3747bool PreBeginCommandBuffer(layer_data *dev_data, VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
3748    bool skip_call = false;
3749    layer_data *phy_dev_data = get_my_data_ptr(get_dispatch_key(dev_data->physical_device), layer_data_map);
3750    const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
3751
3752    if (pInfo != NULL) {
3753        if ((phy_dev_data->physical_device_features.inheritedQueries == VK_FALSE) && (pInfo->occlusionQueryEnable != VK_FALSE)) {
3754            skip_call |=
3755                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3756                        reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DEVICE_FEATURE, LayerName,
3757                        "Cannot set inherited occlusionQueryEnable in vkBeginCommandBuffer() when device does not support "
3758                        "inheritedQueries.");
3759        }
3760
3761        if ((phy_dev_data->physical_device_features.inheritedQueries != VK_FALSE) && (pInfo->occlusionQueryEnable != VK_FALSE) &&
3762            (!validate_VkQueryControlFlagBits(VkQueryControlFlagBits(pInfo->queryFlags)))) {
3763            skip_call |=
3764                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3765                        reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DEVICE_FEATURE, LayerName,
3766                        "Cannot enable in occlusion queries in vkBeginCommandBuffer() and set queryFlags to %d which is not a "
3767                        "valid combination of VkQueryControlFlagBits.",
3768                        pInfo->queryFlags);
3769        }
3770    }
3771    return skip_call;
3772}
3773
3774VKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
3775    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3776    bool skip_call = false;
3777    layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3778    assert(device_data != nullptr);
3779    debug_report_data *report_data = device_data->report_data;
3780
3781    skip_call |= parameter_validation_vkBeginCommandBuffer(report_data, pBeginInfo);
3782
3783    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
3784    // TODO: pBeginInfo->pInheritanceInfo must not be NULL if commandBuffer is a secondary command buffer
3785    skip_call |= validate_struct_type(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo",
3786                                      "VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO", pBeginInfo->pInheritanceInfo,
3787                                      VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, false);
3788
3789    if (pBeginInfo->pInheritanceInfo != NULL) {
3790        skip_call |= validate_struct_pnext(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->pNext", NULL,
3791                                           pBeginInfo->pInheritanceInfo->pNext, 0, NULL, GeneratedHeaderVersion);
3792
3793        skip_call |= validate_bool32(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->occlusionQueryEnable",
3794                                     pBeginInfo->pInheritanceInfo->occlusionQueryEnable);
3795
3796        // TODO: This only needs to be validated when the inherited queries feature is enabled
3797        // skip_call |= validate_flags(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->queryFlags",
3798        // "VkQueryControlFlagBits", AllVkQueryControlFlagBits, pBeginInfo->pInheritanceInfo->queryFlags, false);
3799
3800        // TODO: This must be 0 if the pipeline statistics queries feature is not enabled
3801        skip_call |= validate_flags(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->pipelineStatistics",
3802                                    "VkQueryPipelineStatisticFlagBits", AllVkQueryPipelineStatisticFlagBits,
3803                                    pBeginInfo->pInheritanceInfo->pipelineStatistics, false);
3804    }
3805
3806    skip_call |= PreBeginCommandBuffer(device_data, commandBuffer, pBeginInfo);
3807
3808    if (!skip_call) {
3809        result = get_dispatch_table(pc_device_table_map, commandBuffer)->BeginCommandBuffer(commandBuffer, pBeginInfo);
3810
3811        validate_result(report_data, "vkBeginCommandBuffer", result);
3812    }
3813
3814    return result;
3815}
3816
3817VKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
3818    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3819    assert(my_data != NULL);
3820
3821    VkResult result = get_dispatch_table(pc_device_table_map, commandBuffer)->EndCommandBuffer(commandBuffer);
3822
3823    validate_result(my_data->report_data, "vkEndCommandBuffer", result);
3824
3825    return result;
3826}
3827
3828VKAPI_ATTR VkResult VKAPI_CALL
3829ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
3830    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
3831    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3832    assert(my_data != NULL);
3833
3834    bool skip_call = parameter_validation_vkResetCommandBuffer(my_data->report_data, flags);
3835
3836    if (!skip_call) {
3837        result = get_dispatch_table(pc_device_table_map, commandBuffer)->ResetCommandBuffer(commandBuffer, flags);
3838
3839        validate_result(my_data->report_data, "vkResetCommandBuffer", result);
3840    }
3841
3842    return result;
3843}
3844
3845VKAPI_ATTR void VKAPI_CALL
3846CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) {
3847    bool skipCall = false;
3848    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3849    assert(my_data != NULL);
3850
3851    skipCall |= parameter_validation_vkCmdBindPipeline(my_data->report_data, pipelineBindPoint, pipeline);
3852
3853    if (!skipCall) {
3854        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
3855    }
3856}
3857
3858VKAPI_ATTR void VKAPI_CALL
3859CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) {
3860    bool skipCall = false;
3861    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3862    assert(my_data != NULL);
3863
3864    skipCall |= parameter_validation_vkCmdSetViewport(my_data->report_data, firstViewport, viewportCount, pViewports);
3865
3866    if (!skipCall) {
3867        get_dispatch_table(pc_device_table_map, commandBuffer)
3868            ->CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
3869    }
3870}
3871
3872VKAPI_ATTR void VKAPI_CALL
3873CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) {
3874    bool skipCall = false;
3875    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3876    assert(my_data != NULL);
3877
3878    skipCall |= parameter_validation_vkCmdSetScissor(my_data->report_data, firstScissor, scissorCount, pScissors);
3879
3880    if (!skipCall) {
3881        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
3882    }
3883}
3884
3885VKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
3886    get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetLineWidth(commandBuffer, lineWidth);
3887}
3888
3889VKAPI_ATTR void VKAPI_CALL
3890CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) {
3891    get_dispatch_table(pc_device_table_map, commandBuffer)
3892        ->CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
3893}
3894
3895VKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
3896    bool skipCall = false;
3897    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3898    assert(my_data != NULL);
3899
3900    skipCall |= parameter_validation_vkCmdSetBlendConstants(my_data->report_data, blendConstants);
3901
3902    if (!skipCall) {
3903        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetBlendConstants(commandBuffer, blendConstants);
3904    }
3905}
3906
3907VKAPI_ATTR void VKAPI_CALL
3908CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
3909    get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
3910}
3911
3912VKAPI_ATTR void VKAPI_CALL
3913CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) {
3914    bool skipCall = false;
3915    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3916    assert(my_data != NULL);
3917
3918    skipCall |= parameter_validation_vkCmdSetStencilCompareMask(my_data->report_data, faceMask, compareMask);
3919
3920    if (!skipCall) {
3921        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
3922    }
3923}
3924
3925VKAPI_ATTR void VKAPI_CALL
3926CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
3927    bool skipCall = false;
3928    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3929    assert(my_data != NULL);
3930
3931    skipCall |= parameter_validation_vkCmdSetStencilWriteMask(my_data->report_data, faceMask, writeMask);
3932
3933    if (!skipCall) {
3934        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
3935    }
3936}
3937
3938VKAPI_ATTR void VKAPI_CALL
3939CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
3940    bool skipCall = false;
3941    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3942    assert(my_data != NULL);
3943
3944    skipCall |= parameter_validation_vkCmdSetStencilReference(my_data->report_data, faceMask, reference);
3945
3946    if (!skipCall) {
3947        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetStencilReference(commandBuffer, faceMask, reference);
3948    }
3949}
3950
3951VKAPI_ATTR void VKAPI_CALL
3952CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout,
3953                      uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets,
3954                      uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets) {
3955    bool skipCall = false;
3956    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3957    assert(my_data != NULL);
3958
3959    skipCall |= parameter_validation_vkCmdBindDescriptorSets(my_data->report_data, pipelineBindPoint, layout, firstSet, descriptorSetCount,
3960                                                    pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
3961
3962    if (!skipCall) {
3963        get_dispatch_table(pc_device_table_map, commandBuffer)
3964            ->CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets,
3965                                    dynamicOffsetCount, pDynamicOffsets);
3966    }
3967}
3968
3969VKAPI_ATTR void VKAPI_CALL
3970CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) {
3971    bool skipCall = false;
3972    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3973    assert(my_data != NULL);
3974
3975    skipCall |= parameter_validation_vkCmdBindIndexBuffer(my_data->report_data, buffer, offset, indexType);
3976
3977    if (!skipCall) {
3978        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
3979    }
3980}
3981
3982VKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding,
3983                                                uint32_t bindingCount, const VkBuffer *pBuffers,
3984                                                const VkDeviceSize *pOffsets) {
3985    bool skipCall = false;
3986    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
3987    assert(my_data != NULL);
3988
3989    skipCall |= parameter_validation_vkCmdBindVertexBuffers(my_data->report_data, firstBinding, bindingCount, pBuffers, pOffsets);
3990
3991    if (!skipCall) {
3992        get_dispatch_table(pc_device_table_map, commandBuffer)
3993            ->CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
3994    }
3995}
3996
3997bool PreCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex,
3998                uint32_t firstInstance) {
3999    if (vertexCount == 0) {
4000        // TODO: Verify against Valid Usage section. I don't see a non-zero vertexCount listed, may need to add that and make
4001        // this an error or leave as is.
4002        log_msg(mdd(commandBuffer), VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4003                REQUIRED_PARAMETER, LayerName, "vkCmdDraw parameter, uint32_t vertexCount, is 0");
4004        return false;
4005    }
4006
4007    if (instanceCount == 0) {
4008        // TODO: Verify against Valid Usage section. I don't see a non-zero instanceCount listed, may need to add that and make
4009        // this an error or leave as is.
4010        log_msg(mdd(commandBuffer), VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4011                REQUIRED_PARAMETER, LayerName, "vkCmdDraw parameter, uint32_t instanceCount, is 0");
4012        return false;
4013    }
4014
4015    return true;
4016}
4017
4018VKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
4019                                   uint32_t firstVertex, uint32_t firstInstance) {
4020    PreCmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
4021
4022    get_dispatch_table(pc_device_table_map, commandBuffer)
4023        ->CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
4024}
4025
4026VKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount,
4027                                          uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset,
4028                                          uint32_t firstInstance) {
4029    get_dispatch_table(pc_device_table_map, commandBuffer)
4030        ->CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
4031}
4032
4033VKAPI_ATTR void VKAPI_CALL
4034CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
4035    bool skipCall = false;
4036    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4037    assert(my_data != NULL);
4038
4039    skipCall |= parameter_validation_vkCmdDrawIndirect(my_data->report_data, buffer, offset, count, stride);
4040
4041    if (!skipCall) {
4042        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
4043    }
4044}
4045
4046VKAPI_ATTR void VKAPI_CALL
4047CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
4048    bool skipCall = false;
4049    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4050    assert(my_data != NULL);
4051
4052    skipCall |= parameter_validation_vkCmdDrawIndexedIndirect(my_data->report_data, buffer, offset, count, stride);
4053
4054    if (!skipCall) {
4055        get_dispatch_table(pc_device_table_map, commandBuffer)
4056            ->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
4057    }
4058}
4059
4060VKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
4061    get_dispatch_table(pc_device_table_map, commandBuffer)->CmdDispatch(commandBuffer, x, y, z);
4062}
4063
4064VKAPI_ATTR void VKAPI_CALL
4065CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
4066    bool skipCall = false;
4067    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4068    assert(my_data != NULL);
4069
4070    skipCall |= parameter_validation_vkCmdDispatchIndirect(my_data->report_data, buffer, offset);
4071
4072    if (!skipCall) {
4073        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdDispatchIndirect(commandBuffer, buffer, offset);
4074    }
4075}
4076
4077VKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
4078                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
4079    bool skipCall = false;
4080    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4081    assert(my_data != NULL);
4082
4083    skipCall |= parameter_validation_vkCmdCopyBuffer(my_data->report_data, srcBuffer, dstBuffer, regionCount, pRegions);
4084
4085    if (!skipCall) {
4086        get_dispatch_table(pc_device_table_map, commandBuffer)
4087            ->CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
4088    }
4089}
4090
4091bool PreCmdCopyImage(VkCommandBuffer commandBuffer, const VkImageCopy *pRegions) {
4092    if (pRegions != nullptr) {
4093        if ((pRegions->srcSubresource.aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT |
4094                                                    VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
4095            log_msg(mdd(commandBuffer), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4096                    UNRECOGNIZED_VALUE, LayerName,
4097                    "vkCmdCopyImage parameter, VkImageAspect pRegions->srcSubresource.aspectMask, is an unrecognized enumerator");
4098            return false;
4099        }
4100        if ((pRegions->dstSubresource.aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT |
4101                                                    VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
4102            log_msg(mdd(commandBuffer), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4103                    UNRECOGNIZED_VALUE, LayerName,
4104                    "vkCmdCopyImage parameter, VkImageAspect pRegions->dstSubresource.aspectMask, is an unrecognized enumerator");
4105            return false;
4106        }
4107    }
4108
4109    return true;
4110}
4111
4112VKAPI_ATTR void VKAPI_CALL
4113CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
4114             VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) {
4115    bool skipCall = false;
4116    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4117    assert(my_data != NULL);
4118
4119    skipCall |=
4120        parameter_validation_vkCmdCopyImage(my_data->report_data, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
4121
4122    if (!skipCall) {
4123        PreCmdCopyImage(commandBuffer, pRegions);
4124
4125        get_dispatch_table(pc_device_table_map, commandBuffer)
4126            ->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
4127    }
4128}
4129
4130bool PreCmdBlitImage(VkCommandBuffer commandBuffer, const VkImageBlit *pRegions) {
4131    if (pRegions != nullptr) {
4132        if ((pRegions->srcSubresource.aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT |
4133                                                    VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
4134            log_msg(mdd(commandBuffer), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4135                    UNRECOGNIZED_VALUE, LayerName,
4136                    "vkCmdCopyImage parameter, VkImageAspect pRegions->srcSubresource.aspectMask, is an unrecognized enumerator");
4137            return false;
4138        }
4139        if ((pRegions->dstSubresource.aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT |
4140                                                    VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
4141            log_msg(mdd(commandBuffer), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4142                    UNRECOGNIZED_VALUE, LayerName,
4143                    "vkCmdCopyImage parameter, VkImageAspect pRegions->dstSubresource.aspectMask, is an unrecognized enumerator");
4144            return false;
4145        }
4146    }
4147
4148    return true;
4149}
4150
4151VKAPI_ATTR void VKAPI_CALL
4152CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
4153             VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) {
4154    bool skipCall = false;
4155    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4156    assert(my_data != NULL);
4157
4158    skipCall |= parameter_validation_vkCmdBlitImage(my_data->report_data, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
4159                                           pRegions, filter);
4160
4161    if (!skipCall) {
4162        PreCmdBlitImage(commandBuffer, pRegions);
4163
4164        get_dispatch_table(pc_device_table_map, commandBuffer)
4165            ->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter);
4166    }
4167}
4168
4169bool PreCmdCopyBufferToImage(VkCommandBuffer commandBuffer, const VkBufferImageCopy *pRegions) {
4170    if (pRegions != nullptr) {
4171        if ((pRegions->imageSubresource.aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT |
4172                                                      VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
4173            log_msg(mdd(commandBuffer), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4174                    UNRECOGNIZED_VALUE, LayerName,
4175                    "vkCmdCopyBufferToImage parameter, VkImageAspect pRegions->imageSubresource.aspectMask, is an unrecognized "
4176                    "enumerator");
4177            return false;
4178        }
4179    }
4180
4181    return true;
4182}
4183
4184VKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer,
4185                                                VkImage dstImage, VkImageLayout dstImageLayout,
4186                                                uint32_t regionCount, const VkBufferImageCopy *pRegions) {
4187    bool skipCall = false;
4188    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4189    assert(my_data != NULL);
4190
4191    skipCall |=
4192        parameter_validation_vkCmdCopyBufferToImage(my_data->report_data, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
4193
4194    if (!skipCall) {
4195        PreCmdCopyBufferToImage(commandBuffer, pRegions);
4196
4197        get_dispatch_table(pc_device_table_map, commandBuffer)
4198            ->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
4199    }
4200}
4201
4202bool PreCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, const VkBufferImageCopy *pRegions) {
4203    if (pRegions != nullptr) {
4204        if ((pRegions->imageSubresource.aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT |
4205                                                      VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
4206            log_msg(mdd(commandBuffer), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4207                    UNRECOGNIZED_VALUE, LayerName,
4208                    "vkCmdCopyImageToBuffer parameter, VkImageAspect pRegions->imageSubresource.aspectMask, is an unrecognized "
4209                    "enumerator");
4210            return false;
4211        }
4212    }
4213
4214    return true;
4215}
4216
4217VKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
4218                                                VkImageLayout srcImageLayout, VkBuffer dstBuffer,
4219                                                uint32_t regionCount, const VkBufferImageCopy *pRegions) {
4220    bool skipCall = false;
4221    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4222    assert(my_data != NULL);
4223
4224    skipCall |=
4225        parameter_validation_vkCmdCopyImageToBuffer(my_data->report_data, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
4226
4227    if (!skipCall) {
4228        PreCmdCopyImageToBuffer(commandBuffer, pRegions);
4229
4230        get_dispatch_table(pc_device_table_map, commandBuffer)
4231            ->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
4232    }
4233}
4234
4235VKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
4236                                           VkDeviceSize dataSize, const uint32_t *pData) {
4237    bool skip_call = false;
4238    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4239    assert(my_data != NULL);
4240
4241    skip_call |= parameter_validation_vkCmdUpdateBuffer(my_data->report_data, dstBuffer, dstOffset, dataSize, pData);
4242
4243    if (dstOffset & 3) {
4244        skip_call |= log_msg(
4245            my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__, INVALID_USAGE,
4246            LayerName, "CmdUpdateBuffer parameter, VkDeviceSize dstOffset (0x%" PRIxLEAST64 "), is not a multiple of 4", dstOffset);
4247    }
4248
4249    if ((dataSize <= 0) || (dataSize > 65536)) {
4250        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
4251                             INVALID_USAGE, LayerName, "CmdUpdateBuffer parameter, VkDeviceSize dataSize (0x%" PRIxLEAST64
4252                                                       "), must be greater than zero and less than or equal to 65536",
4253                             dataSize);
4254    } else if (dataSize & 3) {
4255        skip_call |= log_msg(
4256            my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__, INVALID_USAGE,
4257            LayerName, "CmdUpdateBuffer parameter, VkDeviceSize dataSize (0x%" PRIxLEAST64 "), is not a multiple of 4", dataSize);
4258    }
4259
4260    if (!skip_call) {
4261        get_dispatch_table(pc_device_table_map, commandBuffer)
4262            ->CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
4263    }
4264}
4265
4266VKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
4267                                         VkDeviceSize size, uint32_t data) {
4268    bool skip_call = false;
4269    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4270    assert(my_data != NULL);
4271
4272    skip_call |= parameter_validation_vkCmdFillBuffer(my_data->report_data, dstBuffer, dstOffset, size, data);
4273
4274    if (dstOffset & 3) {
4275        skip_call |= log_msg(
4276            my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__, INVALID_USAGE,
4277            LayerName, "vkCmdFillBuffer parameter, VkDeviceSize dstOffset (0x%" PRIxLEAST64 "), is not a multiple of 4", dstOffset);
4278    }
4279
4280    if (size != VK_WHOLE_SIZE) {
4281        if (size <= 0) {
4282            skip_call |= log_msg(
4283                my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__, INVALID_USAGE,
4284                LayerName, "vkCmdFillBuffer parameter, VkDeviceSize size (0x%" PRIxLEAST64 "), must be greater than zero", size);
4285        } else if (size & 3) {
4286            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
4287                                 INVALID_USAGE, LayerName,
4288                                 "vkCmdFillBuffer parameter, VkDeviceSize size (0x%" PRIxLEAST64 "), is not a multiple of 4", size);
4289        }
4290    }
4291
4292    if (!skip_call) {
4293        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
4294    }
4295}
4296
4297VKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image,
4298                                              VkImageLayout imageLayout, const VkClearColorValue *pColor,
4299                                              uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
4300    bool skipCall = false;
4301    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4302    assert(my_data != NULL);
4303
4304    skipCall |= parameter_validation_vkCmdClearColorImage(my_data->report_data, image, imageLayout, pColor, rangeCount, pRanges);
4305
4306    if (!skipCall) {
4307        get_dispatch_table(pc_device_table_map, commandBuffer)
4308            ->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
4309    }
4310}
4311
4312VKAPI_ATTR void VKAPI_CALL
4313CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
4314                          const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
4315                          const VkImageSubresourceRange *pRanges) {
4316    bool skipCall = false;
4317    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4318    assert(my_data != NULL);
4319
4320    skipCall |=
4321        parameter_validation_vkCmdClearDepthStencilImage(my_data->report_data, image, imageLayout, pDepthStencil, rangeCount, pRanges);
4322
4323    if (!skipCall) {
4324        get_dispatch_table(pc_device_table_map, commandBuffer)
4325            ->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
4326    }
4327}
4328
4329VKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
4330                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
4331                                               const VkClearRect *pRects) {
4332    bool skipCall = false;
4333    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4334    assert(my_data != NULL);
4335
4336    skipCall |= parameter_validation_vkCmdClearAttachments(my_data->report_data, attachmentCount, pAttachments, rectCount, pRects);
4337
4338    if (!skipCall) {
4339        get_dispatch_table(pc_device_table_map, commandBuffer)
4340            ->CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
4341    }
4342}
4343
4344bool PreCmdResolveImage(VkCommandBuffer commandBuffer, const VkImageResolve *pRegions) {
4345    if (pRegions != nullptr) {
4346        if ((pRegions->srcSubresource.aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT |
4347                                                    VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
4348            log_msg(
4349                mdd(commandBuffer), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4350                UNRECOGNIZED_VALUE, LayerName,
4351                "vkCmdResolveImage parameter, VkImageAspect pRegions->srcSubresource.aspectMask, is an unrecognized enumerator");
4352            return false;
4353        }
4354        if ((pRegions->dstSubresource.aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT |
4355                                                    VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT)) == 0) {
4356            log_msg(
4357                mdd(commandBuffer), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4358                UNRECOGNIZED_VALUE, LayerName,
4359                "vkCmdResolveImage parameter, VkImageAspect pRegions->dstSubresource.aspectMask, is an unrecognized enumerator");
4360            return false;
4361        }
4362    }
4363
4364    return true;
4365}
4366
4367VKAPI_ATTR void VKAPI_CALL
4368CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
4369                VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) {
4370    bool skipCall = false;
4371    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4372    assert(my_data != NULL);
4373
4374    skipCall |= parameter_validation_vkCmdResolveImage(my_data->report_data, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
4375                                              pRegions);
4376
4377    if (!skipCall) {
4378        PreCmdResolveImage(commandBuffer, pRegions);
4379
4380        get_dispatch_table(pc_device_table_map, commandBuffer)
4381            ->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
4382    }
4383}
4384
4385VKAPI_ATTR void VKAPI_CALL
4386CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
4387    bool skipCall = false;
4388    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4389    assert(my_data != NULL);
4390
4391    skipCall |= parameter_validation_vkCmdSetEvent(my_data->report_data, event, stageMask);
4392
4393    if (!skipCall) {
4394        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetEvent(commandBuffer, event, stageMask);
4395    }
4396}
4397
4398VKAPI_ATTR void VKAPI_CALL
4399CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
4400    bool skipCall = false;
4401    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4402    assert(my_data != NULL);
4403
4404    skipCall |= parameter_validation_vkCmdResetEvent(my_data->report_data, event, stageMask);
4405
4406    if (!skipCall) {
4407        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdResetEvent(commandBuffer, event, stageMask);
4408    }
4409}
4410
4411VKAPI_ATTR void VKAPI_CALL
4412CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags srcStageMask,
4413              VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
4414              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
4415              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
4416    bool skipCall = false;
4417    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4418    assert(my_data != NULL);
4419
4420    skipCall |= parameter_validation_vkCmdWaitEvents(my_data->report_data, eventCount, pEvents, srcStageMask, dstStageMask,
4421                                            memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
4422                                            imageMemoryBarrierCount, pImageMemoryBarriers);
4423
4424    if (!skipCall) {
4425        get_dispatch_table(pc_device_table_map, commandBuffer)
4426            ->CmdWaitEvents(commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers,
4427                            bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
4428    }
4429}
4430
4431VKAPI_ATTR void VKAPI_CALL
4432CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
4433                   VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
4434                   uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
4435                   uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
4436    bool skipCall = false;
4437    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4438    assert(my_data != NULL);
4439
4440    skipCall |= parameter_validation_vkCmdPipelineBarrier(my_data->report_data, srcStageMask, dstStageMask, dependencyFlags,
4441                                                 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
4442                                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
4443
4444    if (!skipCall) {
4445        get_dispatch_table(pc_device_table_map, commandBuffer)
4446            ->CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers,
4447                                 bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
4448    }
4449}
4450
4451VKAPI_ATTR void VKAPI_CALL
4452CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkQueryControlFlags flags) {
4453    bool skipCall = false;
4454    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4455    assert(my_data != NULL);
4456
4457    skipCall |= parameter_validation_vkCmdBeginQuery(my_data->report_data, queryPool, slot, flags);
4458
4459    if (!skipCall) {
4460        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdBeginQuery(commandBuffer, queryPool, slot, flags);
4461    }
4462}
4463
4464VKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
4465    bool skipCall = false;
4466    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4467    assert(my_data != NULL);
4468
4469    skipCall |= parameter_validation_vkCmdEndQuery(my_data->report_data, queryPool, slot);
4470
4471    if (!skipCall) {
4472        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdEndQuery(commandBuffer, queryPool, slot);
4473    }
4474}
4475
4476VKAPI_ATTR void VKAPI_CALL
4477CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
4478    bool skipCall = false;
4479    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4480    assert(my_data != NULL);
4481
4482    skipCall |= parameter_validation_vkCmdResetQueryPool(my_data->report_data, queryPool, firstQuery, queryCount);
4483
4484    if (!skipCall) {
4485        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
4486    }
4487}
4488
4489bool PostCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool,
4490                           uint32_t slot) {
4491
4492    ValidateEnumerator(pipelineStage);
4493
4494    return true;
4495}
4496
4497VKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
4498                                             VkQueryPool queryPool, uint32_t query) {
4499    bool skipCall = false;
4500    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4501    assert(my_data != NULL);
4502
4503    skipCall |= parameter_validation_vkCmdWriteTimestamp(my_data->report_data, pipelineStage, queryPool, query);
4504
4505    if (!skipCall) {
4506        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, query);
4507
4508        PostCmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, query);
4509    }
4510}
4511
4512VKAPI_ATTR void VKAPI_CALL
4513CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
4514                        VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) {
4515    bool skipCall = false;
4516    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4517    assert(my_data != NULL);
4518
4519    skipCall |= parameter_validation_vkCmdCopyQueryPoolResults(my_data->report_data, queryPool, firstQuery, queryCount, dstBuffer,
4520                                                               dstOffset, stride, flags);
4521
4522    if (!skipCall) {
4523        get_dispatch_table(pc_device_table_map, commandBuffer)
4524            ->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride, flags);
4525    }
4526}
4527
4528VKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout,
4529                                            VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size,
4530                                            const void *pValues) {
4531    bool skipCall = false;
4532    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4533    assert(my_data != NULL);
4534
4535    skipCall |= parameter_validation_vkCmdPushConstants(my_data->report_data, layout, stageFlags, offset, size, pValues);
4536
4537    if (!skipCall) {
4538        get_dispatch_table(pc_device_table_map, commandBuffer)
4539            ->CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
4540    }
4541}
4542
4543VKAPI_ATTR void VKAPI_CALL
4544CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) {
4545    bool skipCall = false;
4546    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4547    assert(my_data != NULL);
4548
4549    skipCall |= parameter_validation_vkCmdBeginRenderPass(my_data->report_data, pRenderPassBegin, contents);
4550
4551    if (!skipCall) {
4552        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
4553    }
4554}
4555
4556VKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
4557    bool skipCall = false;
4558    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4559    assert(my_data != NULL);
4560
4561    skipCall |= parameter_validation_vkCmdNextSubpass(my_data->report_data, contents);
4562
4563    if (!skipCall) {
4564        get_dispatch_table(pc_device_table_map, commandBuffer)->CmdNextSubpass(commandBuffer, contents);
4565    }
4566}
4567
4568VKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
4569    get_dispatch_table(pc_device_table_map, commandBuffer)->CmdEndRenderPass(commandBuffer);
4570}
4571
4572VKAPI_ATTR void VKAPI_CALL
4573CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) {
4574    bool skipCall = false;
4575    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
4576    assert(my_data != NULL);
4577
4578    skipCall |= parameter_validation_vkCmdExecuteCommands(my_data->report_data, commandBufferCount, pCommandBuffers);
4579
4580    if (!skipCall) {
4581        get_dispatch_table(pc_device_table_map, commandBuffer)
4582            ->CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers);
4583    }
4584}
4585
4586VKAPI_ATTR VkResult VKAPI_CALL
4587EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
4588    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
4589}
4590
4591VKAPI_ATTR VkResult VKAPI_CALL
4592EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) {
4593    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
4594}
4595
4596VKAPI_ATTR VkResult VKAPI_CALL
4597EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) {
4598    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
4599        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
4600
4601    return VK_ERROR_LAYER_NOT_PRESENT;
4602}
4603
4604VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
4605                                                                  const char *pLayerName, uint32_t *pCount,
4606                                                                  VkExtensionProperties *pProperties) {
4607    /* parameter_validation does not have any physical device extensions */
4608    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
4609        return util_GetExtensionProperties(0, NULL, pCount, pProperties);
4610
4611    assert(physicalDevice);
4612
4613    return get_dispatch_table(pc_instance_table_map, physicalDevice)
4614        ->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
4615}
4616
4617static PFN_vkVoidFunction
4618intercept_core_instance_command(const char *name);
4619
4620static PFN_vkVoidFunction
4621intercept_core_device_command(const char *name);
4622
4623VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
4624    assert(device);
4625
4626    layer_data *data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
4627
4628    if (validate_string(data->report_data, "vkGetDeviceProcAddr", "funcName", funcName)) {
4629        return NULL;
4630    }
4631
4632    PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
4633    if (proc)
4634        return proc;
4635
4636    if (get_dispatch_table(pc_device_table_map, device)->GetDeviceProcAddr == NULL)
4637        return NULL;
4638    return get_dispatch_table(pc_device_table_map, device)->GetDeviceProcAddr(device, funcName);
4639}
4640
4641VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
4642    PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
4643    if (!proc)
4644        proc = intercept_core_device_command(funcName);
4645    if (proc)
4646        return proc;
4647
4648    assert(instance);
4649
4650    layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
4651
4652    proc = debug_report_get_instance_proc_addr(data->report_data, funcName);
4653    if (proc)
4654        return proc;
4655
4656    if (get_dispatch_table(pc_instance_table_map, instance)->GetInstanceProcAddr == NULL)
4657        return NULL;
4658    return get_dispatch_table(pc_instance_table_map, instance)->GetInstanceProcAddr(instance, funcName);
4659}
4660
4661static PFN_vkVoidFunction
4662intercept_core_instance_command(const char *name) {
4663    static const struct {
4664        const char *name;
4665        PFN_vkVoidFunction proc;
4666    } core_instance_commands[] = {
4667        { "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) },
4668        { "vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance) },
4669        { "vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance) },
4670        { "vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice) },
4671        { "vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices) },
4672        { "vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProperties) },
4673        { "vkGetPhysicalDeviceFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceFeatures) },
4674        { "vkGetPhysicalDeviceFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceFormatProperties) },
4675        { "vkGetPhysicalDeviceImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceImageFormatProperties) },
4676        { "vkGetPhysicalDeviceSparseImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSparseImageFormatProperties) },
4677        { "vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties) },
4678        { "vkGetPhysicalDeviceMemoryProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceMemoryProperties) },
4679        { "vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties) },
4680        { "vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties) },
4681        { "vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties) },
4682        { "vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties) },
4683    };
4684
4685    for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
4686        if (!strcmp(core_instance_commands[i].name, name))
4687            return core_instance_commands[i].proc;
4688    }
4689
4690    return nullptr;
4691}
4692
4693static PFN_vkVoidFunction
4694intercept_core_device_command(const char *name) {
4695    static const struct {
4696        const char *name;
4697        PFN_vkVoidFunction proc;
4698    } core_device_commands[] = {
4699        { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
4700        { "vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice) },
4701        { "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) },
4702        { "vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit) },
4703        { "vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(QueueWaitIdle) },
4704        { "vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(DeviceWaitIdle) },
4705        { "vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory) },
4706        { "vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory) },
4707        { "vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory) },
4708        { "vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory) },
4709        { "vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges) },
4710        { "vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges) },
4711        { "vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryCommitment) },
4712        { "vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory) },
4713        { "vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory) },
4714        { "vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence) },
4715        { "vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence) },
4716        { "vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences) },
4717        { "vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus) },
4718        { "vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences) },
4719        { "vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore) },
4720        { "vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore) },
4721        { "vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent) },
4722        { "vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent) },
4723        { "vkGetEventStatus", reinterpret_cast<PFN_vkVoidFunction>(GetEventStatus) },
4724        { "vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent) },
4725        { "vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(ResetEvent) },
4726        { "vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool) },
4727        { "vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool) },
4728        { "vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults) },
4729        { "vkCreateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateBuffer) },
4730        { "vkDestroyBuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyBuffer) },
4731        { "vkCreateBufferView", reinterpret_cast<PFN_vkVoidFunction>(CreateBufferView) },
4732        { "vkDestroyBufferView", reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferView) },
4733        { "vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage) },
4734        { "vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage) },
4735        { "vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) },
4736        { "vkCreateImageView", reinterpret_cast<PFN_vkVoidFunction>(CreateImageView) },
4737        { "vkDestroyImageView", reinterpret_cast<PFN_vkVoidFunction>(DestroyImageView) },
4738        { "vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule) },
4739        { "vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule) },
4740        { "vkCreatePipelineCache", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineCache) },
4741        { "vkDestroyPipelineCache", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineCache) },
4742        { "vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData) },
4743        { "vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(MergePipelineCaches) },
4744        { "vkCreateGraphicsPipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateGraphicsPipelines) },
4745        { "vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines) },
4746        { "vkDestroyPipeline", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipeline) },
4747        { "vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout) },
4748        { "vkDestroyPipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineLayout) },
4749        { "vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler) },
4750        { "vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler) },
4751        { "vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout) },
4752        { "vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout) },
4753        { "vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool) },
4754        { "vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool) },
4755        { "vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool) },
4756        { "vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets) },
4757        { "vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets) },
4758        { "vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets) },
4759        { "vkCmdSetViewport", reinterpret_cast<PFN_vkVoidFunction>(CmdSetViewport) },
4760        { "vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor) },
4761        { "vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth) },
4762        { "vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias) },
4763        { "vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants) },
4764        { "vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds) },
4765        { "vkCmdSetStencilCompareMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilCompareMask) },
4766        { "vkCmdSetStencilWriteMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilWriteMask) },
4767        { "vkCmdSetStencilReference", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilReference) },
4768        { "vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers) },
4769        { "vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers) },
4770        { "vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer) },
4771        { "vkEndCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(EndCommandBuffer) },
4772        { "vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandBuffer) },
4773        { "vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline) },
4774        { "vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets) },
4775        { "vkCmdBindVertexBuffers", reinterpret_cast<PFN_vkVoidFunction>(CmdBindVertexBuffers) },
4776        { "vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer) },
4777        { "vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw) },
4778        { "vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed) },
4779        { "vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect) },
4780        { "vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect) },
4781        { "vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch) },
4782        { "vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect) },
4783        { "vkCmdCopyBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBuffer) },
4784        { "vkCmdCopyImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImage) },
4785        { "vkCmdBlitImage", reinterpret_cast<PFN_vkVoidFunction>(CmdBlitImage) },
4786        { "vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage) },
4787        { "vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer) },
4788        { "vkCmdUpdateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdUpdateBuffer) },
4789        { "vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer) },
4790        { "vkCmdClearColorImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearColorImage) },
4791        { "vkCmdResolveImage", reinterpret_cast<PFN_vkVoidFunction>(CmdResolveImage) },
4792        { "vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent) },
4793        { "vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent) },
4794        { "vkCmdWaitEvents", reinterpret_cast<PFN_vkVoidFunction>(CmdWaitEvents) },
4795        { "vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier) },
4796        { "vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery) },
4797        { "vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery) },
4798        { "vkCmdResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CmdResetQueryPool) },
4799        { "vkCmdWriteTimestamp", reinterpret_cast<PFN_vkVoidFunction>(CmdWriteTimestamp) },
4800        { "vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults) },
4801        { "vkCreateFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateFramebuffer) },
4802        { "vkDestroyFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyFramebuffer) },
4803        { "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) },
4804        { "vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass) },
4805        { "vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(GetRenderAreaGranularity) },
4806        { "vkCreateCommandPool", reinterpret_cast<PFN_vkVoidFunction>(CreateCommandPool) },
4807        { "vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool) },
4808        { "vkResetCommandPool", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandPool) },
4809        { "vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass) },
4810        { "vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass) },
4811    };
4812
4813    for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
4814        if (!strcmp(core_device_commands[i].name, name))
4815            return core_device_commands[i].proc;
4816    }
4817
4818    return nullptr;
4819}
4820
4821} // namespace parameter_validation
4822
4823// vk_layer_logging.h expects these to be defined
4824
4825VKAPI_ATTR VkResult VKAPI_CALL
4826vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
4827                               const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
4828    return parameter_validation::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
4829}
4830
4831VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance,
4832                                                                           VkDebugReportCallbackEXT msgCallback,
4833                                                                           const VkAllocationCallbacks *pAllocator) {
4834    parameter_validation::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
4835}
4836
4837VKAPI_ATTR void VKAPI_CALL
4838vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
4839                        size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
4840    parameter_validation::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
4841}
4842
4843// loader-layer interface v0
4844
4845VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
4846vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) {
4847    return parameter_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
4848}
4849
4850VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
4851vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
4852    return parameter_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
4853}
4854
4855VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
4856vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) {
4857    // the layer command handles VK_NULL_HANDLE just fine internally
4858    assert(physicalDevice == VK_NULL_HANDLE);
4859    return parameter_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
4860}
4861
4862VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
4863                                                                                    const char *pLayerName, uint32_t *pCount,
4864                                                                                    VkExtensionProperties *pProperties) {
4865    // the layer command handles VK_NULL_HANDLE just fine internally
4866    assert(physicalDevice == VK_NULL_HANDLE);
4867    return parameter_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
4868}
4869
4870VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
4871    return parameter_validation::GetDeviceProcAddr(dev, funcName);
4872}
4873
4874VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
4875    return parameter_validation::GetInstanceProcAddr(instance, funcName);
4876}
4877