Home | History | Annotate | Download | only in layers
      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  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and/or associated documentation files (the "Materials"), to
      8  * deal in the Materials without restriction, including without limitation the
      9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     10  * sell copies of the Materials, and to permit persons to whom the Materials
     11  * are furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice(s) and this permission notice shall be included
     14  * in all copies or substantial portions of the Materials.
     15  *
     16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     19  *
     20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     23  * USE OR OTHER DEALINGS IN THE MATERIALS
     24  *
     25  * Author: Cody Northrop <cnorthrop (at) google.com>
     26  * Author: Michael Lentine <mlentine (at) google.com>
     27  * Author: Tobin Ehlis <tobine (at) google.com>
     28  * Author: Chia-I Wu <olv (at) google.com>
     29  * Author: Chris Forbes <chrisf (at) ijw.co.nz>
     30  * Author: Mark Lobodzinski <mark (at) lunarg.com>
     31  * Author: Ian Elliott <ianelliott (at) google.com>
     32  */
     33 
     34 // Allow use of STL min and max functions in Windows
     35 #define NOMINMAX
     36 
     37 // Turn on mem_tracker merged code
     38 #define MTMERGESOURCE 1
     39 
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <assert.h>
     44 #include <unordered_map>
     45 #include <unordered_set>
     46 #include <map>
     47 #include <string>
     48 #include <iostream>
     49 #include <algorithm>
     50 #include <list>
     51 #include <SPIRV/spirv.hpp>
     52 #include <set>
     53 
     54 #include "vk_loader_platform.h"
     55 #include "vk_dispatch_table_helper.h"
     56 #include "vk_struct_string_helper_cpp.h"
     57 #if defined(__GNUC__)
     58 #pragma GCC diagnostic ignored "-Wwrite-strings"
     59 #endif
     60 #if defined(__GNUC__)
     61 #pragma GCC diagnostic warning "-Wwrite-strings"
     62 #endif
     63 #include "vk_struct_size_helper.h"
     64 #include "core_validation.h"
     65 #include "vk_layer_config.h"
     66 #include "vk_layer_table.h"
     67 #include "vk_layer_data.h"
     68 #include "vk_layer_logging.h"
     69 #include "vk_layer_extension_utils.h"
     70 #include "vk_layer_utils.h"
     71 
     72 #if defined __ANDROID__
     73 #include <android/log.h>
     74 #define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__))
     75 #else
     76 #define LOGCONSOLE(...) printf(__VA_ARGS__)
     77 #endif
     78 
     79 using std::unordered_map;
     80 using std::unordered_set;
     81 
     82 #if MTMERGESOURCE
     83 // WSI Image Objects bypass usual Image Object creation methods.  A special Memory
     84 // Object value will be used to identify them internally.
     85 static const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
     86 #endif
     87 // Track command pools and their command buffers
     88 struct CMD_POOL_INFO {
     89     VkCommandPoolCreateFlags createFlags;
     90     uint32_t queueFamilyIndex;
     91     list<VkCommandBuffer> commandBuffers; // list container of cmd buffers allocated from this pool
     92 };
     93 
     94 struct devExts {
     95     VkBool32 wsi_enabled;
     96     unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> swapchainMap;
     97     unordered_map<VkImage, VkSwapchainKHR> imageToSwapchainMap;
     98 };
     99 
    100 // fwd decls
    101 struct shader_module;
    102 struct render_pass;
    103 
    104 struct layer_data {
    105     debug_report_data *report_data;
    106     std::vector<VkDebugReportCallbackEXT> logging_callback;
    107     VkLayerDispatchTable *device_dispatch_table;
    108     VkLayerInstanceDispatchTable *instance_dispatch_table;
    109 #if MTMERGESOURCE
    110 // MTMERGESOURCE - stuff pulled directly from MT
    111     uint64_t currentFenceId;
    112     // Maps for tracking key structs related to mem_tracker state
    113     unordered_map<VkDescriptorSet, MT_DESCRIPTOR_SET_INFO> descriptorSetMap;
    114     // Images and Buffers are 2 objects that can have memory bound to them so they get special treatment
    115     unordered_map<uint64_t, MT_OBJ_BINDING_INFO> imageBindingMap;
    116     unordered_map<uint64_t, MT_OBJ_BINDING_INFO> bufferBindingMap;
    117 // MTMERGESOURCE - End of MT stuff
    118 #endif
    119     devExts device_extensions;
    120     vector<VkQueue> queues; // all queues under given device
    121     // Global set of all cmdBuffers that are inFlight on this device
    122     unordered_set<VkCommandBuffer> globalInFlightCmdBuffers;
    123     // Layer specific data
    124     unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> sampleMap;
    125     unordered_map<VkImageView, VkImageViewCreateInfo> imageViewMap;
    126     unordered_map<VkImage, IMAGE_NODE> imageMap;
    127     unordered_map<VkBufferView, VkBufferViewCreateInfo> bufferViewMap;
    128     unordered_map<VkBuffer, BUFFER_NODE> bufferMap;
    129     unordered_map<VkPipeline, PIPELINE_NODE *> pipelineMap;
    130     unordered_map<VkCommandPool, CMD_POOL_INFO> commandPoolMap;
    131     unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_NODE *> descriptorPoolMap;
    132     unordered_map<VkDescriptorSet, SET_NODE *> setMap;
    133     unordered_map<VkDescriptorSetLayout, LAYOUT_NODE *> descriptorSetLayoutMap;
    134     unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
    135     unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> memObjMap;
    136     unordered_map<VkFence, FENCE_NODE> fenceMap;
    137     unordered_map<VkQueue, QUEUE_NODE> queueMap;
    138     unordered_map<VkEvent, EVENT_NODE> eventMap;
    139     unordered_map<QueryObject, bool> queryToStateMap;
    140     unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
    141     unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
    142     unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
    143     unordered_map<VkFramebuffer, FRAMEBUFFER_NODE> frameBufferMap;
    144     unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
    145     unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
    146     unordered_map<VkRenderPass, RENDER_PASS_NODE *> renderPassMap;
    147     unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
    148     // Current render pass
    149     VkRenderPassBeginInfo renderPassBeginInfo;
    150     uint32_t currentSubpass;
    151 
    152     // Device specific data
    153     PHYS_DEV_PROPERTIES_NODE physDevProperties;
    154 // MTMERGESOURCE - added a couple of fields to constructor initializer
    155     layer_data()
    156         : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr),
    157 #if MTMERGESOURCE
    158         currentFenceId(1),
    159 #endif
    160         device_extensions(){};
    161 };
    162 
    163 static const VkLayerProperties cv_global_layers[] = {{
    164     "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
    165 }};
    166 
    167 template <class TCreateInfo> void ValidateLayerOrdering(const TCreateInfo &createInfo) {
    168     bool foundLayer = false;
    169     for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
    170         if (!strcmp(createInfo.ppEnabledLayerNames[i], cv_global_layers[0].layerName)) {
    171             foundLayer = true;
    172         }
    173         // This has to be logged to console as we don't have a callback at this point.
    174         if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
    175             LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.",
    176                        cv_global_layers[0].layerName);
    177         }
    178     }
    179 }
    180 
    181 // Code imported from shader_checker
    182 static void build_def_index(shader_module *);
    183 
    184 // A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
    185 // without the caller needing to care too much about the physical SPIRV module layout.
    186 struct spirv_inst_iter {
    187     std::vector<uint32_t>::const_iterator zero;
    188     std::vector<uint32_t>::const_iterator it;
    189 
    190     uint32_t len() { return *it >> 16; }
    191     uint32_t opcode() { return *it & 0x0ffffu; }
    192     uint32_t const &word(unsigned n) { return it[n]; }
    193     uint32_t offset() { return (uint32_t)(it - zero); }
    194 
    195     spirv_inst_iter() {}
    196 
    197     spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
    198 
    199     bool operator==(spirv_inst_iter const &other) { return it == other.it; }
    200 
    201     bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
    202 
    203     spirv_inst_iter operator++(int) { /* x++ */
    204         spirv_inst_iter ii = *this;
    205         it += len();
    206         return ii;
    207     }
    208 
    209     spirv_inst_iter operator++() { /* ++x; */
    210         it += len();
    211         return *this;
    212     }
    213 
    214     /* The iterator and the value are the same thing. */
    215     spirv_inst_iter &operator*() { return *this; }
    216     spirv_inst_iter const &operator*() const { return *this; }
    217 };
    218 
    219 struct shader_module {
    220     /* the spirv image itself */
    221     vector<uint32_t> words;
    222     /* a mapping of <id> to the first word of its def. this is useful because walking type
    223      * trees, constant expressions, etc requires jumping all over the instruction stream.
    224      */
    225     unordered_map<unsigned, unsigned> def_index;
    226 
    227     shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
    228         : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
    229           def_index() {
    230 
    231         build_def_index(this);
    232     }
    233 
    234     /* expose begin() / end() to enable range-based for */
    235     spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); } /* first insn */
    236     spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }         /* just past last insn */
    237     /* given an offset into the module, produce an iterator there. */
    238     spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
    239 
    240     /* gets an iterator to the definition of an id */
    241     spirv_inst_iter get_def(unsigned id) const {
    242         auto it = def_index.find(id);
    243         if (it == def_index.end()) {
    244             return end();
    245         }
    246         return at(it->second);
    247     }
    248 };
    249 
    250 // TODO : Do we need to guard access to layer_data_map w/ lock?
    251 static unordered_map<void *, layer_data *> layer_data_map;
    252 
    253 // TODO : This can be much smarter, using separate locks for separate global data
    254 static int globalLockInitialized = 0;
    255 static loader_platform_thread_mutex globalLock;
    256 #define MAX_TID 513
    257 static loader_platform_thread_id g_tidMapping[MAX_TID] = {0};
    258 static uint32_t g_maxTID = 0;
    259 #if MTMERGESOURCE
    260 // MTMERGESOURCE - start of direct pull
    261 static VkPhysicalDeviceMemoryProperties memProps;
    262 
    263 static void clear_cmd_buf_and_mem_references(layer_data *my_data, const VkCommandBuffer cb);
    264 
    265 #define MAX_BINDING 0xFFFFFFFF
    266 
    267 static MT_OBJ_BINDING_INFO *get_object_binding_info(layer_data *my_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
    268     MT_OBJ_BINDING_INFO *retValue = NULL;
    269     switch (type) {
    270     case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
    271         auto it = my_data->imageBindingMap.find(handle);
    272         if (it != my_data->imageBindingMap.end())
    273             return &(*it).second;
    274         break;
    275     }
    276     case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
    277         auto it = my_data->bufferBindingMap.find(handle);
    278         if (it != my_data->bufferBindingMap.end())
    279             return &(*it).second;
    280         break;
    281     }
    282     default:
    283         break;
    284     }
    285     return retValue;
    286 }
    287 // MTMERGESOURCE - end section
    288 #endif
    289 template layer_data *get_my_data_ptr<layer_data>(void *data_key, std::unordered_map<void *, layer_data *> &data_map);
    290 
    291 // prototype
    292 static GLOBAL_CB_NODE *getCBNode(layer_data *, const VkCommandBuffer);
    293 
    294 #if MTMERGESOURCE
    295 static void delete_queue_info_list(layer_data *my_data) {
    296     // Process queue list, cleaning up each entry before deleting
    297     my_data->queueMap.clear();
    298 }
    299 
    300 // Delete CBInfo from container and clear mem references to CB
    301 static void delete_cmd_buf_info(layer_data *my_data, VkCommandPool commandPool, const VkCommandBuffer cb) {
    302     clear_cmd_buf_and_mem_references(my_data, cb);
    303     // Delete the CBInfo info
    304     my_data->commandPoolMap[commandPool].commandBuffers.remove(cb);
    305     my_data->commandBufferMap.erase(cb);
    306 }
    307 
    308 static void add_object_binding_info(layer_data *my_data, const uint64_t handle, const VkDebugReportObjectTypeEXT type,
    309                                     const VkDeviceMemory mem) {
    310     switch (type) {
    311     // Buffers and images are unique as their CreateInfo is in container struct
    312     case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
    313         auto pCI = &my_data->bufferBindingMap[handle];
    314         pCI->mem = mem;
    315         break;
    316     }
    317     case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
    318         auto pCI = &my_data->imageBindingMap[handle];
    319         pCI->mem = mem;
    320         break;
    321     }
    322     default:
    323         break;
    324     }
    325 }
    326 
    327 static void add_object_create_info(layer_data *my_data, const uint64_t handle, const VkDebugReportObjectTypeEXT type,
    328                                    const void *pCreateInfo) {
    329     // TODO : For any CreateInfo struct that has ptrs, need to deep copy them and appropriately clean up on Destroy
    330     switch (type) {
    331     // Buffers and images are unique as their CreateInfo is in container struct
    332     case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
    333         auto pCI = &my_data->bufferBindingMap[handle];
    334         memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO));
    335         memcpy(&pCI->create_info.buffer, pCreateInfo, sizeof(VkBufferCreateInfo));
    336         break;
    337     }
    338     case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
    339         auto pCI = &my_data->imageBindingMap[handle];
    340         memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO));
    341         memcpy(&pCI->create_info.image, pCreateInfo, sizeof(VkImageCreateInfo));
    342         break;
    343     }
    344     // Swap Chain is very unique, use my_data->imageBindingMap, but copy in
    345     // SwapChainCreatInfo's usage flags and set the mem value to a unique key. These is used by
    346     // vkCreateImageView and internal mem_tracker routines to distinguish swap chain images
    347     case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: {
    348         auto pCI = &my_data->imageBindingMap[handle];
    349         memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO));
    350         pCI->mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
    351         pCI->valid = false;
    352         pCI->create_info.image.usage =
    353             const_cast<VkSwapchainCreateInfoKHR *>(static_cast<const VkSwapchainCreateInfoKHR *>(pCreateInfo))->imageUsage;
    354         break;
    355     }
    356     default:
    357         break;
    358     }
    359 }
    360 
    361 // Add a fence, creating one if necessary to our list of fences/fenceIds
    362 static VkBool32 add_fence_info(layer_data *my_data, VkFence fence, VkQueue queue, uint64_t *fenceId) {
    363     VkBool32 skipCall = VK_FALSE;
    364     *fenceId = my_data->currentFenceId++;
    365 
    366     // If no fence, create an internal fence to track the submissions
    367     if (fence != VK_NULL_HANDLE) {
    368         my_data->fenceMap[fence].fenceId = *fenceId;
    369         my_data->fenceMap[fence].queue = queue;
    370         // Validate that fence is in UNSIGNALED state
    371         VkFenceCreateInfo *pFenceCI = &(my_data->fenceMap[fence].createInfo);
    372         if (pFenceCI->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
    373             skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
    374                                (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
    375                                "Fence %#" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
    376                                (uint64_t)fence);
    377         }
    378     } else {
    379         // TODO : Do we need to create an internal fence here for tracking purposes?
    380     }
    381     // Update most recently submitted fence and fenceId for Queue
    382     my_data->queueMap[queue].lastSubmittedId = *fenceId;
    383     return skipCall;
    384 }
    385 
    386 // Remove a fenceInfo from our list of fences/fenceIds
    387 static void delete_fence_info(layer_data *my_data, VkFence fence) { my_data->fenceMap.erase(fence); }
    388 
    389 // Record information when a fence is known to be signalled
    390 static void update_fence_tracking(layer_data *my_data, VkFence fence) {
    391     auto fence_item = my_data->fenceMap.find(fence);
    392     if (fence_item != my_data->fenceMap.end()) {
    393         FENCE_NODE *pCurFenceInfo = &(*fence_item).second;
    394         VkQueue queue = pCurFenceInfo->queue;
    395         auto queue_item = my_data->queueMap.find(queue);
    396         if (queue_item != my_data->queueMap.end()) {
    397             QUEUE_NODE *pQueueInfo = &(*queue_item).second;
    398             if (pQueueInfo->lastRetiredId < pCurFenceInfo->fenceId) {
    399                 pQueueInfo->lastRetiredId = pCurFenceInfo->fenceId;
    400             }
    401         }
    402     }
    403 
    404     // Update fence state in fenceCreateInfo structure
    405     auto pFCI = &(my_data->fenceMap[fence].createInfo);
    406     pFCI->flags = static_cast<VkFenceCreateFlags>(pFCI->flags | VK_FENCE_CREATE_SIGNALED_BIT);
    407 }
    408 
    409 // Helper routine that updates the fence list for a specific queue to all-retired
    410 static void retire_queue_fences(layer_data *my_data, VkQueue queue) {
    411     QUEUE_NODE *pQueueInfo = &my_data->queueMap[queue];
    412     // Set queue's lastRetired to lastSubmitted indicating all fences completed
    413     pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId;
    414 }
    415 
    416 // Helper routine that updates all queues to all-retired
    417 static void retire_device_fences(layer_data *my_data, VkDevice device) {
    418     // Process each queue for device
    419     // TODO: Add multiple device support
    420     for (auto ii = my_data->queueMap.begin(); ii != my_data->queueMap.end(); ++ii) {
    421         // Set queue's lastRetired to lastSubmitted indicating all fences completed
    422         QUEUE_NODE *pQueueInfo = &(*ii).second;
    423         pQueueInfo->lastRetiredId = pQueueInfo->lastSubmittedId;
    424     }
    425 }
    426 
    427 // Helper function to validate correct usage bits set for buffers or images
    428 //  Verify that (actual & desired) flags != 0 or,
    429 //   if strict is true, verify that (actual & desired) flags == desired
    430 //  In case of error, report it via dbg callbacks
    431 static VkBool32 validate_usage_flags(layer_data *my_data, void *disp_obj, VkFlags actual, VkFlags desired, VkBool32 strict,
    432                                      uint64_t obj_handle, VkDebugReportObjectTypeEXT obj_type, char const *ty_str,
    433                                      char const *func_name, char const *usage_str) {
    434     VkBool32 correct_usage = VK_FALSE;
    435     VkBool32 skipCall = VK_FALSE;
    436     if (strict)
    437         correct_usage = ((actual & desired) == desired);
    438     else
    439         correct_usage = ((actual & desired) != 0);
    440     if (!correct_usage) {
    441         skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_type, obj_handle, __LINE__,
    442                            MEMTRACK_INVALID_USAGE_FLAG, "MEM", "Invalid usage flag for %s %#" PRIxLEAST64
    443                                                                " used by %s. In this case, %s should have %s set during creation.",
    444                            ty_str, obj_handle, func_name, ty_str, usage_str);
    445     }
    446     return skipCall;
    447 }
    448 
    449 // Helper function to validate usage flags for images
    450 // Pulls image info and then sends actual vs. desired usage off to helper above where
    451 //  an error will be flagged if usage is not correct
    452 static VkBool32 validate_image_usage_flags(layer_data *my_data, void *disp_obj, VkImage image, VkFlags desired, VkBool32 strict,
    453                                            char const *func_name, char const *usage_string) {
    454     VkBool32 skipCall = VK_FALSE;
    455     MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
    456     if (pBindInfo) {
    457         skipCall = validate_usage_flags(my_data, disp_obj, pBindInfo->create_info.image.usage, desired, strict, (uint64_t)image,
    458                                         VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "image", func_name, usage_string);
    459     }
    460     return skipCall;
    461 }
    462 
    463 // Helper function to validate usage flags for buffers
    464 // Pulls buffer info and then sends actual vs. desired usage off to helper above where
    465 //  an error will be flagged if usage is not correct
    466 static VkBool32 validate_buffer_usage_flags(layer_data *my_data, void *disp_obj, VkBuffer buffer, VkFlags desired, VkBool32 strict,
    467                                             char const *func_name, char const *usage_string) {
    468     VkBool32 skipCall = VK_FALSE;
    469     MT_OBJ_BINDING_INFO *pBindInfo = get_object_binding_info(my_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT);
    470     if (pBindInfo) {
    471         skipCall = validate_usage_flags(my_data, disp_obj, pBindInfo->create_info.buffer.usage, desired, strict, (uint64_t)buffer,
    472                                         VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "buffer", func_name, usage_string);
    473     }
    474     return skipCall;
    475 }
    476 
    477 // Return ptr to info in map container containing mem, or NULL if not found
    478 //  Calls to this function should be wrapped in mutex
    479 static DEVICE_MEM_INFO *get_mem_obj_info(layer_data *dev_data, const VkDeviceMemory mem) {
    480     auto item = dev_data->memObjMap.find(mem);
    481     if (item != dev_data->memObjMap.end()) {
    482         return &(*item).second;
    483     } else {
    484         return NULL;
    485     }
    486 }
    487 
    488 static void add_mem_obj_info(layer_data *my_data, void *object, const VkDeviceMemory mem,
    489                              const VkMemoryAllocateInfo *pAllocateInfo) {
    490     assert(object != NULL);
    491 
    492     memcpy(&my_data->memObjMap[mem].allocInfo, pAllocateInfo, sizeof(VkMemoryAllocateInfo));
    493     // TODO:  Update for real hardware, actually process allocation info structures
    494     my_data->memObjMap[mem].allocInfo.pNext = NULL;
    495     my_data->memObjMap[mem].object = object;
    496     my_data->memObjMap[mem].refCount = 0;
    497     my_data->memObjMap[mem].mem = mem;
    498     my_data->memObjMap[mem].image = VK_NULL_HANDLE;
    499     my_data->memObjMap[mem].memRange.offset = 0;
    500     my_data->memObjMap[mem].memRange.size = 0;
    501     my_data->memObjMap[mem].pData = 0;
    502     my_data->memObjMap[mem].pDriverData = 0;
    503     my_data->memObjMap[mem].valid = false;
    504 }
    505 
    506 static VkBool32 validate_memory_is_valid(layer_data *dev_data, VkDeviceMemory mem, const char *functionName,
    507                                          VkImage image = VK_NULL_HANDLE) {
    508     if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
    509         MT_OBJ_BINDING_INFO *pBindInfo =
    510             get_object_binding_info(dev_data, reinterpret_cast<const uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
    511         if (pBindInfo && !pBindInfo->valid) {
    512             return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
    513                            (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM",
    514                            "%s: Cannot read invalid swapchain image %" PRIx64 ", please fill the memory before using.",
    515                            functionName, (uint64_t)(image));
    516         }
    517     } else {
    518         DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
    519         if (pMemObj && !pMemObj->valid) {
    520             return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
    521                            (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM",
    522                            "%s: Cannot read invalid memory %" PRIx64 ", please fill the memory before using.", functionName,
    523                            (uint64_t)(mem));
    524         }
    525     }
    526     return false;
    527 }
    528 
    529 static void set_memory_valid(layer_data *dev_data, VkDeviceMemory mem, bool valid, VkImage image = VK_NULL_HANDLE) {
    530     if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
    531         MT_OBJ_BINDING_INFO *pBindInfo =
    532             get_object_binding_info(dev_data, reinterpret_cast<const uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
    533         if (pBindInfo) {
    534             pBindInfo->valid = valid;
    535         }
    536     } else {
    537         DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
    538         if (pMemObj) {
    539             pMemObj->valid = valid;
    540         }
    541     }
    542 }
    543 
    544 // Find CB Info and add mem reference to list container
    545 // Find Mem Obj Info and add CB reference to list container
    546 static VkBool32 update_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb, const VkDeviceMemory mem,
    547                                                   const char *apiName) {
    548     VkBool32 skipCall = VK_FALSE;
    549 
    550     // Skip validation if this image was created through WSI
    551     if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
    552 
    553         // First update CB binding in MemObj mini CB list
    554         DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem);
    555         if (pMemInfo) {
    556             // Search for cmd buffer object in memory object's binding list
    557             VkBool32 found = VK_FALSE;
    558             if (pMemInfo->pCommandBufferBindings.size() > 0) {
    559                 for (list<VkCommandBuffer>::iterator it = pMemInfo->pCommandBufferBindings.begin();
    560                      it != pMemInfo->pCommandBufferBindings.end(); ++it) {
    561                     if ((*it) == cb) {
    562                         found = VK_TRUE;
    563                         break;
    564                     }
    565                 }
    566             }
    567             // If not present, add to list
    568             if (found == VK_FALSE) {
    569                 pMemInfo->pCommandBufferBindings.push_front(cb);
    570                 pMemInfo->refCount++;
    571             }
    572             // Now update CBInfo's Mem reference list
    573             GLOBAL_CB_NODE *pCBNode = getCBNode(dev_data, cb);
    574             // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object
    575             if (pCBNode) {
    576                 // Search for memory object in cmd buffer's reference list
    577                 VkBool32 found = VK_FALSE;
    578                 if (pCBNode->pMemObjList.size() > 0) {
    579                     for (auto it = pCBNode->pMemObjList.begin(); it != pCBNode->pMemObjList.end(); ++it) {
    580                         if ((*it) == mem) {
    581                             found = VK_TRUE;
    582                             break;
    583                         }
    584                     }
    585                 }
    586                 // If not present, add to list
    587                 if (found == VK_FALSE) {
    588                     pCBNode->pMemObjList.push_front(mem);
    589                 }
    590             }
    591         }
    592     }
    593     return skipCall;
    594 }
    595 
    596 // Free bindings related to CB
    597 static void clear_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb) {
    598     GLOBAL_CB_NODE *pCBNode = getCBNode(dev_data, cb);
    599 
    600     if (pCBNode) {
    601         if (pCBNode->pMemObjList.size() > 0) {
    602             list<VkDeviceMemory> mem_obj_list = pCBNode->pMemObjList;
    603             for (list<VkDeviceMemory>::iterator it = mem_obj_list.begin(); it != mem_obj_list.end(); ++it) {
    604                 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, *it);
    605                 if (pInfo) {
    606                     pInfo->pCommandBufferBindings.remove(cb);
    607                     pInfo->refCount--;
    608                 }
    609             }
    610             pCBNode->pMemObjList.clear();
    611         }
    612         pCBNode->activeDescriptorSets.clear();
    613         pCBNode->validate_functions.clear();
    614     }
    615 }
    616 
    617 // Delete the entire CB list
    618 static void delete_cmd_buf_info_list(layer_data *my_data) {
    619     for (auto &cb_node : my_data->commandBufferMap) {
    620         clear_cmd_buf_and_mem_references(my_data, cb_node.first);
    621     }
    622     my_data->commandBufferMap.clear();
    623 }
    624 
    625 // For given MemObjInfo, report Obj & CB bindings
    626 static VkBool32 reportMemReferencesAndCleanUp(layer_data *dev_data, DEVICE_MEM_INFO *pMemObjInfo) {
    627     VkBool32 skipCall = VK_FALSE;
    628     size_t cmdBufRefCount = pMemObjInfo->pCommandBufferBindings.size();
    629     size_t objRefCount = pMemObjInfo->pObjBindings.size();
    630 
    631     if ((pMemObjInfo->pCommandBufferBindings.size()) != 0) {
    632         skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
    633                            (uint64_t)pMemObjInfo->mem, __LINE__, MEMTRACK_FREED_MEM_REF, "MEM",
    634                            "Attempting to free memory object %#" PRIxLEAST64 " which still contains " PRINTF_SIZE_T_SPECIFIER
    635                            " references",
    636                            (uint64_t)pMemObjInfo->mem, (cmdBufRefCount + objRefCount));
    637     }
    638 
    639     if (cmdBufRefCount > 0 && pMemObjInfo->pCommandBufferBindings.size() > 0) {
    640         for (list<VkCommandBuffer>::const_iterator it = pMemObjInfo->pCommandBufferBindings.begin();
    641              it != pMemObjInfo->pCommandBufferBindings.end(); ++it) {
    642             // TODO : CommandBuffer should be source Obj here
    643             log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    644                     (uint64_t)(*it), __LINE__, MEMTRACK_FREED_MEM_REF, "MEM",
    645                     "Command Buffer %p still has a reference to mem obj %#" PRIxLEAST64, (*it), (uint64_t)pMemObjInfo->mem);
    646         }
    647         // Clear the list of hanging references
    648         pMemObjInfo->pCommandBufferBindings.clear();
    649     }
    650 
    651     if (objRefCount > 0 && pMemObjInfo->pObjBindings.size() > 0) {
    652         for (auto it = pMemObjInfo->pObjBindings.begin(); it != pMemObjInfo->pObjBindings.end(); ++it) {
    653             log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, it->type, it->handle, __LINE__,
    654                     MEMTRACK_FREED_MEM_REF, "MEM", "VK Object %#" PRIxLEAST64 " still has a reference to mem obj %#" PRIxLEAST64,
    655                     it->handle, (uint64_t)pMemObjInfo->mem);
    656         }
    657         // Clear the list of hanging references
    658         pMemObjInfo->pObjBindings.clear();
    659     }
    660     return skipCall;
    661 }
    662 
    663 static VkBool32 deleteMemObjInfo(layer_data *my_data, void *object, VkDeviceMemory mem) {
    664     VkBool32 skipCall = VK_FALSE;
    665     auto item = my_data->memObjMap.find(mem);
    666     if (item != my_data->memObjMap.end()) {
    667         my_data->memObjMap.erase(item);
    668     } else {
    669         skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
    670                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM",
    671                            "Request to delete memory object %#" PRIxLEAST64 " not present in memory Object Map", (uint64_t)mem);
    672     }
    673     return skipCall;
    674 }
    675 
    676 // Check if fence for given CB is completed
    677 static bool checkCBCompleted(layer_data *my_data, const VkCommandBuffer cb, bool *complete) {
    678     GLOBAL_CB_NODE *pCBNode = getCBNode(my_data, cb);
    679     VkBool32 skipCall = false;
    680     *complete = true;
    681 
    682     if (pCBNode) {
    683         if (pCBNode->lastSubmittedQueue != NULL) {
    684             VkQueue queue = pCBNode->lastSubmittedQueue;
    685             QUEUE_NODE *pQueueInfo = &my_data->queueMap[queue];
    686             if (pCBNode->fenceId > pQueueInfo->lastRetiredId) {
    687                 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
    688                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)cb, __LINE__, MEMTRACK_NONE, "MEM",
    689                                    "fence %#" PRIxLEAST64 " for CB %p has not been checked for completion",
    690                                    (uint64_t)pCBNode->lastSubmittedFence, cb);
    691                 *complete = false;
    692             }
    693         }
    694     }
    695     return skipCall;
    696 }
    697 
    698 static VkBool32 freeMemObjInfo(layer_data *dev_data, void *object, VkDeviceMemory mem, VkBool32 internal) {
    699     VkBool32 skipCall = VK_FALSE;
    700     // Parse global list to find info w/ mem
    701     DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem);
    702     if (pInfo) {
    703         if (pInfo->allocInfo.allocationSize == 0 && !internal) {
    704             // TODO: Verify against Valid Use section
    705             skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
    706                                (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM",
    707                                "Attempting to free memory associated with a Persistent Image, %#" PRIxLEAST64 ", "
    708                                "this should not be explicitly freed\n",
    709                                (uint64_t)mem);
    710         } else {
    711             // Clear any CB bindings for completed CBs
    712             //   TODO : Is there a better place to do this?
    713 
    714             bool commandBufferComplete = false;
    715             assert(pInfo->object != VK_NULL_HANDLE);
    716             list<VkCommandBuffer>::iterator it = pInfo->pCommandBufferBindings.begin();
    717             list<VkCommandBuffer>::iterator temp;
    718             while (pInfo->pCommandBufferBindings.size() > 0 && it != pInfo->pCommandBufferBindings.end()) {
    719                 skipCall |= checkCBCompleted(dev_data, *it, &commandBufferComplete);
    720                 if (commandBufferComplete) {
    721                     temp = it;
    722                     ++temp;
    723                     clear_cmd_buf_and_mem_references(dev_data, *it);
    724                     it = temp;
    725                 } else {
    726                     ++it;
    727                 }
    728             }
    729 
    730             // Now verify that no references to this mem obj remain and remove bindings
    731             if (0 != pInfo->refCount) {
    732                 skipCall |= reportMemReferencesAndCleanUp(dev_data, pInfo);
    733             }
    734             // Delete mem obj info
    735             skipCall |= deleteMemObjInfo(dev_data, object, mem);
    736         }
    737     }
    738     return skipCall;
    739 }
    740 
    741 static const char *object_type_to_string(VkDebugReportObjectTypeEXT type) {
    742     switch (type) {
    743     case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
    744         return "image";
    745         break;
    746     case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
    747         return "buffer";
    748         break;
    749     case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:
    750         return "swapchain";
    751         break;
    752     default:
    753         return "unknown";
    754     }
    755 }
    756 
    757 // Remove object binding performs 3 tasks:
    758 // 1. Remove ObjectInfo from MemObjInfo list container of obj bindings & free it
    759 // 2. Decrement refCount for MemObjInfo
    760 // 3. Clear mem binding for image/buffer by setting its handle to 0
    761 // TODO : This only applied to Buffer, Image, and Swapchain objects now, how should it be updated/customized?
    762 static VkBool32 clear_object_binding(layer_data *dev_data, void *dispObj, uint64_t handle, VkDebugReportObjectTypeEXT type) {
    763     // TODO : Need to customize images/buffers/swapchains to track mem binding and clear it here appropriately
    764     VkBool32 skipCall = VK_FALSE;
    765     MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type);
    766     if (pObjBindInfo) {
    767         DEVICE_MEM_INFO *pMemObjInfo = get_mem_obj_info(dev_data, pObjBindInfo->mem);
    768         // TODO : Make sure this is a reasonable way to reset mem binding
    769         pObjBindInfo->mem = VK_NULL_HANDLE;
    770         if (pMemObjInfo) {
    771             // This obj is bound to a memory object. Remove the reference to this object in that memory object's list, decrement the
    772             // memObj's refcount
    773             // and set the objects memory binding pointer to NULL.
    774             VkBool32 clearSucceeded = VK_FALSE;
    775             for (auto it = pMemObjInfo->pObjBindings.begin(); it != pMemObjInfo->pObjBindings.end(); ++it) {
    776                 if ((it->handle == handle) && (it->type == type)) {
    777                     pMemObjInfo->refCount--;
    778                     pMemObjInfo->pObjBindings.erase(it);
    779                     clearSucceeded = VK_TRUE;
    780                     break;
    781                 }
    782             }
    783             if (VK_FALSE == clearSucceeded) {
    784                 skipCall |=
    785                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT,
    786                             "MEM", "While trying to clear mem binding for %s obj %#" PRIxLEAST64
    787                                    ", unable to find that object referenced by mem obj %#" PRIxLEAST64,
    788                             object_type_to_string(type), handle, (uint64_t)pMemObjInfo->mem);
    789             }
    790         }
    791     }
    792     return skipCall;
    793 }
    794 
    795 // For NULL mem case, output warning
    796 // Make sure given object is in global object map
    797 //  IF a previous binding existed, output validation error
    798 //  Otherwise, add reference from objectInfo to memoryInfo
    799 //  Add reference off of objInfo
    800 //  device is required for error logging, need a dispatchable
    801 //  object for that.
    802 static VkBool32 set_mem_binding(layer_data *dev_data, void *dispatch_object, VkDeviceMemory mem, uint64_t handle,
    803                                 VkDebugReportObjectTypeEXT type, const char *apiName) {
    804     VkBool32 skipCall = VK_FALSE;
    805     // Handle NULL case separately, just clear previous binding & decrement reference
    806     if (mem == VK_NULL_HANDLE) {
    807         // TODO: Verify against Valid Use section of spec.
    808         skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_MEM_OBJ,
    809                            "MEM", "In %s, attempting to Bind Obj(%#" PRIxLEAST64 ") to NULL", apiName, handle);
    810     } else {
    811         MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type);
    812         if (!pObjBindInfo) {
    813             skipCall |=
    814                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS,
    815                         "MEM", "In %s, attempting to update Binding of %s Obj(%#" PRIxLEAST64 ") that's not in global list()",
    816                         object_type_to_string(type), apiName, handle);
    817         } else {
    818             // non-null case so should have real mem obj
    819             DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem);
    820             if (pMemInfo) {
    821                 // TODO : Need to track mem binding for obj and report conflict here
    822                 DEVICE_MEM_INFO *pPrevBinding = get_mem_obj_info(dev_data, pObjBindInfo->mem);
    823                 if (pPrevBinding != NULL) {
    824                     skipCall |=
    825                         log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
    826                                 (uint64_t)mem, __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
    827                                 "In %s, attempting to bind memory (%#" PRIxLEAST64 ") to object (%#" PRIxLEAST64
    828                                 ") which has already been bound to mem object %#" PRIxLEAST64,
    829                                 apiName, (uint64_t)mem, handle, (uint64_t)pPrevBinding->mem);
    830                 } else {
    831                     MT_OBJ_HANDLE_TYPE oht;
    832                     oht.handle = handle;
    833                     oht.type = type;
    834                     pMemInfo->pObjBindings.push_front(oht);
    835                     pMemInfo->refCount++;
    836                     // For image objects, make sure default memory state is correctly set
    837                     // TODO : What's the best/correct way to handle this?
    838                     if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) {
    839                         VkImageCreateInfo ici = pObjBindInfo->create_info.image;
    840                         if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
    841                             // TODO::  More memory state transition stuff.
    842                         }
    843                     }
    844                     pObjBindInfo->mem = mem;
    845                 }
    846             }
    847         }
    848     }
    849     return skipCall;
    850 }
    851 
    852 // For NULL mem case, clear any previous binding Else...
    853 // Make sure given object is in its object map
    854 //  IF a previous binding existed, update binding
    855 //  Add reference from objectInfo to memoryInfo
    856 //  Add reference off of object's binding info
    857 // Return VK_TRUE if addition is successful, VK_FALSE otherwise
    858 static VkBool32 set_sparse_mem_binding(layer_data *dev_data, void *dispObject, VkDeviceMemory mem, uint64_t handle,
    859                                        VkDebugReportObjectTypeEXT type, const char *apiName) {
    860     VkBool32 skipCall = VK_FALSE;
    861     // Handle NULL case separately, just clear previous binding & decrement reference
    862     if (mem == VK_NULL_HANDLE) {
    863         skipCall = clear_object_binding(dev_data, dispObject, handle, type);
    864     } else {
    865         MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(dev_data, handle, type);
    866         if (!pObjBindInfo) {
    867             skipCall |= log_msg(
    868                 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, "MEM",
    869                 "In %s, attempting to update Binding of Obj(%#" PRIxLEAST64 ") that's not in global list()", apiName, handle);
    870         }
    871         // non-null case so should have real mem obj
    872         DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem);
    873         if (pInfo) {
    874             // Search for object in memory object's binding list
    875             VkBool32 found = VK_FALSE;
    876             if (pInfo->pObjBindings.size() > 0) {
    877                 for (auto it = pInfo->pObjBindings.begin(); it != pInfo->pObjBindings.end(); ++it) {
    878                     if (((*it).handle == handle) && ((*it).type == type)) {
    879                         found = VK_TRUE;
    880                         break;
    881                     }
    882                 }
    883             }
    884             // If not present, add to list
    885             if (found == VK_FALSE) {
    886                 MT_OBJ_HANDLE_TYPE oht;
    887                 oht.handle = handle;
    888                 oht.type = type;
    889                 pInfo->pObjBindings.push_front(oht);
    890                 pInfo->refCount++;
    891             }
    892             // Need to set mem binding for this object
    893             pObjBindInfo->mem = mem;
    894         }
    895     }
    896     return skipCall;
    897 }
    898 
    899 template <typename T>
    900 void print_object_map_members(layer_data *my_data, void *dispObj, T const &objectName, VkDebugReportObjectTypeEXT objectType,
    901                               const char *objectStr) {
    902     for (auto const &element : objectName) {
    903         log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objectType, 0, __LINE__, MEMTRACK_NONE, "MEM",
    904                 "    %s Object list contains %s Object %#" PRIxLEAST64 " ", objectStr, objectStr, element.first);
    905     }
    906 }
    907 
    908 // For given Object, get 'mem' obj that it's bound to or NULL if no binding
    909 static VkBool32 get_mem_binding_from_object(layer_data *my_data, void *dispObj, const uint64_t handle,
    910                                             const VkDebugReportObjectTypeEXT type, VkDeviceMemory *mem) {
    911     VkBool32 skipCall = VK_FALSE;
    912     *mem = VK_NULL_HANDLE;
    913     MT_OBJ_BINDING_INFO *pObjBindInfo = get_object_binding_info(my_data, handle, type);
    914     if (pObjBindInfo) {
    915         if (pObjBindInfo->mem) {
    916             *mem = pObjBindInfo->mem;
    917         } else {
    918             skipCall =
    919                 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS,
    920                         "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but object has no mem binding", handle);
    921         }
    922     } else {
    923         skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT,
    924                            "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but no such object in %s list", handle,
    925                            object_type_to_string(type));
    926     }
    927     return skipCall;
    928 }
    929 
    930 // Print details of MemObjInfo list
    931 static void print_mem_list(layer_data *dev_data, void *dispObj) {
    932     DEVICE_MEM_INFO *pInfo = NULL;
    933 
    934     // Early out if info is not requested
    935     if (!(dev_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
    936         return;
    937     }
    938 
    939     // Just printing each msg individually for now, may want to package these into single large print
    940     log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
    941             MEMTRACK_NONE, "MEM", "Details of Memory Object list (of size " PRINTF_SIZE_T_SPECIFIER " elements)",
    942             dev_data->memObjMap.size());
    943     log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
    944             MEMTRACK_NONE, "MEM", "=============================");
    945 
    946     if (dev_data->memObjMap.size() <= 0)
    947         return;
    948 
    949     for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) {
    950         pInfo = &(*ii).second;
    951 
    952         log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
    953                 __LINE__, MEMTRACK_NONE, "MEM", "    ===MemObjInfo at %p===", (void *)pInfo);
    954         log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
    955                 __LINE__, MEMTRACK_NONE, "MEM", "    Mem object: %#" PRIxLEAST64, (uint64_t)(pInfo->mem));
    956         log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
    957                 __LINE__, MEMTRACK_NONE, "MEM", "    Ref Count: %u", pInfo->refCount);
    958         if (0 != pInfo->allocInfo.allocationSize) {
    959             string pAllocInfoMsg = vk_print_vkmemoryallocateinfo(&pInfo->allocInfo, "MEM(INFO):         ");
    960             log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
    961                     __LINE__, MEMTRACK_NONE, "MEM", "    Mem Alloc info:\n%s", pAllocInfoMsg.c_str());
    962         } else {
    963             log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
    964                     __LINE__, MEMTRACK_NONE, "MEM", "    Mem Alloc info is NULL (alloc done by vkCreateSwapchainKHR())");
    965         }
    966 
    967         log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
    968                 __LINE__, MEMTRACK_NONE, "MEM", "    VK OBJECT Binding list of size " PRINTF_SIZE_T_SPECIFIER " elements:",
    969                 pInfo->pObjBindings.size());
    970         if (pInfo->pObjBindings.size() > 0) {
    971             for (list<MT_OBJ_HANDLE_TYPE>::iterator it = pInfo->pObjBindings.begin(); it != pInfo->pObjBindings.end(); ++it) {
    972                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
    973                         0, __LINE__, MEMTRACK_NONE, "MEM", "       VK OBJECT %" PRIu64, it->handle);
    974             }
    975         }
    976 
    977         log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
    978                 __LINE__, MEMTRACK_NONE, "MEM",
    979                 "    VK Command Buffer (CB) binding list of size " PRINTF_SIZE_T_SPECIFIER " elements",
    980                 pInfo->pCommandBufferBindings.size());
    981         if (pInfo->pCommandBufferBindings.size() > 0) {
    982             for (list<VkCommandBuffer>::iterator it = pInfo->pCommandBufferBindings.begin();
    983                  it != pInfo->pCommandBufferBindings.end(); ++it) {
    984                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
    985                         0, __LINE__, MEMTRACK_NONE, "MEM", "      VK CB %p", (*it));
    986             }
    987         }
    988     }
    989 }
    990 
    991 static void printCBList(layer_data *my_data, void *dispObj) {
    992     GLOBAL_CB_NODE *pCBInfo = NULL;
    993 
    994     // Early out if info is not requested
    995     if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
    996         return;
    997     }
    998 
    999     log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
   1000             MEMTRACK_NONE, "MEM", "Details of CB list (of size " PRINTF_SIZE_T_SPECIFIER " elements)",
   1001             my_data->commandBufferMap.size());
   1002     log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
   1003             MEMTRACK_NONE, "MEM", "==================");
   1004 
   1005     if (my_data->commandBufferMap.size() <= 0)
   1006         return;
   1007 
   1008     for (auto &cb_node : my_data->commandBufferMap) {
   1009         pCBInfo = cb_node.second;
   1010 
   1011         log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
   1012                 __LINE__, MEMTRACK_NONE, "MEM", "    CB Info (%p) has CB %p, fenceId %" PRIx64 ", and fence %#" PRIxLEAST64,
   1013                 (void *)pCBInfo, (void *)pCBInfo->commandBuffer, pCBInfo->fenceId, (uint64_t)pCBInfo->lastSubmittedFence);
   1014 
   1015         if (pCBInfo->pMemObjList.size() <= 0)
   1016             continue;
   1017         for (list<VkDeviceMemory>::iterator it = pCBInfo->pMemObjList.begin(); it != pCBInfo->pMemObjList.end(); ++it) {
   1018             log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
   1019                     __LINE__, MEMTRACK_NONE, "MEM", "      Mem obj %" PRIu64, (uint64_t)(*it));
   1020         }
   1021     }
   1022 }
   1023 
   1024 #endif
   1025 
   1026 // Map actual TID to an index value and return that index
   1027 //  This keeps TIDs in range from 0-MAX_TID and simplifies compares between runs
   1028 static uint32_t getTIDIndex() {
   1029     loader_platform_thread_id tid = loader_platform_get_thread_id();
   1030     for (uint32_t i = 0; i < g_maxTID; i++) {
   1031         if (tid == g_tidMapping[i])
   1032             return i;
   1033     }
   1034     // Don't yet have mapping, set it and return newly set index
   1035     uint32_t retVal = (uint32_t)g_maxTID;
   1036     g_tidMapping[g_maxTID++] = tid;
   1037     assert(g_maxTID < MAX_TID);
   1038     return retVal;
   1039 }
   1040 
   1041 // Return a string representation of CMD_TYPE enum
   1042 static string cmdTypeToString(CMD_TYPE cmd) {
   1043     switch (cmd) {
   1044     case CMD_BINDPIPELINE:
   1045         return "CMD_BINDPIPELINE";
   1046     case CMD_BINDPIPELINEDELTA:
   1047         return "CMD_BINDPIPELINEDELTA";
   1048     case CMD_SETVIEWPORTSTATE:
   1049         return "CMD_SETVIEWPORTSTATE";
   1050     case CMD_SETLINEWIDTHSTATE:
   1051         return "CMD_SETLINEWIDTHSTATE";
   1052     case CMD_SETDEPTHBIASSTATE:
   1053         return "CMD_SETDEPTHBIASSTATE";
   1054     case CMD_SETBLENDSTATE:
   1055         return "CMD_SETBLENDSTATE";
   1056     case CMD_SETDEPTHBOUNDSSTATE:
   1057         return "CMD_SETDEPTHBOUNDSSTATE";
   1058     case CMD_SETSTENCILREADMASKSTATE:
   1059         return "CMD_SETSTENCILREADMASKSTATE";
   1060     case CMD_SETSTENCILWRITEMASKSTATE:
   1061         return "CMD_SETSTENCILWRITEMASKSTATE";
   1062     case CMD_SETSTENCILREFERENCESTATE:
   1063         return "CMD_SETSTENCILREFERENCESTATE";
   1064     case CMD_BINDDESCRIPTORSETS:
   1065         return "CMD_BINDDESCRIPTORSETS";
   1066     case CMD_BINDINDEXBUFFER:
   1067         return "CMD_BINDINDEXBUFFER";
   1068     case CMD_BINDVERTEXBUFFER:
   1069         return "CMD_BINDVERTEXBUFFER";
   1070     case CMD_DRAW:
   1071         return "CMD_DRAW";
   1072     case CMD_DRAWINDEXED:
   1073         return "CMD_DRAWINDEXED";
   1074     case CMD_DRAWINDIRECT:
   1075         return "CMD_DRAWINDIRECT";
   1076     case CMD_DRAWINDEXEDINDIRECT:
   1077         return "CMD_DRAWINDEXEDINDIRECT";
   1078     case CMD_DISPATCH:
   1079         return "CMD_DISPATCH";
   1080     case CMD_DISPATCHINDIRECT:
   1081         return "CMD_DISPATCHINDIRECT";
   1082     case CMD_COPYBUFFER:
   1083         return "CMD_COPYBUFFER";
   1084     case CMD_COPYIMAGE:
   1085         return "CMD_COPYIMAGE";
   1086     case CMD_BLITIMAGE:
   1087         return "CMD_BLITIMAGE";
   1088     case CMD_COPYBUFFERTOIMAGE:
   1089         return "CMD_COPYBUFFERTOIMAGE";
   1090     case CMD_COPYIMAGETOBUFFER:
   1091         return "CMD_COPYIMAGETOBUFFER";
   1092     case CMD_CLONEIMAGEDATA:
   1093         return "CMD_CLONEIMAGEDATA";
   1094     case CMD_UPDATEBUFFER:
   1095         return "CMD_UPDATEBUFFER";
   1096     case CMD_FILLBUFFER:
   1097         return "CMD_FILLBUFFER";
   1098     case CMD_CLEARCOLORIMAGE:
   1099         return "CMD_CLEARCOLORIMAGE";
   1100     case CMD_CLEARATTACHMENTS:
   1101         return "CMD_CLEARCOLORATTACHMENT";
   1102     case CMD_CLEARDEPTHSTENCILIMAGE:
   1103         return "CMD_CLEARDEPTHSTENCILIMAGE";
   1104     case CMD_RESOLVEIMAGE:
   1105         return "CMD_RESOLVEIMAGE";
   1106     case CMD_SETEVENT:
   1107         return "CMD_SETEVENT";
   1108     case CMD_RESETEVENT:
   1109         return "CMD_RESETEVENT";
   1110     case CMD_WAITEVENTS:
   1111         return "CMD_WAITEVENTS";
   1112     case CMD_PIPELINEBARRIER:
   1113         return "CMD_PIPELINEBARRIER";
   1114     case CMD_BEGINQUERY:
   1115         return "CMD_BEGINQUERY";
   1116     case CMD_ENDQUERY:
   1117         return "CMD_ENDQUERY";
   1118     case CMD_RESETQUERYPOOL:
   1119         return "CMD_RESETQUERYPOOL";
   1120     case CMD_COPYQUERYPOOLRESULTS:
   1121         return "CMD_COPYQUERYPOOLRESULTS";
   1122     case CMD_WRITETIMESTAMP:
   1123         return "CMD_WRITETIMESTAMP";
   1124     case CMD_INITATOMICCOUNTERS:
   1125         return "CMD_INITATOMICCOUNTERS";
   1126     case CMD_LOADATOMICCOUNTERS:
   1127         return "CMD_LOADATOMICCOUNTERS";
   1128     case CMD_SAVEATOMICCOUNTERS:
   1129         return "CMD_SAVEATOMICCOUNTERS";
   1130     case CMD_BEGINRENDERPASS:
   1131         return "CMD_BEGINRENDERPASS";
   1132     case CMD_ENDRENDERPASS:
   1133         return "CMD_ENDRENDERPASS";
   1134     default:
   1135         return "UNKNOWN";
   1136     }
   1137 }
   1138 
   1139 // SPIRV utility functions
   1140 static void build_def_index(shader_module *module) {
   1141     for (auto insn : *module) {
   1142         switch (insn.opcode()) {
   1143         /* Types */
   1144         case spv::OpTypeVoid:
   1145         case spv::OpTypeBool:
   1146         case spv::OpTypeInt:
   1147         case spv::OpTypeFloat:
   1148         case spv::OpTypeVector:
   1149         case spv::OpTypeMatrix:
   1150         case spv::OpTypeImage:
   1151         case spv::OpTypeSampler:
   1152         case spv::OpTypeSampledImage:
   1153         case spv::OpTypeArray:
   1154         case spv::OpTypeRuntimeArray:
   1155         case spv::OpTypeStruct:
   1156         case spv::OpTypeOpaque:
   1157         case spv::OpTypePointer:
   1158         case spv::OpTypeFunction:
   1159         case spv::OpTypeEvent:
   1160         case spv::OpTypeDeviceEvent:
   1161         case spv::OpTypeReserveId:
   1162         case spv::OpTypeQueue:
   1163         case spv::OpTypePipe:
   1164             module->def_index[insn.word(1)] = insn.offset();
   1165             break;
   1166 
   1167         /* Fixed constants */
   1168         case spv::OpConstantTrue:
   1169         case spv::OpConstantFalse:
   1170         case spv::OpConstant:
   1171         case spv::OpConstantComposite:
   1172         case spv::OpConstantSampler:
   1173         case spv::OpConstantNull:
   1174             module->def_index[insn.word(2)] = insn.offset();
   1175             break;
   1176 
   1177         /* Specialization constants */
   1178         case spv::OpSpecConstantTrue:
   1179         case spv::OpSpecConstantFalse:
   1180         case spv::OpSpecConstant:
   1181         case spv::OpSpecConstantComposite:
   1182         case spv::OpSpecConstantOp:
   1183             module->def_index[insn.word(2)] = insn.offset();
   1184             break;
   1185 
   1186         /* Variables */
   1187         case spv::OpVariable:
   1188             module->def_index[insn.word(2)] = insn.offset();
   1189             break;
   1190 
   1191         /* Functions */
   1192         case spv::OpFunction:
   1193             module->def_index[insn.word(2)] = insn.offset();
   1194             break;
   1195 
   1196         default:
   1197             /* We don't care about any other defs for now. */
   1198             break;
   1199         }
   1200     }
   1201 }
   1202 
   1203 static spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
   1204     for (auto insn : *src) {
   1205         if (insn.opcode() == spv::OpEntryPoint) {
   1206             auto entrypointName = (char const *)&insn.word(3);
   1207             auto entrypointStageBits = 1u << insn.word(1);
   1208 
   1209             if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
   1210                 return insn;
   1211             }
   1212         }
   1213     }
   1214 
   1215     return src->end();
   1216 }
   1217 
   1218 bool shader_is_spirv(VkShaderModuleCreateInfo const *pCreateInfo) {
   1219     uint32_t *words = (uint32_t *)pCreateInfo->pCode;
   1220     size_t sizeInWords = pCreateInfo->codeSize / sizeof(uint32_t);
   1221 
   1222     /* Just validate that the header makes sense. */
   1223     return sizeInWords >= 5 && words[0] == spv::MagicNumber && words[1] == spv::Version;
   1224 }
   1225 
   1226 static char const *storage_class_name(unsigned sc) {
   1227     switch (sc) {
   1228     case spv::StorageClassInput:
   1229         return "input";
   1230     case spv::StorageClassOutput:
   1231         return "output";
   1232     case spv::StorageClassUniformConstant:
   1233         return "const uniform";
   1234     case spv::StorageClassUniform:
   1235         return "uniform";
   1236     case spv::StorageClassWorkgroup:
   1237         return "workgroup local";
   1238     case spv::StorageClassCrossWorkgroup:
   1239         return "workgroup global";
   1240     case spv::StorageClassPrivate:
   1241         return "private global";
   1242     case spv::StorageClassFunction:
   1243         return "function";
   1244     case spv::StorageClassGeneric:
   1245         return "generic";
   1246     case spv::StorageClassAtomicCounter:
   1247         return "atomic counter";
   1248     case spv::StorageClassImage:
   1249         return "image";
   1250     case spv::StorageClassPushConstant:
   1251         return "push constant";
   1252     default:
   1253         return "unknown";
   1254     }
   1255 }
   1256 
   1257 /* get the value of an integral constant */
   1258 unsigned get_constant_value(shader_module const *src, unsigned id) {
   1259     auto value = src->get_def(id);
   1260     assert(value != src->end());
   1261 
   1262     if (value.opcode() != spv::OpConstant) {
   1263         /* TODO: Either ensure that the specialization transform is already performed on a module we're
   1264             considering here, OR -- specialize on the fly now.
   1265             */
   1266         return 1;
   1267     }
   1268 
   1269     return value.word(3);
   1270 }
   1271 
   1272 
   1273 static void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
   1274     auto insn = src->get_def(type);
   1275     assert(insn != src->end());
   1276 
   1277     switch (insn.opcode()) {
   1278     case spv::OpTypeBool:
   1279         ss << "bool";
   1280         break;
   1281     case spv::OpTypeInt:
   1282         ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
   1283         break;
   1284     case spv::OpTypeFloat:
   1285         ss << "float" << insn.word(2);
   1286         break;
   1287     case spv::OpTypeVector:
   1288         ss << "vec" << insn.word(3) << " of ";
   1289         describe_type_inner(ss, src, insn.word(2));
   1290         break;
   1291     case spv::OpTypeMatrix:
   1292         ss << "mat" << insn.word(3) << " of ";
   1293         describe_type_inner(ss, src, insn.word(2));
   1294         break;
   1295     case spv::OpTypeArray:
   1296         ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
   1297         describe_type_inner(ss, src, insn.word(2));
   1298         break;
   1299     case spv::OpTypePointer:
   1300         ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
   1301         describe_type_inner(ss, src, insn.word(3));
   1302         break;
   1303     case spv::OpTypeStruct: {
   1304         ss << "struct of (";
   1305         for (unsigned i = 2; i < insn.len(); i++) {
   1306             describe_type_inner(ss, src, insn.word(i));
   1307             if (i == insn.len() - 1) {
   1308                 ss << ")";
   1309             } else {
   1310                 ss << ", ";
   1311             }
   1312         }
   1313         break;
   1314     }
   1315     case spv::OpTypeSampler:
   1316         ss << "sampler";
   1317         break;
   1318     case spv::OpTypeSampledImage:
   1319         ss << "sampler+";
   1320         describe_type_inner(ss, src, insn.word(2));
   1321         break;
   1322     case spv::OpTypeImage:
   1323         ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
   1324         break;
   1325     default:
   1326         ss << "oddtype";
   1327         break;
   1328     }
   1329 }
   1330 
   1331 
   1332 static std::string describe_type(shader_module const *src, unsigned type) {
   1333     std::ostringstream ss;
   1334     describe_type_inner(ss, src, type);
   1335     return ss.str();
   1336 }
   1337 
   1338 
   1339 static bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool b_arrayed) {
   1340     /* walk two type trees together, and complain about differences */
   1341     auto a_insn = a->get_def(a_type);
   1342     auto b_insn = b->get_def(b_type);
   1343     assert(a_insn != a->end());
   1344     assert(b_insn != b->end());
   1345 
   1346     if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
   1347         /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */
   1348         return types_match(a, b, a_type, b_insn.word(2), false);
   1349     }
   1350 
   1351     if (a_insn.opcode() != b_insn.opcode()) {
   1352         return false;
   1353     }
   1354 
   1355     switch (a_insn.opcode()) {
   1356     /* if b_arrayed and we hit a leaf type, then we can't match -- there's nowhere for the extra OpTypeArray to be! */
   1357     case spv::OpTypeBool:
   1358         return true && !b_arrayed;
   1359     case spv::OpTypeInt:
   1360         /* match on width, signedness */
   1361         return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3) && !b_arrayed;
   1362     case spv::OpTypeFloat:
   1363         /* match on width */
   1364         return a_insn.word(2) == b_insn.word(2) && !b_arrayed;
   1365     case spv::OpTypeVector:
   1366     case spv::OpTypeMatrix:
   1367         /* match on element type, count. these all have the same layout. we don't get here if
   1368          * b_arrayed -- that is handled above. */
   1369         return !b_arrayed && types_match(a, b, a_insn.word(2), b_insn.word(2), b_arrayed) && a_insn.word(3) == b_insn.word(3);
   1370     case spv::OpTypeArray:
   1371         /* match on element type, count. these all have the same layout. we don't get here if
   1372          * b_arrayed. This differs from vector & matrix types in that the array size is the id of a constant instruction,
   1373          * not a literal within OpTypeArray */
   1374         return !b_arrayed && types_match(a, b, a_insn.word(2), b_insn.word(2), b_arrayed) &&
   1375                get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
   1376     case spv::OpTypeStruct:
   1377         /* match on all element types */
   1378         {
   1379             if (b_arrayed) {
   1380                 /* for the purposes of matching different levels of arrayness, structs are leaves. */
   1381                 return false;
   1382             }
   1383 
   1384             if (a_insn.len() != b_insn.len()) {
   1385                 return false; /* structs cannot match if member counts differ */
   1386             }
   1387 
   1388             for (unsigned i = 2; i < a_insn.len(); i++) {
   1389                 if (!types_match(a, b, a_insn.word(i), b_insn.word(i), b_arrayed)) {
   1390                     return false;
   1391                 }
   1392             }
   1393 
   1394             return true;
   1395         }
   1396     case spv::OpTypePointer:
   1397         /* match on pointee type. storage class is expected to differ */
   1398         return types_match(a, b, a_insn.word(3), b_insn.word(3), b_arrayed);
   1399 
   1400     default:
   1401         /* remaining types are CLisms, or may not appear in the interfaces we
   1402          * are interested in. Just claim no match.
   1403          */
   1404         return false;
   1405     }
   1406 }
   1407 
   1408 static int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) {
   1409     auto it = map.find(id);
   1410     if (it == map.end())
   1411         return def;
   1412     else
   1413         return it->second;
   1414 }
   1415 
   1416 static unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
   1417     auto insn = src->get_def(type);
   1418     assert(insn != src->end());
   1419 
   1420     switch (insn.opcode()) {
   1421     case spv::OpTypePointer:
   1422         /* see through the ptr -- this is only ever at the toplevel for graphics shaders;
   1423          * we're never actually passing pointers around. */
   1424         return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
   1425     case spv::OpTypeArray:
   1426         if (strip_array_level) {
   1427             return get_locations_consumed_by_type(src, insn.word(2), false);
   1428         } else {
   1429             return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
   1430         }
   1431     case spv::OpTypeMatrix:
   1432         /* num locations is the dimension * element size */
   1433         return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
   1434     default:
   1435         /* everything else is just 1. */
   1436         return 1;
   1437 
   1438         /* TODO: extend to handle 64bit scalar types, whose vectors may need
   1439          * multiple locations. */
   1440     }
   1441 }
   1442 
   1443 typedef std::pair<unsigned, unsigned> location_t;
   1444 typedef std::pair<unsigned, unsigned> descriptor_slot_t;
   1445 
   1446 struct interface_var {
   1447     uint32_t id;
   1448     uint32_t type_id;
   1449     uint32_t offset;
   1450     /* TODO: collect the name, too? Isn't required to be present. */
   1451 };
   1452 
   1453 static spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
   1454     while (true) {
   1455 
   1456         if (def.opcode() == spv::OpTypePointer) {
   1457             def = src->get_def(def.word(3));
   1458         } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
   1459             def = src->get_def(def.word(2));
   1460             is_array_of_verts = false;
   1461         } else if (def.opcode() == spv::OpTypeStruct) {
   1462             return def;
   1463         } else {
   1464             return src->end();
   1465         }
   1466     }
   1467 }
   1468 
   1469 static void collect_interface_block_members(layer_data *my_data, VkDevice dev, shader_module const *src,
   1470                                             std::map<location_t, interface_var> &out,
   1471                                             std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
   1472                                             uint32_t id, uint32_t type_id) {
   1473     /* Walk down the type_id presented, trying to determine whether it's actually an interface block. */
   1474     auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts);
   1475     if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
   1476         /* this isn't an interface block. */
   1477         return;
   1478     }
   1479 
   1480     std::unordered_map<unsigned, unsigned> member_components;
   1481 
   1482     /* Walk all the OpMemberDecorate for type's result id -- first pass, collect components. */
   1483     for (auto insn : *src) {
   1484         if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
   1485             unsigned member_index = insn.word(2);
   1486 
   1487             if (insn.word(3) == spv::DecorationComponent) {
   1488                 unsigned component = insn.word(4);
   1489                 member_components[member_index] = component;
   1490             }
   1491         }
   1492     }
   1493 
   1494     /* Second pass -- produce the output, from Location decorations */
   1495     for (auto insn : *src) {
   1496         if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
   1497             unsigned member_index = insn.word(2);
   1498             unsigned member_type_id = type.word(2 + member_index);
   1499 
   1500             if (insn.word(3) == spv::DecorationLocation) {
   1501                 unsigned location = insn.word(4);
   1502                 unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
   1503                 auto component_it = member_components.find(member_index);
   1504                 unsigned component = component_it == member_components.end() ? 0 : component_it->second;
   1505 
   1506                 for (unsigned int offset = 0; offset < num_locations; offset++) {
   1507                     interface_var v;
   1508                     v.id = id;
   1509                     /* TODO: member index in interface_var too? */
   1510                     v.type_id = member_type_id;
   1511                     v.offset = offset;
   1512                     out[std::make_pair(location + offset, component)] = v;
   1513                 }
   1514             }
   1515         }
   1516     }
   1517 }
   1518 
   1519 static void collect_interface_by_location(layer_data *my_data, VkDevice dev, shader_module const *src, spirv_inst_iter entrypoint,
   1520                                           spv::StorageClass sinterface, std::map<location_t, interface_var> &out,
   1521                                           bool is_array_of_verts) {
   1522     std::unordered_map<unsigned, unsigned> var_locations;
   1523     std::unordered_map<unsigned, unsigned> var_builtins;
   1524     std::unordered_map<unsigned, unsigned> var_components;
   1525     std::unordered_map<unsigned, unsigned> blocks;
   1526 
   1527     for (auto insn : *src) {
   1528 
   1529         /* We consider two interface models: SSO rendezvous-by-location, and
   1530          * builtins. Complain about anything that fits neither model.
   1531          */
   1532         if (insn.opcode() == spv::OpDecorate) {
   1533             if (insn.word(2) == spv::DecorationLocation) {
   1534                 var_locations[insn.word(1)] = insn.word(3);
   1535             }
   1536 
   1537             if (insn.word(2) == spv::DecorationBuiltIn) {
   1538                 var_builtins[insn.word(1)] = insn.word(3);
   1539             }
   1540 
   1541             if (insn.word(2) == spv::DecorationComponent) {
   1542                 var_components[insn.word(1)] = insn.word(3);
   1543             }
   1544 
   1545             if (insn.word(2) == spv::DecorationBlock) {
   1546                 blocks[insn.word(1)] = 1;
   1547             }
   1548         }
   1549     }
   1550 
   1551     /* TODO: handle grouped decorations */
   1552     /* TODO: handle index=1 dual source outputs from FS -- two vars will
   1553      * have the same location, and we DONT want to clobber. */
   1554 
   1555     /* find the end of the entrypoint's name string. additional zero bytes follow the actual null
   1556        terminator, to fill out the rest of the word - so we only need to look at the last byte in
   1557        the word to determine which word contains the terminator. */
   1558     auto word = 3;
   1559     while (entrypoint.word(word) & 0xff000000u) {
   1560         ++word;
   1561     }
   1562     ++word;
   1563 
   1564     for (; word < entrypoint.len(); word++) {
   1565         auto insn = src->get_def(entrypoint.word(word));
   1566         assert(insn != src->end());
   1567         assert(insn.opcode() == spv::OpVariable);
   1568 
   1569         if (insn.word(3) == sinterface) {
   1570             unsigned id = insn.word(2);
   1571             unsigned type = insn.word(1);
   1572 
   1573             int location = value_or_default(var_locations, id, -1);
   1574             int builtin = value_or_default(var_builtins, id, -1);
   1575             unsigned component = value_or_default(var_components, id, 0); /* unspecified is OK, is 0 */
   1576 
   1577             /* All variables and interface block members in the Input or Output storage classes
   1578              * must be decorated with either a builtin or an explicit location.
   1579              *
   1580              * TODO: integrate the interface block support here. For now, don't complain --
   1581              * a valid SPIRV module will only hit this path for the interface block case, as the
   1582              * individual members of the type are decorated, rather than variable declarations.
   1583              */
   1584 
   1585             if (location != -1) {
   1586                 /* A user-defined interface variable, with a location. Where a variable
   1587                  * occupied multiple locations, emit one result for each. */
   1588                 unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts);
   1589                 for (unsigned int offset = 0; offset < num_locations; offset++) {
   1590                     interface_var v;
   1591                     v.id = id;
   1592                     v.type_id = type;
   1593                     v.offset = offset;
   1594                     out[std::make_pair(location + offset, component)] = v;
   1595                 }
   1596             } else if (builtin == -1) {
   1597                 /* An interface block instance */
   1598                 collect_interface_block_members(my_data, dev, src, out, blocks, is_array_of_verts, id, type);
   1599             }
   1600         }
   1601     }
   1602 }
   1603 
   1604 static void collect_interface_by_descriptor_slot(layer_data *my_data, VkDevice dev, shader_module const *src,
   1605                                                  std::unordered_set<uint32_t> const &accessible_ids,
   1606                                                  std::map<descriptor_slot_t, interface_var> &out) {
   1607 
   1608     std::unordered_map<unsigned, unsigned> var_sets;
   1609     std::unordered_map<unsigned, unsigned> var_bindings;
   1610 
   1611     for (auto insn : *src) {
   1612         /* All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
   1613          * DecorationDescriptorSet and DecorationBinding.
   1614          */
   1615         if (insn.opcode() == spv::OpDecorate) {
   1616             if (insn.word(2) == spv::DecorationDescriptorSet) {
   1617                 var_sets[insn.word(1)] = insn.word(3);
   1618             }
   1619 
   1620             if (insn.word(2) == spv::DecorationBinding) {
   1621                 var_bindings[insn.word(1)] = insn.word(3);
   1622             }
   1623         }
   1624     }
   1625 
   1626     for (auto id : accessible_ids) {
   1627         auto insn = src->get_def(id);
   1628         assert(insn != src->end());
   1629 
   1630         if (insn.opcode() == spv::OpVariable &&
   1631             (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
   1632             unsigned set = value_or_default(var_sets, insn.word(2), 0);
   1633             unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
   1634 
   1635             auto existing_it = out.find(std::make_pair(set, binding));
   1636             if (existing_it != out.end()) {
   1637                 /* conflict within spv image */
   1638                 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1639                         __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
   1640                         "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition",
   1641                         insn.word(2), insn.word(1), storage_class_name(insn.word(3)), existing_it->first.first,
   1642                         existing_it->first.second);
   1643             }
   1644 
   1645             interface_var v;
   1646             v.id = insn.word(2);
   1647             v.type_id = insn.word(1);
   1648             out[std::make_pair(set, binding)] = v;
   1649         }
   1650     }
   1651 }
   1652 
   1653 static bool validate_interface_between_stages(layer_data *my_data, VkDevice dev, shader_module const *producer,
   1654                                               spirv_inst_iter producer_entrypoint, char const *producer_name,
   1655                                               shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
   1656                                               char const *consumer_name, bool consumer_arrayed_input) {
   1657     std::map<location_t, interface_var> outputs;
   1658     std::map<location_t, interface_var> inputs;
   1659 
   1660     bool pass = true;
   1661 
   1662     collect_interface_by_location(my_data, dev, producer, producer_entrypoint, spv::StorageClassOutput, outputs, false);
   1663     collect_interface_by_location(my_data, dev, consumer, consumer_entrypoint, spv::StorageClassInput, inputs,
   1664                                   consumer_arrayed_input);
   1665 
   1666     auto a_it = outputs.begin();
   1667     auto b_it = inputs.begin();
   1668 
   1669     /* maps sorted by key (location); walk them together to find mismatches */
   1670     while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
   1671         bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
   1672         bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
   1673         auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
   1674         auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
   1675 
   1676         if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
   1677             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   1678                         /*dev*/ 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
   1679                         "%s writes to output location %u.%u which is not consumed by %s", producer_name, a_first.first,
   1680                         a_first.second, consumer_name)) {
   1681                 pass = false;
   1682             }
   1683             a_it++;
   1684         } else if (a_at_end || a_first > b_first) {
   1685             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1686                         __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
   1687                         "%s consumes input location %u.%u which is not written by %s", consumer_name, b_first.first, b_first.second,
   1688                         producer_name)) {
   1689                 pass = false;
   1690             }
   1691             b_it++;
   1692         } else {
   1693             if (types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id, consumer_arrayed_input)) {
   1694                 /* OK! */
   1695             } else {
   1696                 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1697                             __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
   1698                             a_first.first, a_first.second,
   1699                             describe_type(producer, a_it->second.type_id).c_str(),
   1700                             describe_type(consumer, b_it->second.type_id).c_str())) {
   1701                     pass = false;
   1702                 }
   1703             }
   1704             a_it++;
   1705             b_it++;
   1706         }
   1707     }
   1708 
   1709     return pass;
   1710 }
   1711 
   1712 enum FORMAT_TYPE {
   1713     FORMAT_TYPE_UNDEFINED,
   1714     FORMAT_TYPE_FLOAT, /* UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader */
   1715     FORMAT_TYPE_SINT,
   1716     FORMAT_TYPE_UINT,
   1717 };
   1718 
   1719 static unsigned get_format_type(VkFormat fmt) {
   1720     switch (fmt) {
   1721     case VK_FORMAT_UNDEFINED:
   1722         return FORMAT_TYPE_UNDEFINED;
   1723     case VK_FORMAT_R8_SINT:
   1724     case VK_FORMAT_R8G8_SINT:
   1725     case VK_FORMAT_R8G8B8_SINT:
   1726     case VK_FORMAT_R8G8B8A8_SINT:
   1727     case VK_FORMAT_R16_SINT:
   1728     case VK_FORMAT_R16G16_SINT:
   1729     case VK_FORMAT_R16G16B16_SINT:
   1730     case VK_FORMAT_R16G16B16A16_SINT:
   1731     case VK_FORMAT_R32_SINT:
   1732     case VK_FORMAT_R32G32_SINT:
   1733     case VK_FORMAT_R32G32B32_SINT:
   1734     case VK_FORMAT_R32G32B32A32_SINT:
   1735     case VK_FORMAT_B8G8R8_SINT:
   1736     case VK_FORMAT_B8G8R8A8_SINT:
   1737     case VK_FORMAT_A2B10G10R10_SINT_PACK32:
   1738     case VK_FORMAT_A2R10G10B10_SINT_PACK32:
   1739         return FORMAT_TYPE_SINT;
   1740     case VK_FORMAT_R8_UINT:
   1741     case VK_FORMAT_R8G8_UINT:
   1742     case VK_FORMAT_R8G8B8_UINT:
   1743     case VK_FORMAT_R8G8B8A8_UINT:
   1744     case VK_FORMAT_R16_UINT:
   1745     case VK_FORMAT_R16G16_UINT:
   1746     case VK_FORMAT_R16G16B16_UINT:
   1747     case VK_FORMAT_R16G16B16A16_UINT:
   1748     case VK_FORMAT_R32_UINT:
   1749     case VK_FORMAT_R32G32_UINT:
   1750     case VK_FORMAT_R32G32B32_UINT:
   1751     case VK_FORMAT_R32G32B32A32_UINT:
   1752     case VK_FORMAT_B8G8R8_UINT:
   1753     case VK_FORMAT_B8G8R8A8_UINT:
   1754     case VK_FORMAT_A2B10G10R10_UINT_PACK32:
   1755     case VK_FORMAT_A2R10G10B10_UINT_PACK32:
   1756         return FORMAT_TYPE_UINT;
   1757     default:
   1758         return FORMAT_TYPE_FLOAT;
   1759     }
   1760 }
   1761 
   1762 /* characterizes a SPIR-V type appearing in an interface to a FF stage,
   1763  * for comparison to a VkFormat's characterization above. */
   1764 static unsigned get_fundamental_type(shader_module const *src, unsigned type) {
   1765     auto insn = src->get_def(type);
   1766     assert(insn != src->end());
   1767 
   1768     switch (insn.opcode()) {
   1769     case spv::OpTypeInt:
   1770         return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
   1771     case spv::OpTypeFloat:
   1772         return FORMAT_TYPE_FLOAT;
   1773     case spv::OpTypeVector:
   1774         return get_fundamental_type(src, insn.word(2));
   1775     case spv::OpTypeMatrix:
   1776         return get_fundamental_type(src, insn.word(2));
   1777     case spv::OpTypeArray:
   1778         return get_fundamental_type(src, insn.word(2));
   1779     case spv::OpTypePointer:
   1780         return get_fundamental_type(src, insn.word(3));
   1781     default:
   1782         return FORMAT_TYPE_UNDEFINED;
   1783     }
   1784 }
   1785 
   1786 static uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
   1787     uint32_t bit_pos = u_ffs(stage);
   1788     return bit_pos - 1;
   1789 }
   1790 
   1791 static bool validate_vi_consistency(layer_data *my_data, VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi) {
   1792     /* walk the binding descriptions, which describe the step rate and stride of each vertex buffer.
   1793      * each binding should be specified only once.
   1794      */
   1795     std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
   1796     bool pass = true;
   1797 
   1798     for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
   1799         auto desc = &vi->pVertexBindingDescriptions[i];
   1800         auto &binding = bindings[desc->binding];
   1801         if (binding) {
   1802             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1803                         __LINE__, SHADER_CHECKER_INCONSISTENT_VI, "SC",
   1804                         "Duplicate vertex input binding descriptions for binding %d", desc->binding)) {
   1805                 pass = false;
   1806             }
   1807         } else {
   1808             binding = desc;
   1809         }
   1810     }
   1811 
   1812     return pass;
   1813 }
   1814 
   1815 static bool validate_vi_against_vs_inputs(layer_data *my_data, VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi,
   1816                                           shader_module const *vs, spirv_inst_iter entrypoint) {
   1817     std::map<location_t, interface_var> inputs;
   1818     bool pass = true;
   1819 
   1820     collect_interface_by_location(my_data, dev, vs, entrypoint, spv::StorageClassInput, inputs, false);
   1821 
   1822     /* Build index by location */
   1823     std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
   1824     if (vi) {
   1825         for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++)
   1826             attribs[vi->pVertexAttributeDescriptions[i].location] = &vi->pVertexAttributeDescriptions[i];
   1827     }
   1828 
   1829     auto it_a = attribs.begin();
   1830     auto it_b = inputs.begin();
   1831 
   1832     while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
   1833         bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
   1834         bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
   1835         auto a_first = a_at_end ? 0 : it_a->first;
   1836         auto b_first = b_at_end ? 0 : it_b->first.first;
   1837         if (!a_at_end && (b_at_end || a_first < b_first)) {
   1838             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   1839                         /*dev*/ 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
   1840                         "Vertex attribute at location %d not consumed by VS", a_first)) {
   1841                 pass = false;
   1842             }
   1843             it_a++;
   1844         } else if (!b_at_end && (a_at_end || b_first < a_first)) {
   1845             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1846                         __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "VS consumes input at location %d but not provided",
   1847                         b_first)) {
   1848                 pass = false;
   1849             }
   1850             it_b++;
   1851         } else {
   1852             unsigned attrib_type = get_format_type(it_a->second->format);
   1853             unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
   1854 
   1855             /* type checking */
   1856             if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) {
   1857                 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1858                             __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
   1859                             "Attribute type of `%s` at location %d does not match VS input type of `%s`",
   1860                             string_VkFormat(it_a->second->format), a_first,
   1861                             describe_type(vs, it_b->second.type_id).c_str())) {
   1862                     pass = false;
   1863                 }
   1864             }
   1865 
   1866             /* OK! */
   1867             it_a++;
   1868             it_b++;
   1869         }
   1870     }
   1871 
   1872     return pass;
   1873 }
   1874 
   1875 static bool validate_fs_outputs_against_render_pass(layer_data *my_data, VkDevice dev, shader_module const *fs,
   1876                                                     spirv_inst_iter entrypoint, RENDER_PASS_NODE const *rp, uint32_t subpass) {
   1877     const std::vector<VkFormat> &color_formats = rp->subpassColorFormats[subpass];
   1878     std::map<location_t, interface_var> outputs;
   1879     bool pass = true;
   1880 
   1881     /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */
   1882 
   1883     collect_interface_by_location(my_data, dev, fs, entrypoint, spv::StorageClassOutput, outputs, false);
   1884 
   1885     auto it = outputs.begin();
   1886     uint32_t attachment = 0;
   1887 
   1888     /* Walk attachment list and outputs together -- this is a little overpowered since attachments
   1889      * are currently dense, but the parallel with matching between shader stages is nice.
   1890      */
   1891 
   1892     while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) {
   1893         if (attachment == color_formats.size() || (it != outputs.end() && it->first.first < attachment)) {
   1894             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1895                         __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
   1896                         "FS writes to output location %d with no matching attachment", it->first.first)) {
   1897                 pass = false;
   1898             }
   1899             it++;
   1900         } else if (it == outputs.end() || it->first.first > attachment) {
   1901             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1902                         __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by FS", attachment)) {
   1903                 pass = false;
   1904             }
   1905             attachment++;
   1906         } else {
   1907             unsigned output_type = get_fundamental_type(fs, it->second.type_id);
   1908             unsigned att_type = get_format_type(color_formats[attachment]);
   1909 
   1910             /* type checking */
   1911             if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) {
   1912                 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
   1913                             __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
   1914                             "Attachment %d of type `%s` does not match FS output type of `%s`", attachment,
   1915                             string_VkFormat(color_formats[attachment]),
   1916                             describe_type(fs, it->second.type_id).c_str())) {
   1917                     pass = false;
   1918                 }
   1919             }
   1920 
   1921             /* OK! */
   1922             it++;
   1923             attachment++;
   1924         }
   1925     }
   1926 
   1927     return pass;
   1928 }
   1929 
   1930 /* For some analyses, we need to know about all ids referenced by the static call tree of a particular
   1931  * entrypoint. This is important for identifying the set of shader resources actually used by an entrypoint,
   1932  * for example.
   1933  * Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
   1934  *  - NOT the shader input/output interfaces.
   1935  *
   1936  * TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
   1937  * converting parts of this to be generated from the machine-readable spec instead.
   1938  */
   1939 static void mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint, std::unordered_set<uint32_t> &ids) {
   1940     std::unordered_set<uint32_t> worklist;
   1941     worklist.insert(entrypoint.word(2));
   1942 
   1943     while (!worklist.empty()) {
   1944         auto id_iter = worklist.begin();
   1945         auto id = *id_iter;
   1946         worklist.erase(id_iter);
   1947 
   1948         auto insn = src->get_def(id);
   1949         if (insn == src->end()) {
   1950             /* id is something we didnt collect in build_def_index. that's OK -- we'll stumble
   1951              * across all kinds of things here that we may not care about. */
   1952             continue;
   1953         }
   1954 
   1955         /* try to add to the output set */
   1956         if (!ids.insert(id).second) {
   1957             continue; /* if we already saw this id, we don't want to walk it again. */
   1958         }
   1959 
   1960         switch (insn.opcode()) {
   1961         case spv::OpFunction:
   1962             /* scan whole body of the function, enlisting anything interesting */
   1963             while (++insn, insn.opcode() != spv::OpFunctionEnd) {
   1964                 switch (insn.opcode()) {
   1965                 case spv::OpLoad:
   1966                 case spv::OpAtomicLoad:
   1967                 case spv::OpAtomicExchange:
   1968                 case spv::OpAtomicCompareExchange:
   1969                 case spv::OpAtomicCompareExchangeWeak:
   1970                 case spv::OpAtomicIIncrement:
   1971                 case spv::OpAtomicIDecrement:
   1972                 case spv::OpAtomicIAdd:
   1973                 case spv::OpAtomicISub:
   1974                 case spv::OpAtomicSMin:
   1975                 case spv::OpAtomicUMin:
   1976                 case spv::OpAtomicSMax:
   1977                 case spv::OpAtomicUMax:
   1978                 case spv::OpAtomicAnd:
   1979                 case spv::OpAtomicOr:
   1980                 case spv::OpAtomicXor:
   1981                     worklist.insert(insn.word(3)); /* ptr */
   1982                     break;
   1983                 case spv::OpStore:
   1984                 case spv::OpAtomicStore:
   1985                     worklist.insert(insn.word(1)); /* ptr */
   1986                     break;
   1987                 case spv::OpAccessChain:
   1988                 case spv::OpInBoundsAccessChain:
   1989                     worklist.insert(insn.word(3)); /* base ptr */
   1990                     break;
   1991                 case spv::OpSampledImage:
   1992                 case spv::OpImageSampleImplicitLod:
   1993                 case spv::OpImageSampleExplicitLod:
   1994                 case spv::OpImageSampleDrefImplicitLod:
   1995                 case spv::OpImageSampleDrefExplicitLod:
   1996                 case spv::OpImageSampleProjImplicitLod:
   1997                 case spv::OpImageSampleProjExplicitLod:
   1998                 case spv::OpImageSampleProjDrefImplicitLod:
   1999                 case spv::OpImageSampleProjDrefExplicitLod:
   2000                 case spv::OpImageFetch:
   2001                 case spv::OpImageGather:
   2002                 case spv::OpImageDrefGather:
   2003                 case spv::OpImageRead:
   2004                 case spv::OpImage:
   2005                 case spv::OpImageQueryFormat:
   2006                 case spv::OpImageQueryOrder:
   2007                 case spv::OpImageQuerySizeLod:
   2008                 case spv::OpImageQuerySize:
   2009                 case spv::OpImageQueryLod:
   2010                 case spv::OpImageQueryLevels:
   2011                 case spv::OpImageQuerySamples:
   2012                 case spv::OpImageSparseSampleImplicitLod:
   2013                 case spv::OpImageSparseSampleExplicitLod:
   2014                 case spv::OpImageSparseSampleDrefImplicitLod:
   2015                 case spv::OpImageSparseSampleDrefExplicitLod:
   2016                 case spv::OpImageSparseSampleProjImplicitLod:
   2017                 case spv::OpImageSparseSampleProjExplicitLod:
   2018                 case spv::OpImageSparseSampleProjDrefImplicitLod:
   2019                 case spv::OpImageSparseSampleProjDrefExplicitLod:
   2020                 case spv::OpImageSparseFetch:
   2021                 case spv::OpImageSparseGather:
   2022                 case spv::OpImageSparseDrefGather:
   2023                 case spv::OpImageTexelPointer:
   2024                     worklist.insert(insn.word(3)); /* image or sampled image */
   2025                     break;
   2026                 case spv::OpImageWrite:
   2027                     worklist.insert(insn.word(1)); /* image -- different operand order to above */
   2028                     break;
   2029                 case spv::OpFunctionCall:
   2030                     for (auto i = 3; i < insn.len(); i++) {
   2031                         worklist.insert(insn.word(i)); /* fn itself, and all args */
   2032                     }
   2033                     break;
   2034 
   2035                 case spv::OpExtInst:
   2036                     for (auto i = 5; i < insn.len(); i++) {
   2037                         worklist.insert(insn.word(i)); /* operands to ext inst */
   2038                     }
   2039                     break;
   2040                 }
   2041             }
   2042             break;
   2043         }
   2044     }
   2045 }
   2046 
   2047 struct shader_stage_attributes {
   2048     char const *const name;
   2049     bool arrayed_input;
   2050 };
   2051 
   2052 static shader_stage_attributes shader_stage_attribs[] = {
   2053     {"vertex shader", false},
   2054     {"tessellation control shader", true},
   2055     {"tessellation evaluation shader", false},
   2056     {"geometry shader", true},
   2057     {"fragment shader", false},
   2058 };
   2059 
   2060 static bool validate_push_constant_block_against_pipeline(layer_data *my_data, VkDevice dev,
   2061                                                           std::vector<VkPushConstantRange> const *pushConstantRanges,
   2062                                                           shader_module const *src, spirv_inst_iter type,
   2063                                                           VkShaderStageFlagBits stage) {
   2064     bool pass = true;
   2065 
   2066     /* strip off ptrs etc */
   2067     type = get_struct_type(src, type, false);
   2068     assert(type != src->end());
   2069 
   2070     /* validate directly off the offsets. this isn't quite correct for arrays
   2071      * and matrices, but is a good first step. TODO: arrays, matrices, weird
   2072      * sizes */
   2073     for (auto insn : *src) {
   2074         if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
   2075 
   2076             if (insn.word(3) == spv::DecorationOffset) {
   2077                 unsigned offset = insn.word(4);
   2078                 auto size = 4; /* bytes; TODO: calculate this based on the type */
   2079 
   2080                 bool found_range = false;
   2081                 for (auto const &range : *pushConstantRanges) {
   2082                     if (range.offset <= offset && range.offset + range.size >= offset + size) {
   2083                         found_range = true;
   2084 
   2085                         if ((range.stageFlags & stage) == 0) {
   2086                             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2087                                         /* dev */ 0, __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
   2088                                         "Push constant range covering variable starting at "
   2089                                         "offset %u not accessible from stage %s",
   2090                                         offset, string_VkShaderStageFlagBits(stage))) {
   2091                                 pass = false;
   2092                             }
   2093                         }
   2094 
   2095                         break;
   2096                     }
   2097                 }
   2098 
   2099                 if (!found_range) {
   2100                     if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2101                                 /* dev */ 0, __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
   2102                                 "Push constant range covering variable starting at "
   2103                                 "offset %u not declared in layout",
   2104                                 offset)) {
   2105                         pass = false;
   2106                     }
   2107                 }
   2108             }
   2109         }
   2110     }
   2111 
   2112     return pass;
   2113 }
   2114 
   2115 static bool validate_push_constant_usage(layer_data *my_data, VkDevice dev,
   2116                                          std::vector<VkPushConstantRange> const *pushConstantRanges, shader_module const *src,
   2117                                          std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
   2118     bool pass = true;
   2119 
   2120     for (auto id : accessible_ids) {
   2121         auto def_insn = src->get_def(id);
   2122         if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
   2123             pass = validate_push_constant_block_against_pipeline(my_data, dev, pushConstantRanges, src,
   2124                                                                  src->get_def(def_insn.word(1)), stage) &&
   2125                    pass;
   2126         }
   2127     }
   2128 
   2129     return pass;
   2130 }
   2131 
   2132 // For given pipelineLayout verify that the setLayout at slot.first
   2133 //  has the requested binding at slot.second
   2134 static VkDescriptorSetLayoutBinding const * get_descriptor_binding(layer_data *my_data, vector<VkDescriptorSetLayout> *pipelineLayout, descriptor_slot_t slot) {
   2135 
   2136     if (!pipelineLayout)
   2137         return nullptr;
   2138 
   2139     if (slot.first >= pipelineLayout->size())
   2140         return nullptr;
   2141 
   2142     auto const layout_node = my_data->descriptorSetLayoutMap[(*pipelineLayout)[slot.first]];
   2143 
   2144     auto bindingIt = layout_node->bindingToIndexMap.find(slot.second);
   2145     if ((bindingIt == layout_node->bindingToIndexMap.end()) || (layout_node->createInfo.pBindings == NULL))
   2146         return nullptr;
   2147 
   2148     assert(bindingIt->second < layout_node->createInfo.bindingCount);
   2149     return &layout_node->createInfo.pBindings[bindingIt->second];
   2150 }
   2151 
   2152 // Block of code at start here for managing/tracking Pipeline state that this layer cares about
   2153 
   2154 static uint64_t g_drawCount[NUM_DRAW_TYPES] = {0, 0, 0, 0};
   2155 
   2156 // TODO : Should be tracking lastBound per commandBuffer and when draws occur, report based on that cmd buffer lastBound
   2157 //   Then need to synchronize the accesses based on cmd buffer so that if I'm reading state on one cmd buffer, updates
   2158 //   to that same cmd buffer by separate thread are not changing state from underneath us
   2159 // Track the last cmd buffer touched by this thread
   2160 
   2161 static VkBool32 hasDrawCmd(GLOBAL_CB_NODE *pCB) {
   2162     for (uint32_t i = 0; i < NUM_DRAW_TYPES; i++) {
   2163         if (pCB->drawCount[i])
   2164             return VK_TRUE;
   2165     }
   2166     return VK_FALSE;
   2167 }
   2168 
   2169 // Check object status for selected flag state
   2170 static VkBool32 validate_status(layer_data *my_data, GLOBAL_CB_NODE *pNode, CBStatusFlags enable_mask, CBStatusFlags status_mask,
   2171                                 CBStatusFlags status_flag, VkFlags msg_flags, DRAW_STATE_ERROR error_code, const char *fail_msg) {
   2172     // If non-zero enable mask is present, check it against status but if enable_mask
   2173     //  is 0 then no enable required so we should always just check status
   2174     if ((!enable_mask) || (enable_mask & pNode->status)) {
   2175         if ((pNode->status & status_mask) != status_flag) {
   2176             // TODO : How to pass dispatchable objects as srcObject? Here src obj should be cmd buffer
   2177             return log_msg(my_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, error_code,
   2178                            "DS", "CB object %#" PRIxLEAST64 ": %s", (uint64_t)(pNode->commandBuffer), fail_msg);
   2179         }
   2180     }
   2181     return VK_FALSE;
   2182 }
   2183 
   2184 // Retrieve pipeline node ptr for given pipeline object
   2185 static PIPELINE_NODE *getPipeline(layer_data *my_data, const VkPipeline pipeline) {
   2186     if (my_data->pipelineMap.find(pipeline) == my_data->pipelineMap.end()) {
   2187         return NULL;
   2188     }
   2189     return my_data->pipelineMap[pipeline];
   2190 }
   2191 
   2192 // Return VK_TRUE if for a given PSO, the given state enum is dynamic, else return VK_FALSE
   2193 static VkBool32 isDynamic(const PIPELINE_NODE *pPipeline, const VkDynamicState state) {
   2194     if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
   2195         for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
   2196             if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i])
   2197                 return VK_TRUE;
   2198         }
   2199     }
   2200     return VK_FALSE;
   2201 }
   2202 
   2203 // Validate state stored as flags at time of draw call
   2204 static VkBool32 validate_draw_state_flags(layer_data *my_data, GLOBAL_CB_NODE *pCB, VkBool32 indexedDraw) {
   2205     VkBool32 result;
   2206     result =
   2207         validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_VIEWPORT_SET, CBSTATUS_VIEWPORT_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   2208                         DRAWSTATE_VIEWPORT_NOT_BOUND, "Dynamic viewport state not set for this command buffer");
   2209     result |=
   2210         validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_SCISSOR_SET, CBSTATUS_SCISSOR_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   2211                         DRAWSTATE_SCISSOR_NOT_BOUND, "Dynamic scissor state not set for this command buffer");
   2212     result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_LINE_WIDTH_SET, CBSTATUS_LINE_WIDTH_SET,
   2213                               VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_LINE_WIDTH_NOT_BOUND,
   2214                               "Dynamic line width state not set for this command buffer");
   2215     result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_DEPTH_BIAS_SET, CBSTATUS_DEPTH_BIAS_SET,
   2216                               VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_DEPTH_BIAS_NOT_BOUND,
   2217                               "Dynamic depth bias state not set for this command buffer");
   2218     result |= validate_status(my_data, pCB, CBSTATUS_COLOR_BLEND_WRITE_ENABLE, CBSTATUS_BLEND_SET, CBSTATUS_BLEND_SET,
   2219                               VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_BLEND_NOT_BOUND,
   2220                               "Dynamic blend object state not set for this command buffer");
   2221     result |= validate_status(my_data, pCB, CBSTATUS_DEPTH_WRITE_ENABLE, CBSTATUS_DEPTH_BOUNDS_SET, CBSTATUS_DEPTH_BOUNDS_SET,
   2222                               VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND,
   2223                               "Dynamic depth bounds state not set for this command buffer");
   2224     result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_READ_MASK_SET,
   2225                               CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND,
   2226                               "Dynamic stencil read mask state not set for this command buffer");
   2227     result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_WRITE_MASK_SET,
   2228                               CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND,
   2229                               "Dynamic stencil write mask state not set for this command buffer");
   2230     result |= validate_status(my_data, pCB, CBSTATUS_STENCIL_TEST_ENABLE, CBSTATUS_STENCIL_REFERENCE_SET,
   2231                               CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_STENCIL_NOT_BOUND,
   2232                               "Dynamic stencil reference state not set for this command buffer");
   2233     if (indexedDraw)
   2234         result |= validate_status(my_data, pCB, CBSTATUS_NONE, CBSTATUS_INDEX_BUFFER_BOUND, CBSTATUS_INDEX_BUFFER_BOUND,
   2235                                   VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_INDEX_BUFFER_NOT_BOUND,
   2236                                   "Index buffer object not bound to this command buffer when Indexed Draw attempted");
   2237     return result;
   2238 }
   2239 
   2240 // Verify attachment reference compatibility according to spec
   2241 //  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
   2242 //  If both AttachmentReference arrays have requested index, check their corresponding AttachementDescriptions
   2243 //   to make sure that format and samples counts match.
   2244 //  If not, they are not compatible.
   2245 static bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
   2246                                              const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
   2247                                              const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
   2248                                              const VkAttachmentDescription *pSecondaryAttachments) {
   2249     if (index >= primaryCount) { // Check secondary as if primary is VK_ATTACHMENT_UNUSED
   2250         if (VK_ATTACHMENT_UNUSED != pSecondary[index].attachment)
   2251             return false;
   2252     } else if (index >= secondaryCount) { // Check primary as if secondary is VK_ATTACHMENT_UNUSED
   2253         if (VK_ATTACHMENT_UNUSED != pPrimary[index].attachment)
   2254             return false;
   2255     } else { // format and sample count must match
   2256         if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
   2257              pSecondaryAttachments[pSecondary[index].attachment].format) &&
   2258             (pPrimaryAttachments[pPrimary[index].attachment].samples ==
   2259              pSecondaryAttachments[pSecondary[index].attachment].samples))
   2260             return true;
   2261     }
   2262     // Format and sample counts didn't match
   2263     return false;
   2264 }
   2265 
   2266 // For give primary and secondary RenderPass objects, verify that they're compatible
   2267 static bool verify_renderpass_compatibility(layer_data *my_data, const VkRenderPass primaryRP, const VkRenderPass secondaryRP,
   2268                                             string &errorMsg) {
   2269     stringstream errorStr;
   2270     if (my_data->renderPassMap.find(primaryRP) == my_data->renderPassMap.end()) {
   2271         errorStr << "invalid VkRenderPass (" << primaryRP << ")";
   2272         errorMsg = errorStr.str();
   2273         return false;
   2274     } else if (my_data->renderPassMap.find(secondaryRP) == my_data->renderPassMap.end()) {
   2275         errorStr << "invalid VkRenderPass (" << secondaryRP << ")";
   2276         errorMsg = errorStr.str();
   2277         return false;
   2278     }
   2279     // Trivial pass case is exact same RP
   2280     if (primaryRP == secondaryRP) {
   2281         return true;
   2282     }
   2283     const VkRenderPassCreateInfo *primaryRPCI = my_data->renderPassMap[primaryRP]->pCreateInfo;
   2284     const VkRenderPassCreateInfo *secondaryRPCI = my_data->renderPassMap[secondaryRP]->pCreateInfo;
   2285     if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
   2286         errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
   2287                  << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
   2288         errorMsg = errorStr.str();
   2289         return false;
   2290     }
   2291     uint32_t spIndex = 0;
   2292     for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
   2293         // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
   2294         uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
   2295         uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
   2296         uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
   2297         for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
   2298             if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
   2299                                                   primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
   2300                                                   secondaryColorCount, secondaryRPCI->pAttachments)) {
   2301                 errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
   2302                 errorMsg = errorStr.str();
   2303                 return false;
   2304             } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
   2305                                                          primaryColorCount, primaryRPCI->pAttachments,
   2306                                                          secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
   2307                                                          secondaryColorCount, secondaryRPCI->pAttachments)) {
   2308                 errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
   2309                 errorMsg = errorStr.str();
   2310                 return false;
   2311             } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
   2312                                                          primaryColorCount, primaryRPCI->pAttachments,
   2313                                                          secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
   2314                                                          secondaryColorCount, secondaryRPCI->pAttachments)) {
   2315                 errorStr << "depth/stencil attachments at index " << cIdx << " of subpass index " << spIndex
   2316                          << " are not compatible.";
   2317                 errorMsg = errorStr.str();
   2318                 return false;
   2319             }
   2320         }
   2321         uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
   2322         uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
   2323         uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
   2324         for (uint32_t i = 0; i < inputMax; ++i) {
   2325             if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount,
   2326                                                   primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
   2327                                                   secondaryColorCount, secondaryRPCI->pAttachments)) {
   2328                 errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
   2329                 errorMsg = errorStr.str();
   2330                 return false;
   2331             }
   2332         }
   2333     }
   2334     return true;
   2335 }
   2336 
   2337 // For give SET_NODE, verify that its Set is compatible w/ the setLayout corresponding to pipelineLayout[layoutIndex]
   2338 static bool verify_set_layout_compatibility(layer_data *my_data, const SET_NODE *pSet, const VkPipelineLayout layout,
   2339                                             const uint32_t layoutIndex, string &errorMsg) {
   2340     stringstream errorStr;
   2341     auto pipeline_layout_it = my_data->pipelineLayoutMap.find(layout);
   2342     if (pipeline_layout_it == my_data->pipelineLayoutMap.end()) {
   2343         errorStr << "invalid VkPipelineLayout (" << layout << ")";
   2344         errorMsg = errorStr.str();
   2345         return false;
   2346     }
   2347     if (layoutIndex >= pipeline_layout_it->second.descriptorSetLayouts.size()) {
   2348         errorStr << "VkPipelineLayout (" << layout << ") only contains " << pipeline_layout_it->second.descriptorSetLayouts.size()
   2349                  << " setLayouts corresponding to sets 0-" << pipeline_layout_it->second.descriptorSetLayouts.size() - 1
   2350                  << ", but you're attempting to bind set to index " << layoutIndex;
   2351         errorMsg = errorStr.str();
   2352         return false;
   2353     }
   2354     // Get the specific setLayout from PipelineLayout that overlaps this set
   2355     LAYOUT_NODE *pLayoutNode = my_data->descriptorSetLayoutMap[pipeline_layout_it->second.descriptorSetLayouts[layoutIndex]];
   2356     if (pLayoutNode->layout == pSet->pLayout->layout) { // trivial pass case
   2357         return true;
   2358     }
   2359     size_t descriptorCount = pLayoutNode->descriptorTypes.size();
   2360     if (descriptorCount != pSet->pLayout->descriptorTypes.size()) {
   2361         errorStr << "setLayout " << layoutIndex << " from pipelineLayout " << layout << " has " << descriptorCount
   2362                  << " descriptors, but corresponding set being bound has " << pSet->pLayout->descriptorTypes.size()
   2363                  << " descriptors.";
   2364         errorMsg = errorStr.str();
   2365         return false; // trivial fail case
   2366     }
   2367     // Now need to check set against corresponding pipelineLayout to verify compatibility
   2368     for (size_t i = 0; i < descriptorCount; ++i) {
   2369         // Need to verify that layouts are identically defined
   2370         //  TODO : Is below sufficient? Making sure that types & stageFlags match per descriptor
   2371         //    do we also need to check immutable samplers?
   2372         if (pLayoutNode->descriptorTypes[i] != pSet->pLayout->descriptorTypes[i]) {
   2373             errorStr << "descriptor " << i << " for descriptorSet being bound is type '"
   2374                      << string_VkDescriptorType(pSet->pLayout->descriptorTypes[i])
   2375                      << "' but corresponding descriptor from pipelineLayout is type '"
   2376                      << string_VkDescriptorType(pLayoutNode->descriptorTypes[i]) << "'";
   2377             errorMsg = errorStr.str();
   2378             return false;
   2379         }
   2380         if (pLayoutNode->stageFlags[i] != pSet->pLayout->stageFlags[i]) {
   2381             errorStr << "stageFlags " << i << " for descriptorSet being bound is " << pSet->pLayout->stageFlags[i]
   2382                      << "' but corresponding descriptor from pipelineLayout has stageFlags " << pLayoutNode->stageFlags[i];
   2383             errorMsg = errorStr.str();
   2384             return false;
   2385         }
   2386     }
   2387     return true;
   2388 }
   2389 
   2390 // Validate that data for each specialization entry is fully contained within the buffer.
   2391 static VkBool32 validate_specialization_offsets(layer_data *my_data, VkPipelineShaderStageCreateInfo const *info) {
   2392     VkBool32 pass = VK_TRUE;
   2393 
   2394     VkSpecializationInfo const *spec = info->pSpecializationInfo;
   2395 
   2396     if (spec) {
   2397         for (auto i = 0u; i < spec->mapEntryCount; i++) {
   2398             if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
   2399                 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2400                             /*dev*/ 0, __LINE__, SHADER_CHECKER_BAD_SPECIALIZATION, "SC",
   2401                             "Specialization entry %u (for constant id %u) references memory outside provided "
   2402                             "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
   2403                             " bytes provided)",
   2404                             i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
   2405                             spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize)) {
   2406 
   2407                     pass = VK_FALSE;
   2408                 }
   2409             }
   2410         }
   2411     }
   2412 
   2413     return pass;
   2414 }
   2415 
   2416 static bool descriptor_type_match(layer_data *my_data, shader_module const *module, uint32_t type_id,
   2417                                   VkDescriptorType descriptor_type, unsigned &descriptor_count) {
   2418     auto type = module->get_def(type_id);
   2419 
   2420     descriptor_count = 1;
   2421 
   2422     /* Strip off any array or ptrs. Where we remove array levels, adjust the
   2423      * descriptor count for each dimension. */
   2424     while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
   2425         if (type.opcode() == spv::OpTypeArray) {
   2426             descriptor_count *= get_constant_value(module, type.word(3));
   2427             type = module->get_def(type.word(2));
   2428         }
   2429         else {
   2430             type = module->get_def(type.word(3));
   2431         }
   2432     }
   2433 
   2434     switch (type.opcode()) {
   2435     case spv::OpTypeStruct: {
   2436         for (auto insn : *module) {
   2437             if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
   2438                 if (insn.word(2) == spv::DecorationBlock) {
   2439                     return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
   2440                            descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
   2441                 } else if (insn.word(2) == spv::DecorationBufferBlock) {
   2442                     return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
   2443                            descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
   2444                 }
   2445             }
   2446         }
   2447 
   2448         /* Invalid */
   2449         return false;
   2450     }
   2451 
   2452     case spv::OpTypeSampler:
   2453         return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER;
   2454 
   2455     case spv::OpTypeSampledImage:
   2456         return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
   2457 
   2458     case spv::OpTypeImage: {
   2459         /* Many descriptor types backing image types-- depends on dimension
   2460          * and whether the image will be used with a sampler. SPIRV for
   2461          * Vulkan requires that sampled be 1 or 2 -- leaving the decision to
   2462          * runtime is unacceptable.
   2463          */
   2464         auto dim = type.word(3);
   2465         auto sampled = type.word(7);
   2466 
   2467         if (dim == spv::DimSubpassData) {
   2468             return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
   2469         } else if (dim == spv::DimBuffer) {
   2470             if (sampled == 1) {
   2471                 return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
   2472             } else {
   2473                 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
   2474             }
   2475         } else if (sampled == 1) {
   2476             return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
   2477         } else {
   2478             return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
   2479         }
   2480     }
   2481 
   2482     /* We shouldn't really see any other junk types -- but if we do, they're
   2483      * a mismatch.
   2484      */
   2485     default:
   2486         return false; /* Mismatch */
   2487     }
   2488 }
   2489 
   2490 static VkBool32 require_feature(layer_data *my_data, VkBool32 feature, char const *feature_name) {
   2491     if (!feature) {
   2492         if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2493                     /* dev */ 0, __LINE__, SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
   2494                     "Shader requires VkPhysicalDeviceFeatures::%s but is not "
   2495                     "enabled on the device",
   2496                     feature_name)) {
   2497             return false;
   2498         }
   2499     }
   2500 
   2501     return true;
   2502 }
   2503 
   2504 static VkBool32 validate_shader_capabilities(layer_data *my_data, VkDevice dev, shader_module const *src)
   2505 {
   2506     VkBool32 pass = VK_TRUE;
   2507 
   2508     auto enabledFeatures = &my_data->physDevProperties.features;
   2509 
   2510     for (auto insn : *src) {
   2511         if (insn.opcode() == spv::OpCapability) {
   2512             switch (insn.word(1)) {
   2513             case spv::CapabilityMatrix:
   2514             case spv::CapabilityShader:
   2515             case spv::CapabilityInputAttachment:
   2516             case spv::CapabilitySampled1D:
   2517             case spv::CapabilityImage1D:
   2518             case spv::CapabilitySampledBuffer:
   2519             case spv::CapabilityImageBuffer:
   2520             case spv::CapabilityImageQuery:
   2521             case spv::CapabilityDerivativeControl:
   2522                 // Always supported by a Vulkan 1.0 implementation -- no feature bits.
   2523                 break;
   2524 
   2525             case spv::CapabilityGeometry:
   2526                 pass &= require_feature(my_data, enabledFeatures->geometryShader, "geometryShader");
   2527                 break;
   2528 
   2529             case spv::CapabilityTessellation:
   2530                 pass &= require_feature(my_data, enabledFeatures->tessellationShader, "tessellationShader");
   2531                 break;
   2532 
   2533             case spv::CapabilityFloat64:
   2534                 pass &= require_feature(my_data, enabledFeatures->shaderFloat64, "shaderFloat64");
   2535                 break;
   2536 
   2537             case spv::CapabilityInt64:
   2538                 pass &= require_feature(my_data, enabledFeatures->shaderInt64, "shaderInt64");
   2539                 break;
   2540 
   2541             case spv::CapabilityTessellationPointSize:
   2542             case spv::CapabilityGeometryPointSize:
   2543                 pass &= require_feature(my_data, enabledFeatures->shaderTessellationAndGeometryPointSize,
   2544                                         "shaderTessellationAndGeometryPointSize");
   2545                 break;
   2546 
   2547             case spv::CapabilityImageGatherExtended:
   2548                 pass &= require_feature(my_data, enabledFeatures->shaderImageGatherExtended, "shaderImageGatherExtended");
   2549                 break;
   2550 
   2551             case spv::CapabilityStorageImageMultisample:
   2552                 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample");
   2553                 break;
   2554 
   2555             case spv::CapabilityUniformBufferArrayDynamicIndexing:
   2556                 pass &= require_feature(my_data, enabledFeatures->shaderUniformBufferArrayDynamicIndexing,
   2557                                         "shaderUniformBufferArrayDynamicIndexing");
   2558                 break;
   2559 
   2560             case spv::CapabilitySampledImageArrayDynamicIndexing:
   2561                 pass &= require_feature(my_data, enabledFeatures->shaderSampledImageArrayDynamicIndexing,
   2562                                         "shaderSampledImageArrayDynamicIndexing");
   2563                 break;
   2564 
   2565             case spv::CapabilityStorageBufferArrayDynamicIndexing:
   2566                 pass &= require_feature(my_data, enabledFeatures->shaderStorageBufferArrayDynamicIndexing,
   2567                                         "shaderStorageBufferArrayDynamicIndexing");
   2568                 break;
   2569 
   2570             case spv::CapabilityStorageImageArrayDynamicIndexing:
   2571                 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageArrayDynamicIndexing,
   2572                                         "shaderStorageImageArrayDynamicIndexing");
   2573                 break;
   2574 
   2575             case spv::CapabilityClipDistance:
   2576                 pass &= require_feature(my_data, enabledFeatures->shaderClipDistance, "shaderClipDistance");
   2577                 break;
   2578 
   2579             case spv::CapabilityCullDistance:
   2580                 pass &= require_feature(my_data, enabledFeatures->shaderCullDistance, "shaderCullDistance");
   2581                 break;
   2582 
   2583             case spv::CapabilityImageCubeArray:
   2584                 pass &= require_feature(my_data, enabledFeatures->imageCubeArray, "imageCubeArray");
   2585                 break;
   2586 
   2587             case spv::CapabilitySampleRateShading:
   2588                 pass &= require_feature(my_data, enabledFeatures->sampleRateShading, "sampleRateShading");
   2589                 break;
   2590 
   2591             case spv::CapabilitySparseResidency:
   2592                 pass &= require_feature(my_data, enabledFeatures->shaderResourceResidency, "shaderResourceResidency");
   2593                 break;
   2594 
   2595             case spv::CapabilityMinLod:
   2596                 pass &= require_feature(my_data, enabledFeatures->shaderResourceMinLod, "shaderResourceMinLod");
   2597                 break;
   2598 
   2599             case spv::CapabilitySampledCubeArray:
   2600                 pass &= require_feature(my_data, enabledFeatures->imageCubeArray, "imageCubeArray");
   2601                 break;
   2602 
   2603             case spv::CapabilityImageMSArray:
   2604                 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample");
   2605                 break;
   2606 
   2607             case spv::CapabilityStorageImageExtendedFormats:
   2608                 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageExtendedFormats,
   2609                                         "shaderStorageImageExtendedFormats");
   2610                 break;
   2611 
   2612             case spv::CapabilityInterpolationFunction:
   2613                 pass &= require_feature(my_data, enabledFeatures->sampleRateShading, "sampleRateShading");
   2614                 break;
   2615 
   2616             case spv::CapabilityStorageImageReadWithoutFormat:
   2617                 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageReadWithoutFormat,
   2618                                         "shaderStorageImageReadWithoutFormat");
   2619                 break;
   2620 
   2621             case spv::CapabilityStorageImageWriteWithoutFormat:
   2622                 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageWriteWithoutFormat,
   2623                                         "shaderStorageImageWriteWithoutFormat");
   2624                 break;
   2625 
   2626             case spv::CapabilityMultiViewport:
   2627                 pass &= require_feature(my_data, enabledFeatures->multiViewport, "multiViewport");
   2628                 break;
   2629 
   2630             default:
   2631                 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /* dev */0,
   2632                             __LINE__, SHADER_CHECKER_BAD_CAPABILITY, "SC",
   2633                             "Shader declares capability %u, not supported in Vulkan.",
   2634                             insn.word(1)))
   2635                     pass = VK_FALSE;
   2636                 break;
   2637             }
   2638         }
   2639     }
   2640 
   2641     return pass;
   2642 }
   2643 
   2644 
   2645 // Validate that the shaders used by the given pipeline
   2646 //  As a side effect this function also records the sets that are actually used by the pipeline
   2647 static VkBool32 validate_pipeline_shaders(layer_data *my_data, VkDevice dev, PIPELINE_NODE *pPipeline) {
   2648     VkGraphicsPipelineCreateInfo const *pCreateInfo = &pPipeline->graphicsPipelineCI;
   2649     /* We seem to allow pipeline stages to be specified out of order, so collect and identify them
   2650      * before trying to do anything more: */
   2651     int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
   2652     int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
   2653 
   2654     shader_module *shaders[5];
   2655     memset(shaders, 0, sizeof(shaders));
   2656     spirv_inst_iter entrypoints[5];
   2657     memset(entrypoints, 0, sizeof(entrypoints));
   2658     RENDER_PASS_NODE const *rp = 0;
   2659     VkPipelineVertexInputStateCreateInfo const *vi = 0;
   2660     VkBool32 pass = VK_TRUE;
   2661 
   2662     for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
   2663         VkPipelineShaderStageCreateInfo const *pStage = &pCreateInfo->pStages[i];
   2664         if (pStage->sType == VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) {
   2665 
   2666             if ((pStage->stage & (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT |
   2667                                   VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) == 0) {
   2668                 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2669                             /*dev*/ 0, __LINE__, SHADER_CHECKER_UNKNOWN_STAGE, "SC", "Unknown shader stage %d", pStage->stage)) {
   2670                     pass = VK_FALSE;
   2671                 }
   2672             } else {
   2673                 pass = validate_specialization_offsets(my_data, pStage) && pass;
   2674 
   2675                 auto stage_id = get_shader_stage_id(pStage->stage);
   2676                 auto module = my_data->shaderModuleMap[pStage->module].get();
   2677                 shaders[stage_id] = module;
   2678 
   2679                 /* find the entrypoint */
   2680                 entrypoints[stage_id] = find_entrypoint(module, pStage->pName, pStage->stage);
   2681                 if (entrypoints[stage_id] == module->end()) {
   2682                     if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2683                                 /*dev*/ 0, __LINE__, SHADER_CHECKER_MISSING_ENTRYPOINT, "SC",
   2684                                 "No entrypoint found named `%s` for stage %s", pStage->pName,
   2685                                 string_VkShaderStageFlagBits(pStage->stage))) {
   2686                         pass = VK_FALSE;
   2687                     }
   2688                 }
   2689 
   2690                 /* validate shader capabilities against enabled device features */
   2691                 pass = validate_shader_capabilities(my_data, dev, module) && pass;
   2692 
   2693                 /* mark accessible ids */
   2694                 std::unordered_set<uint32_t> accessible_ids;
   2695                 mark_accessible_ids(module, entrypoints[stage_id], accessible_ids);
   2696 
   2697                 /* validate descriptor set layout against what the entrypoint actually uses */
   2698                 std::map<descriptor_slot_t, interface_var> descriptor_uses;
   2699                 collect_interface_by_descriptor_slot(my_data, dev, module, accessible_ids, descriptor_uses);
   2700 
   2701                 auto layouts = pCreateInfo->layout != VK_NULL_HANDLE
   2702                                    ? &(my_data->pipelineLayoutMap[pCreateInfo->layout].descriptorSetLayouts)
   2703                                    : nullptr;
   2704 
   2705                 for (auto use : descriptor_uses) {
   2706                     // As a side-effect of this function, capture which sets are used by the pipeline
   2707                     pPipeline->active_sets.insert(use.first.first);
   2708 
   2709                     /* find the matching binding */
   2710                     auto binding = get_descriptor_binding(my_data, layouts, use.first);
   2711                     unsigned required_descriptor_count;
   2712 
   2713                     if (!binding) {
   2714                         if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2715                                     /*dev*/ 0, __LINE__, SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
   2716                                     "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
   2717                                     use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str())) {
   2718                             pass = VK_FALSE;
   2719                         }
   2720                     } else if (~binding->stageFlags & pStage->stage) {
   2721                         if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2722                                     /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
   2723                                     "Shader uses descriptor slot %u.%u (used "
   2724                                     "as type `%s`) but descriptor not "
   2725                                     "accessible from stage %s",
   2726                                     use.first.first, use.first.second,
   2727                                     describe_type(module, use.second.type_id).c_str(),
   2728                                     string_VkShaderStageFlagBits(pStage->stage))) {
   2729                             pass = VK_FALSE;
   2730                         }
   2731                     } else if (!descriptor_type_match(my_data, module, use.second.type_id, binding->descriptorType, /*out*/ required_descriptor_count)) {
   2732                         if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2733                                     /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
   2734                                     "Type mismatch on descriptor slot "
   2735                                     "%u.%u (used as type `%s`) but "
   2736                                     "descriptor of type %s",
   2737                                     use.first.first, use.first.second,
   2738                                     describe_type(module, use.second.type_id).c_str(),
   2739                                     string_VkDescriptorType(binding->descriptorType))) {
   2740                             pass = VK_FALSE;
   2741                         }
   2742                     } else if (binding->descriptorCount < required_descriptor_count) {
   2743                         if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   2744                                     /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
   2745                                     "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
   2746                                     required_descriptor_count, use.first.first, use.first.second,
   2747                                     describe_type(module, use.second.type_id).c_str(),
   2748                                     binding->descriptorCount)) {
   2749                             pass = VK_FALSE;
   2750                         }
   2751                     }
   2752                 }
   2753 
   2754                 /* validate push constant usage */
   2755                 pass =
   2756                     validate_push_constant_usage(my_data, dev, &my_data->pipelineLayoutMap[pCreateInfo->layout].pushConstantRanges,
   2757                                                  module, accessible_ids, pStage->stage) &&
   2758                     pass;
   2759             }
   2760         }
   2761     }
   2762 
   2763     if (pCreateInfo->renderPass != VK_NULL_HANDLE)
   2764         rp = my_data->renderPassMap[pCreateInfo->renderPass];
   2765 
   2766     vi = pCreateInfo->pVertexInputState;
   2767 
   2768     if (vi) {
   2769         pass = validate_vi_consistency(my_data, dev, vi) && pass;
   2770     }
   2771 
   2772     if (shaders[vertex_stage]) {
   2773         pass = validate_vi_against_vs_inputs(my_data, dev, vi, shaders[vertex_stage], entrypoints[vertex_stage]) && pass;
   2774     }
   2775 
   2776     /* TODO: enforce rules about present combinations of shaders */
   2777     int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
   2778     int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
   2779 
   2780     while (!shaders[producer] && producer != fragment_stage) {
   2781         producer++;
   2782         consumer++;
   2783     }
   2784 
   2785     for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
   2786         assert(shaders[producer]);
   2787         if (shaders[consumer]) {
   2788             pass = validate_interface_between_stages(my_data, dev, shaders[producer], entrypoints[producer],
   2789                                                      shader_stage_attribs[producer].name, shaders[consumer], entrypoints[consumer],
   2790                                                      shader_stage_attribs[consumer].name,
   2791                                                      shader_stage_attribs[consumer].arrayed_input) &&
   2792                    pass;
   2793 
   2794             producer = consumer;
   2795         }
   2796     }
   2797 
   2798     if (shaders[fragment_stage] && rp) {
   2799         pass = validate_fs_outputs_against_render_pass(my_data, dev, shaders[fragment_stage], entrypoints[fragment_stage], rp,
   2800                                                        pCreateInfo->subpass) &&
   2801                pass;
   2802     }
   2803 
   2804     return pass;
   2805 }
   2806 
   2807 // Return Set node ptr for specified set or else NULL
   2808 static SET_NODE *getSetNode(layer_data *my_data, const VkDescriptorSet set) {
   2809     if (my_data->setMap.find(set) == my_data->setMap.end()) {
   2810         return NULL;
   2811     }
   2812     return my_data->setMap[set];
   2813 }
   2814 // For the given command buffer, verify that for each set set in activeSetNodes
   2815 //  that any dynamic descriptor in that set has a valid dynamic offset bound.
   2816 //  To be valid, the dynamic offset combined with the offset and range from its
   2817 //  descriptor update must not overflow the size of its buffer being updated
   2818 static VkBool32 validate_dynamic_offsets(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const vector<SET_NODE *> activeSetNodes) {
   2819     VkBool32 result = VK_FALSE;
   2820 
   2821     VkWriteDescriptorSet *pWDS = NULL;
   2822     uint32_t dynOffsetIndex = 0;
   2823     VkDeviceSize bufferSize = 0;
   2824     for (auto set_node : activeSetNodes) {
   2825         for (uint32_t i = 0; i < set_node->descriptorCount; ++i) {
   2826             // TODO: Add validation for descriptors dynamically skipped in shader
   2827             if (set_node->ppDescriptors[i] != NULL) {
   2828                 switch (set_node->ppDescriptors[i]->sType) {
   2829                 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
   2830                     pWDS = (VkWriteDescriptorSet *)set_node->ppDescriptors[i];
   2831                     if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
   2832                         (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
   2833                         for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
   2834                             bufferSize = my_data->bufferMap[pWDS->pBufferInfo[j].buffer].create_info->size;
   2835                             uint32_t dynOffset = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].dynamicOffsets[dynOffsetIndex];
   2836                             if (pWDS->pBufferInfo[j].range == VK_WHOLE_SIZE) {
   2837                                 if ((dynOffset + pWDS->pBufferInfo[j].offset) > bufferSize) {
   2838                                     result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   2839                                                       VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   2840                                                       reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
   2841                                                       DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
   2842                                                       "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has range of "
   2843                                                       "VK_WHOLE_SIZE but dynamic offset %#" PRIxLEAST32 ". "
   2844                                                       "combined with offset %#" PRIxLEAST64 " oversteps its buffer (%#" PRIxLEAST64
   2845                                                       ") which has a size of %#" PRIxLEAST64 ".",
   2846                                                       reinterpret_cast<const uint64_t &>(set_node->set), i,
   2847                                                       pCB->dynamicOffsets[dynOffsetIndex], pWDS->pBufferInfo[j].offset,
   2848                                                       reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
   2849                                 }
   2850                             } else if ((dynOffset + pWDS->pBufferInfo[j].offset + pWDS->pBufferInfo[j].range) > bufferSize) {
   2851                                 result |= log_msg(
   2852                                     my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   2853                                     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   2854                                     reinterpret_cast<const uint64_t &>(set_node->set), __LINE__, DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW,
   2855                                     "DS",
   2856                                     "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has dynamic offset %#" PRIxLEAST32 ". "
   2857                                     "Combined with offset %#" PRIxLEAST64 " and range %#" PRIxLEAST64
   2858                                     " from its update, this oversteps its buffer "
   2859                                     "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".",
   2860                                     reinterpret_cast<const uint64_t &>(set_node->set), i, pCB->dynamicOffsets[dynOffsetIndex],
   2861                                     pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range,
   2862                                     reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
   2863                             } else if ((dynOffset + pWDS->pBufferInfo[j].offset + pWDS->pBufferInfo[j].range) > bufferSize) {
   2864                                 result |= log_msg(
   2865                                     my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   2866                                     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   2867                                     reinterpret_cast<const uint64_t &>(set_node->set), __LINE__, DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW,
   2868                                     "DS",
   2869                                     "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has dynamic offset %#" PRIxLEAST32 ". "
   2870                                     "Combined with offset %#" PRIxLEAST64 " and range %#" PRIxLEAST64
   2871                                     " from its update, this oversteps its buffer "
   2872                                     "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".",
   2873                                     reinterpret_cast<const uint64_t &>(set_node->set), i, pCB->dynamicOffsets[dynOffsetIndex],
   2874                                     pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range,
   2875                                     reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
   2876                             }
   2877                             dynOffsetIndex++;
   2878                             i += j; // Advance i to end of this set of descriptors (++i at end of for loop will move 1 index past
   2879                                     // last of these descriptors)
   2880                         }
   2881                     }
   2882                     break;
   2883                 default: // Currently only shadowing Write update nodes so shouldn't get here
   2884                     assert(0);
   2885                     continue;
   2886                 }
   2887             }
   2888         }
   2889     }
   2890     return result;
   2891 }
   2892 
   2893 // Validate overall state at the time of a draw call
   2894 static VkBool32 validate_draw_state(layer_data *my_data, GLOBAL_CB_NODE *pCB, VkBool32 indexedDraw) {
   2895     // First check flag states
   2896     VkBool32 result = validate_draw_state_flags(my_data, pCB, indexedDraw);
   2897     PIPELINE_NODE *pPipe = getPipeline(my_data, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
   2898     // Now complete other state checks
   2899     // TODO : Currently only performing next check if *something* was bound (non-zero last bound)
   2900     //  There is probably a better way to gate when this check happens, and to know if something *should* have been bound
   2901     //  We should have that check separately and then gate this check based on that check
   2902     if (pPipe) {
   2903         auto const &state = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS];
   2904         if (state.pipelineLayout) {
   2905             string errorString;
   2906             // Need a vector (vs. std::set) of active Sets for dynamicOffset validation in case same set bound w/ different offsets
   2907             vector<SET_NODE *> activeSetNodes;
   2908             for (auto setIndex : pPipe->active_sets) {
   2909                 // If valid set is not bound throw an error
   2910                 if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
   2911                     result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   2912                                       __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
   2913                                       "VkPipeline %#" PRIxLEAST64 " uses set #%u but that set is not bound.",
   2914                                       (uint64_t)pPipe->pipeline, setIndex);
   2915                 } else if (!verify_set_layout_compatibility(my_data, my_data->setMap[state.boundDescriptorSets[setIndex]],
   2916                                                             pPipe->graphicsPipelineCI.layout, setIndex, errorString)) {
   2917                     // Set is bound but not compatible w/ overlapping pipelineLayout from PSO
   2918                     VkDescriptorSet setHandle = my_data->setMap[state.boundDescriptorSets[setIndex]]->set;
   2919                     result |= log_msg(
   2920                         my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   2921                         (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
   2922                         "VkDescriptorSet (%#" PRIxLEAST64
   2923                         ") bound as set #%u is not compatible with overlapping VkPipelineLayout %#" PRIxLEAST64 " due to: %s",
   2924                         (uint64_t)setHandle, setIndex, (uint64_t)pPipe->graphicsPipelineCI.layout, errorString.c_str());
   2925                 } else { // Valid set is bound and layout compatible, validate that it's updated and verify any dynamic offsets
   2926                     // Pull the set node
   2927                     SET_NODE *pSet = my_data->setMap[state.boundDescriptorSets[setIndex]];
   2928                     // Save vector of all active sets to verify dynamicOffsets below
   2929                     activeSetNodes.push_back(pSet);
   2930                     // Make sure set has been updated
   2931                     if (!pSet->pUpdateStructs) {
   2932                         result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   2933                                           VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pSet->set, __LINE__,
   2934                                           DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
   2935                                           "DS %#" PRIxLEAST64 " bound but it was never updated. It is now being used to draw so "
   2936                                                               "this will result in undefined behavior.",
   2937                                           (uint64_t)pSet->set);
   2938                     }
   2939                 }
   2940             }
   2941             // For each dynamic descriptor, make sure dynamic offset doesn't overstep buffer
   2942             if (!state.dynamicOffsets.empty())
   2943                 result |= validate_dynamic_offsets(my_data, pCB, activeSetNodes);
   2944         }
   2945         // Verify Vtx binding
   2946         if (pPipe->vertexBindingDescriptions.size() > 0) {
   2947             for (size_t i = 0; i < pPipe->vertexBindingDescriptions.size(); i++) {
   2948                 if ((pCB->currentDrawData.buffers.size() < (i + 1)) || (pCB->currentDrawData.buffers[i] == VK_NULL_HANDLE)) {
   2949                     result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   2950                                       __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
   2951                                       "The Pipeline State Object (%#" PRIxLEAST64
   2952                                       ") expects that this Command Buffer's vertex binding Index " PRINTF_SIZE_T_SPECIFIER
   2953                                       " should be set via vkCmdBindVertexBuffers.",
   2954                                       (uint64_t)pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline, i);
   2955                 }
   2956             }
   2957         } else {
   2958             if (!pCB->currentDrawData.buffers.empty()) {
   2959                 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
   2960                                   0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
   2961                                   "Vertex buffers are bound to command buffer (%#" PRIxLEAST64
   2962                                   ") but no vertex buffers are attached to this Pipeline State Object (%#" PRIxLEAST64 ").",
   2963                                   (uint64_t)pCB->commandBuffer, (uint64_t)pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
   2964             }
   2965         }
   2966         // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
   2967         // Skip check if rasterization is disabled or there is no viewport.
   2968         if ((!pPipe->graphicsPipelineCI.pRasterizationState ||
   2969              !pPipe->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) &&
   2970             pPipe->graphicsPipelineCI.pViewportState) {
   2971             VkBool32 dynViewport = isDynamic(pPipe, VK_DYNAMIC_STATE_VIEWPORT);
   2972             VkBool32 dynScissor = isDynamic(pPipe, VK_DYNAMIC_STATE_SCISSOR);
   2973             if (dynViewport) {
   2974                 if (pCB->viewports.size() != pPipe->graphicsPipelineCI.pViewportState->viewportCount) {
   2975                     result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   2976                                       __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
   2977                                       "Dynamic viewportCount from vkCmdSetViewport() is " PRINTF_SIZE_T_SPECIFIER
   2978                                       ", but PSO viewportCount is %u. These counts must match.",
   2979                                       pCB->viewports.size(), pPipe->graphicsPipelineCI.pViewportState->viewportCount);
   2980                 }
   2981             }
   2982             if (dynScissor) {
   2983                 if (pCB->scissors.size() != pPipe->graphicsPipelineCI.pViewportState->scissorCount) {
   2984                     result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   2985                                       __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
   2986                                       "Dynamic scissorCount from vkCmdSetScissor() is " PRINTF_SIZE_T_SPECIFIER
   2987                                       ", but PSO scissorCount is %u. These counts must match.",
   2988                                       pCB->scissors.size(), pPipe->graphicsPipelineCI.pViewportState->scissorCount);
   2989                 }
   2990             }
   2991         }
   2992     }
   2993     return result;
   2994 }
   2995 
   2996 // Verify that create state for a pipeline is valid
   2997 static VkBool32 verifyPipelineCreateState(layer_data *my_data, const VkDevice device, std::vector<PIPELINE_NODE *> pPipelines,
   2998                                           int pipelineIndex) {
   2999     VkBool32 skipCall = VK_FALSE;
   3000 
   3001     PIPELINE_NODE *pPipeline = pPipelines[pipelineIndex];
   3002 
   3003     // If create derivative bit is set, check that we've specified a base
   3004     // pipeline correctly, and that the base pipeline was created to allow
   3005     // derivatives.
   3006     if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
   3007         PIPELINE_NODE *pBasePipeline = nullptr;
   3008         if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
   3009               (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
   3010             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3011                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
   3012                                 "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
   3013         } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
   3014             if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
   3015                 skipCall |=
   3016                     log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3017                             DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
   3018                             "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline.");
   3019             } else {
   3020                 pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
   3021             }
   3022         } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
   3023             pBasePipeline = getPipeline(my_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
   3024         }
   3025 
   3026         if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
   3027             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3028                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
   3029                                 "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
   3030         }
   3031     }
   3032 
   3033     if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
   3034         if (!my_data->physDevProperties.features.independentBlend) {
   3035             if (pPipeline->attachments.size() > 0) {
   3036                 VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
   3037                 for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
   3038                     if ((pAttachments[0].blendEnable != pAttachments[i].blendEnable) ||
   3039                         (pAttachments[0].srcColorBlendFactor != pAttachments[i].srcColorBlendFactor) ||
   3040                         (pAttachments[0].dstColorBlendFactor != pAttachments[i].dstColorBlendFactor) ||
   3041                         (pAttachments[0].colorBlendOp != pAttachments[i].colorBlendOp) ||
   3042                         (pAttachments[0].srcAlphaBlendFactor != pAttachments[i].srcAlphaBlendFactor) ||
   3043                         (pAttachments[0].dstAlphaBlendFactor != pAttachments[i].dstAlphaBlendFactor) ||
   3044                         (pAttachments[0].alphaBlendOp != pAttachments[i].alphaBlendOp) ||
   3045                         (pAttachments[0].colorWriteMask != pAttachments[i].colorWriteMask)) {
   3046                         skipCall |=
   3047                             log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3048                             DRAWSTATE_INDEPENDENT_BLEND, "DS", "Invalid Pipeline CreateInfo: If independent blend feature not "
   3049                             "enabled, all elements of pAttachments must be identical");
   3050                     }
   3051                 }
   3052             }
   3053         }
   3054         if (!my_data->physDevProperties.features.logicOp &&
   3055             (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
   3056             skipCall |=
   3057                 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3058                         DRAWSTATE_DISABLED_LOGIC_OP, "DS",
   3059                         "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE");
   3060         }
   3061         if ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable == VK_TRUE) &&
   3062             ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOp < VK_LOGIC_OP_CLEAR) ||
   3063              (pPipeline->graphicsPipelineCI.pColorBlendState->logicOp > VK_LOGIC_OP_SET))) {
   3064             skipCall |=
   3065                 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3066                         DRAWSTATE_INVALID_LOGIC_OP, "DS",
   3067                         "Invalid Pipeline CreateInfo: If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value");
   3068         }
   3069     }
   3070 
   3071     // Ensure the subpass index is valid. If not, then validate_pipeline_shaders
   3072     // produces nonsense errors that confuse users. Other layers should already
   3073     // emit errors for renderpass being invalid.
   3074     auto rp_data = my_data->renderPassMap.find(pPipeline->graphicsPipelineCI.renderPass);
   3075     if (rp_data != my_data->renderPassMap.end() &&
   3076         pPipeline->graphicsPipelineCI.subpass >= rp_data->second->pCreateInfo->subpassCount) {
   3077         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3078                             DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Subpass index %u "
   3079                                                                            "is out of range for this renderpass (0..%u)",
   3080                             pPipeline->graphicsPipelineCI.subpass, rp_data->second->pCreateInfo->subpassCount - 1);
   3081     }
   3082 
   3083     if (!validate_pipeline_shaders(my_data, device, pPipeline)) {
   3084         skipCall = VK_TRUE;
   3085     }
   3086     // VS is required
   3087     if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
   3088         skipCall |=
   3089             log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3090                     DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Vtx Shader required");
   3091     }
   3092     // Either both or neither TC/TE shaders should be defined
   3093     if (((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) == 0) !=
   3094         ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) == 0)) {
   3095         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3096                             DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
   3097                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair");
   3098     }
   3099     // Compute shaders should be specified independent of Gfx shaders
   3100     if ((pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) &&
   3101         (pPipeline->active_shaders &
   3102          (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT |
   3103           VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT))) {
   3104         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3105                             DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
   3106                             "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline");
   3107     }
   3108     // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
   3109     // Mismatching primitive topology and tessellation fails graphics pipeline creation.
   3110     if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
   3111         (pPipeline->iaStateCI.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
   3112         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3113                             DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
   3114                                                                            "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
   3115                                                                            "topology for tessellation pipelines");
   3116     }
   3117     if (pPipeline->iaStateCI.topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
   3118         if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
   3119             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3120                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
   3121                                                                                "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
   3122                                                                                "topology is only valid for tessellation pipelines");
   3123         }
   3124         if (!pPipeline->tessStateCI.patchControlPoints || (pPipeline->tessStateCI.patchControlPoints > 32)) {
   3125             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3126                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
   3127                                                                                "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
   3128                                                                                "topology used with patchControlPoints value %u."
   3129                                                                                " patchControlPoints should be >0 and <=32.",
   3130                                 pPipeline->tessStateCI.patchControlPoints);
   3131         }
   3132     }
   3133     // Viewport state must be included if rasterization is enabled.
   3134     // If the viewport state is included, the viewport and scissor counts should always match.
   3135     // NOTE : Even if these are flagged as dynamic, counts need to be set correctly for shader compiler
   3136     if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
   3137         !pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) {
   3138         if (!pPipeline->graphicsPipelineCI.pViewportState) {
   3139             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3140                                 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "Gfx Pipeline pViewportState is null. Even if viewport "
   3141                                                                            "and scissors are dynamic PSO must include "
   3142                                                                            "viewportCount and scissorCount in pViewportState.");
   3143         } else if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount !=
   3144                    pPipeline->graphicsPipelineCI.pViewportState->viewportCount) {
   3145             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3146                                 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
   3147                                 "Gfx Pipeline viewport count (%u) must match scissor count (%u).",
   3148                                 pPipeline->vpStateCI.viewportCount, pPipeline->vpStateCI.scissorCount);
   3149         } else {
   3150             // If viewport or scissor are not dynamic, then verify that data is appropriate for count
   3151             VkBool32 dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
   3152             VkBool32 dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
   3153             if (!dynViewport) {
   3154                 if (pPipeline->graphicsPipelineCI.pViewportState->viewportCount &&
   3155                     !pPipeline->graphicsPipelineCI.pViewportState->pViewports) {
   3156                     skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   3157                                         __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
   3158                                         "Gfx Pipeline viewportCount is %u, but pViewports is NULL. For non-zero viewportCount, you "
   3159                                         "must either include pViewports data, or include viewport in pDynamicState and set it with "
   3160                                         "vkCmdSetViewport().",
   3161                                         pPipeline->graphicsPipelineCI.pViewportState->viewportCount);
   3162                 }
   3163             }
   3164             if (!dynScissor) {
   3165                 if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount &&
   3166                     !pPipeline->graphicsPipelineCI.pViewportState->pScissors) {
   3167                     skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   3168                                         __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
   3169                                         "Gfx Pipeline scissorCount is %u, but pScissors is NULL. For non-zero scissorCount, you "
   3170                                         "must either include pScissors data, or include scissor in pDynamicState and set it with "
   3171                                         "vkCmdSetScissor().",
   3172                                         pPipeline->graphicsPipelineCI.pViewportState->scissorCount);
   3173                 }
   3174             }
   3175         }
   3176     }
   3177     return skipCall;
   3178 }
   3179 
   3180 // Init the pipeline mapping info based on pipeline create info LL tree
   3181 //  Threading note : Calls to this function should wrapped in mutex
   3182 // TODO : this should really just be in the constructor for PIPELINE_NODE
   3183 static PIPELINE_NODE *initGraphicsPipeline(layer_data *dev_data, const VkGraphicsPipelineCreateInfo *pCreateInfo) {
   3184     PIPELINE_NODE *pPipeline = new PIPELINE_NODE;
   3185 
   3186     // First init create info
   3187     memcpy(&pPipeline->graphicsPipelineCI, pCreateInfo, sizeof(VkGraphicsPipelineCreateInfo));
   3188 
   3189     size_t bufferSize = 0;
   3190     const VkPipelineVertexInputStateCreateInfo *pVICI = NULL;
   3191     const VkPipelineColorBlendStateCreateInfo *pCBCI = NULL;
   3192 
   3193     for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
   3194         const VkPipelineShaderStageCreateInfo *pPSSCI = &pCreateInfo->pStages[i];
   3195 
   3196         switch (pPSSCI->stage) {
   3197         case VK_SHADER_STAGE_VERTEX_BIT:
   3198             memcpy(&pPipeline->vsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
   3199             pPipeline->active_shaders |= VK_SHADER_STAGE_VERTEX_BIT;
   3200             break;
   3201         case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
   3202             memcpy(&pPipeline->tcsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
   3203             pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
   3204             break;
   3205         case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
   3206             memcpy(&pPipeline->tesCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
   3207             pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
   3208             break;
   3209         case VK_SHADER_STAGE_GEOMETRY_BIT:
   3210             memcpy(&pPipeline->gsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
   3211             pPipeline->active_shaders |= VK_SHADER_STAGE_GEOMETRY_BIT;
   3212             break;
   3213         case VK_SHADER_STAGE_FRAGMENT_BIT:
   3214             memcpy(&pPipeline->fsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
   3215             pPipeline->active_shaders |= VK_SHADER_STAGE_FRAGMENT_BIT;
   3216             break;
   3217         case VK_SHADER_STAGE_COMPUTE_BIT:
   3218             // TODO : Flag error, CS is specified through VkComputePipelineCreateInfo
   3219             pPipeline->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT;
   3220             break;
   3221         default:
   3222             // TODO : Flag error
   3223             break;
   3224         }
   3225     }
   3226     // Copy over GraphicsPipelineCreateInfo structure embedded pointers
   3227     if (pCreateInfo->stageCount != 0) {
   3228         pPipeline->graphicsPipelineCI.pStages = new VkPipelineShaderStageCreateInfo[pCreateInfo->stageCount];
   3229         bufferSize = pCreateInfo->stageCount * sizeof(VkPipelineShaderStageCreateInfo);
   3230         memcpy((void *)pPipeline->graphicsPipelineCI.pStages, pCreateInfo->pStages, bufferSize);
   3231     }
   3232     if (pCreateInfo->pVertexInputState != NULL) {
   3233         pPipeline->vertexInputCI = *pCreateInfo->pVertexInputState;
   3234         // Copy embedded ptrs
   3235         pVICI = pCreateInfo->pVertexInputState;
   3236         if (pVICI->vertexBindingDescriptionCount) {
   3237             pPipeline->vertexBindingDescriptions = std::vector<VkVertexInputBindingDescription>(
   3238                 pVICI->pVertexBindingDescriptions, pVICI->pVertexBindingDescriptions + pVICI->vertexBindingDescriptionCount);
   3239         }
   3240         if (pVICI->vertexAttributeDescriptionCount) {
   3241             pPipeline->vertexAttributeDescriptions = std::vector<VkVertexInputAttributeDescription>(
   3242                 pVICI->pVertexAttributeDescriptions, pVICI->pVertexAttributeDescriptions + pVICI->vertexAttributeDescriptionCount);
   3243         }
   3244         pPipeline->graphicsPipelineCI.pVertexInputState = &pPipeline->vertexInputCI;
   3245     }
   3246     if (pCreateInfo->pInputAssemblyState != NULL) {
   3247         pPipeline->iaStateCI = *pCreateInfo->pInputAssemblyState;
   3248         pPipeline->graphicsPipelineCI.pInputAssemblyState = &pPipeline->iaStateCI;
   3249     }
   3250     if (pCreateInfo->pTessellationState != NULL) {
   3251         pPipeline->tessStateCI = *pCreateInfo->pTessellationState;
   3252         pPipeline->graphicsPipelineCI.pTessellationState = &pPipeline->tessStateCI;
   3253     }
   3254     if (pCreateInfo->pViewportState != NULL) {
   3255         pPipeline->vpStateCI = *pCreateInfo->pViewportState;
   3256         pPipeline->graphicsPipelineCI.pViewportState = &pPipeline->vpStateCI;
   3257     }
   3258     if (pCreateInfo->pRasterizationState != NULL) {
   3259         pPipeline->rsStateCI = *pCreateInfo->pRasterizationState;
   3260         pPipeline->graphicsPipelineCI.pRasterizationState = &pPipeline->rsStateCI;
   3261     }
   3262     if (pCreateInfo->pMultisampleState != NULL) {
   3263         pPipeline->msStateCI = *pCreateInfo->pMultisampleState;
   3264         pPipeline->graphicsPipelineCI.pMultisampleState = &pPipeline->msStateCI;
   3265     }
   3266     if (pCreateInfo->pDepthStencilState != NULL) {
   3267         pPipeline->dsStateCI = *pCreateInfo->pDepthStencilState;
   3268         pPipeline->graphicsPipelineCI.pDepthStencilState = &pPipeline->dsStateCI;
   3269     }
   3270     if (pCreateInfo->pColorBlendState != NULL) {
   3271         pPipeline->cbStateCI = *pCreateInfo->pColorBlendState;
   3272         // Copy embedded ptrs
   3273         pCBCI = pCreateInfo->pColorBlendState;
   3274         if (pCBCI->attachmentCount) {
   3275             pPipeline->attachments = std::vector<VkPipelineColorBlendAttachmentState>(
   3276                 pCBCI->pAttachments, pCBCI->pAttachments + pCBCI->attachmentCount);
   3277         }
   3278         pPipeline->graphicsPipelineCI.pColorBlendState = &pPipeline->cbStateCI;
   3279     }
   3280     if (pCreateInfo->pDynamicState != NULL) {
   3281         pPipeline->dynStateCI = *pCreateInfo->pDynamicState;
   3282         if (pPipeline->dynStateCI.dynamicStateCount) {
   3283             pPipeline->dynStateCI.pDynamicStates = new VkDynamicState[pPipeline->dynStateCI.dynamicStateCount];
   3284             bufferSize = pPipeline->dynStateCI.dynamicStateCount * sizeof(VkDynamicState);
   3285             memcpy((void *)pPipeline->dynStateCI.pDynamicStates, pCreateInfo->pDynamicState->pDynamicStates, bufferSize);
   3286         }
   3287         pPipeline->graphicsPipelineCI.pDynamicState = &pPipeline->dynStateCI;
   3288     }
   3289     return pPipeline;
   3290 }
   3291 
   3292 // Free the Pipeline nodes
   3293 static void deletePipelines(layer_data *my_data) {
   3294     if (my_data->pipelineMap.size() <= 0)
   3295         return;
   3296     for (auto ii = my_data->pipelineMap.begin(); ii != my_data->pipelineMap.end(); ++ii) {
   3297         if ((*ii).second->graphicsPipelineCI.stageCount != 0) {
   3298             delete[](*ii).second->graphicsPipelineCI.pStages;
   3299         }
   3300         if ((*ii).second->dynStateCI.dynamicStateCount != 0) {
   3301             delete[](*ii).second->dynStateCI.pDynamicStates;
   3302         }
   3303         delete (*ii).second;
   3304     }
   3305     my_data->pipelineMap.clear();
   3306 }
   3307 
   3308 // For given pipeline, return number of MSAA samples, or one if MSAA disabled
   3309 static VkSampleCountFlagBits getNumSamples(layer_data *my_data, const VkPipeline pipeline) {
   3310     PIPELINE_NODE *pPipe = my_data->pipelineMap[pipeline];
   3311     if (VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pPipe->msStateCI.sType) {
   3312         return pPipe->msStateCI.rasterizationSamples;
   3313     }
   3314     return VK_SAMPLE_COUNT_1_BIT;
   3315 }
   3316 
   3317 // Validate state related to the PSO
   3318 static VkBool32 validatePipelineState(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const VkPipelineBindPoint pipelineBindPoint,
   3319                                       const VkPipeline pipeline) {
   3320     if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
   3321         // Verify that any MSAA request in PSO matches sample# in bound FB
   3322         // Skip the check if rasterization is disabled.
   3323         PIPELINE_NODE *pPipeline = my_data->pipelineMap[pipeline];
   3324         if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
   3325             !pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) {
   3326             VkSampleCountFlagBits psoNumSamples = getNumSamples(my_data, pipeline);
   3327             if (pCB->activeRenderPass) {
   3328                 const VkRenderPassCreateInfo *pRPCI = my_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo;
   3329                 const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass];
   3330                 VkSampleCountFlagBits subpassNumSamples = (VkSampleCountFlagBits)0;
   3331                 uint32_t i;
   3332 
   3333                 for (i = 0; i < pSD->colorAttachmentCount; i++) {
   3334                     VkSampleCountFlagBits samples;
   3335 
   3336                     if (pSD->pColorAttachments[i].attachment == VK_ATTACHMENT_UNUSED)
   3337                         continue;
   3338 
   3339                     samples = pRPCI->pAttachments[pSD->pColorAttachments[i].attachment].samples;
   3340                     if (subpassNumSamples == (VkSampleCountFlagBits)0) {
   3341                         subpassNumSamples = samples;
   3342                     } else if (subpassNumSamples != samples) {
   3343                         subpassNumSamples = (VkSampleCountFlagBits)-1;
   3344                         break;
   3345                     }
   3346                 }
   3347                 if (pSD->pDepthStencilAttachment && pSD->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
   3348                     const VkSampleCountFlagBits samples = pRPCI->pAttachments[pSD->pDepthStencilAttachment->attachment].samples;
   3349                     if (subpassNumSamples == (VkSampleCountFlagBits)0)
   3350                         subpassNumSamples = samples;
   3351                     else if (subpassNumSamples != samples)
   3352                         subpassNumSamples = (VkSampleCountFlagBits)-1;
   3353                 }
   3354 
   3355                 if (psoNumSamples != subpassNumSamples) {
   3356                     return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
   3357                                    (uint64_t)pipeline, __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
   3358                                    "Num samples mismatch! Binding PSO (%#" PRIxLEAST64
   3359                                    ") with %u samples while current RenderPass (%#" PRIxLEAST64 ") w/ %u samples!",
   3360                                    (uint64_t)pipeline, psoNumSamples, (uint64_t)pCB->activeRenderPass, subpassNumSamples);
   3361                 }
   3362             } else {
   3363                 // TODO : I believe it's an error if we reach this point and don't have an activeRenderPass
   3364                 //   Verify and flag error as appropriate
   3365             }
   3366         }
   3367         // TODO : Add more checks here
   3368     } else {
   3369         // TODO : Validate non-gfx pipeline updates
   3370     }
   3371     return VK_FALSE;
   3372 }
   3373 
   3374 // Block of code at start here specifically for managing/tracking DSs
   3375 
   3376 // Return Pool node ptr for specified pool or else NULL
   3377 static DESCRIPTOR_POOL_NODE *getPoolNode(layer_data *my_data, const VkDescriptorPool pool) {
   3378     if (my_data->descriptorPoolMap.find(pool) == my_data->descriptorPoolMap.end()) {
   3379         return NULL;
   3380     }
   3381     return my_data->descriptorPoolMap[pool];
   3382 }
   3383 
   3384 static LAYOUT_NODE *getLayoutNode(layer_data *my_data, const VkDescriptorSetLayout layout) {
   3385     if (my_data->descriptorSetLayoutMap.find(layout) == my_data->descriptorSetLayoutMap.end()) {
   3386         return NULL;
   3387     }
   3388     return my_data->descriptorSetLayoutMap[layout];
   3389 }
   3390 
   3391 // Return VK_FALSE if update struct is of valid type, otherwise flag error and return code from callback
   3392 static VkBool32 validUpdateStruct(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
   3393     switch (pUpdateStruct->sType) {
   3394     case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
   3395     case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
   3396         return VK_FALSE;
   3397     default:
   3398         return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3399                        DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
   3400                        "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
   3401                        string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
   3402     }
   3403 }
   3404 
   3405 // Set count for given update struct in the last parameter
   3406 // Return value of skipCall, which is only VK_TRUE if error occurs and callback signals execution to cease
   3407 static uint32_t getUpdateCount(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
   3408     switch (pUpdateStruct->sType) {
   3409     case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
   3410         return ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorCount;
   3411     case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
   3412         // TODO : Need to understand this case better and make sure code is correct
   3413         return ((VkCopyDescriptorSet *)pUpdateStruct)->descriptorCount;
   3414     default:
   3415         return 0;
   3416     }
   3417     return 0;
   3418 }
   3419 
   3420 // For given Layout Node and binding, return index where that binding begins
   3421 static uint32_t getBindingStartIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) {
   3422     uint32_t offsetIndex = 0;
   3423     for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) {
   3424         if (pLayout->createInfo.pBindings[i].binding == binding)
   3425             break;
   3426         offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount;
   3427     }
   3428     return offsetIndex;
   3429 }
   3430 
   3431 // For given layout node and binding, return last index that is updated
   3432 static uint32_t getBindingEndIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) {
   3433     uint32_t offsetIndex = 0;
   3434     for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) {
   3435         offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount;
   3436         if (pLayout->createInfo.pBindings[i].binding == binding)
   3437             break;
   3438     }
   3439     return offsetIndex - 1;
   3440 }
   3441 
   3442 // For given layout and update, return the first overall index of the layout that is updated
   3443 static uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding,
   3444                                     const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
   3445     return getBindingStartIndex(pLayout, binding) + arrayIndex;
   3446 }
   3447 
   3448 // For given layout and update, return the last overall index of the layout that is updated
   3449 static uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding,
   3450                                   const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
   3451     uint32_t count = getUpdateCount(my_data, device, pUpdateStruct);
   3452     return getBindingStartIndex(pLayout, binding) + arrayIndex + count - 1;
   3453 }
   3454 
   3455 // Verify that the descriptor type in the update struct matches what's expected by the layout
   3456 static VkBool32 validateUpdateConsistency(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout,
   3457                                           const GENERIC_HEADER *pUpdateStruct, uint32_t startIndex, uint32_t endIndex) {
   3458     // First get actual type of update
   3459     VkBool32 skipCall = VK_FALSE;
   3460     VkDescriptorType actualType;
   3461     uint32_t i = 0;
   3462     switch (pUpdateStruct->sType) {
   3463     case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
   3464         actualType = ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorType;
   3465         break;
   3466     case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
   3467         /* no need to validate */
   3468         return VK_FALSE;
   3469         break;
   3470     default:
   3471         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3472                             DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
   3473                             "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
   3474                             string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
   3475     }
   3476     if (VK_FALSE == skipCall) {
   3477         // Set first stageFlags as reference and verify that all other updates match it
   3478         VkShaderStageFlags refStageFlags = pLayout->stageFlags[startIndex];
   3479         for (i = startIndex; i <= endIndex; i++) {
   3480             if (pLayout->descriptorTypes[i] != actualType) {
   3481                 skipCall |= log_msg(
   3482                     my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3483                     DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
   3484                     "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!",
   3485                     string_VkDescriptorType(actualType), string_VkDescriptorType(pLayout->descriptorTypes[i]));
   3486             }
   3487             if (pLayout->stageFlags[i] != refStageFlags) {
   3488                 skipCall |= log_msg(
   3489                     my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3490                     DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH, "DS",
   3491                     "Write descriptor update has stageFlags %x that do not match overlapping binding descriptor stageFlags of %x!",
   3492                     refStageFlags, pLayout->stageFlags[i]);
   3493             }
   3494         }
   3495     }
   3496     return skipCall;
   3497 }
   3498 
   3499 // Determine the update type, allocate a new struct of that type, shadow the given pUpdate
   3500 //   struct into the pNewNode param. Return VK_TRUE if error condition encountered and callback signals early exit.
   3501 // NOTE : Calls to this function should be wrapped in mutex
   3502 static VkBool32 shadowUpdateNode(layer_data *my_data, const VkDevice device, GENERIC_HEADER *pUpdate, GENERIC_HEADER **pNewNode) {
   3503     VkBool32 skipCall = VK_FALSE;
   3504     VkWriteDescriptorSet *pWDS = NULL;
   3505     VkCopyDescriptorSet *pCDS = NULL;
   3506     switch (pUpdate->sType) {
   3507     case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
   3508         pWDS = new VkWriteDescriptorSet;
   3509         *pNewNode = (GENERIC_HEADER *)pWDS;
   3510         memcpy(pWDS, pUpdate, sizeof(VkWriteDescriptorSet));
   3511 
   3512         switch (pWDS->descriptorType) {
   3513         case VK_DESCRIPTOR_TYPE_SAMPLER:
   3514         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
   3515         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
   3516         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
   3517             VkDescriptorImageInfo *info = new VkDescriptorImageInfo[pWDS->descriptorCount];
   3518             memcpy(info, pWDS->pImageInfo, pWDS->descriptorCount * sizeof(VkDescriptorImageInfo));
   3519             pWDS->pImageInfo = info;
   3520         } break;
   3521         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
   3522         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
   3523             VkBufferView *info = new VkBufferView[pWDS->descriptorCount];
   3524             memcpy(info, pWDS->pTexelBufferView, pWDS->descriptorCount * sizeof(VkBufferView));
   3525             pWDS->pTexelBufferView = info;
   3526         } break;
   3527         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
   3528         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
   3529         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
   3530         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
   3531             VkDescriptorBufferInfo *info = new VkDescriptorBufferInfo[pWDS->descriptorCount];
   3532             memcpy(info, pWDS->pBufferInfo, pWDS->descriptorCount * sizeof(VkDescriptorBufferInfo));
   3533             pWDS->pBufferInfo = info;
   3534         } break;
   3535         default:
   3536             return VK_ERROR_VALIDATION_FAILED_EXT;
   3537             break;
   3538         }
   3539         break;
   3540     case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
   3541         pCDS = new VkCopyDescriptorSet;
   3542         *pNewNode = (GENERIC_HEADER *)pCDS;
   3543         memcpy(pCDS, pUpdate, sizeof(VkCopyDescriptorSet));
   3544         break;
   3545     default:
   3546         if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   3547                     DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
   3548                     "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
   3549                     string_VkStructureType(pUpdate->sType), pUpdate->sType))
   3550             return VK_TRUE;
   3551     }
   3552     // Make sure that pNext for the end of shadow copy is NULL
   3553     (*pNewNode)->pNext = NULL;
   3554     return skipCall;
   3555 }
   3556 
   3557 // Verify that given sampler is valid
   3558 static VkBool32 validateSampler(const layer_data *my_data, const VkSampler *pSampler, const VkBool32 immutable) {
   3559     VkBool32 skipCall = VK_FALSE;
   3560     auto sampIt = my_data->sampleMap.find(*pSampler);
   3561     if (sampIt == my_data->sampleMap.end()) {
   3562         if (!immutable) {
   3563             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
   3564                                 (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS",
   3565                                 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid sampler %#" PRIxLEAST64,
   3566                                 (uint64_t)*pSampler);
   3567         } else { // immutable
   3568             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
   3569                                 (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS",
   3570                                 "vkUpdateDescriptorSets: Attempt to update descriptor whose binding has an invalid immutable "
   3571                                 "sampler %#" PRIxLEAST64,
   3572                                 (uint64_t)*pSampler);
   3573         }
   3574     } else {
   3575         // TODO : Any further checks we want to do on the sampler?
   3576     }
   3577     return skipCall;
   3578 }
   3579 
   3580 // find layout(s) on the cmd buf level
   3581 bool FindLayout(const GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, IMAGE_CMD_BUF_LAYOUT_NODE &node) {
   3582     ImageSubresourcePair imgpair = {image, true, range};
   3583     auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
   3584     if (imgsubIt == pCB->imageLayoutMap.end()) {
   3585         imgpair = {image, false, VkImageSubresource()};
   3586         imgsubIt = pCB->imageLayoutMap.find(imgpair);
   3587         if (imgsubIt == pCB->imageLayoutMap.end())
   3588             return false;
   3589     }
   3590     node = imgsubIt->second;
   3591     return true;
   3592 }
   3593 
   3594 // find layout(s) on the global level
   3595 bool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout) {
   3596     auto imgsubIt = my_data->imageLayoutMap.find(imgpair);
   3597     if (imgsubIt == my_data->imageLayoutMap.end()) {
   3598         imgpair = {imgpair.image, false, VkImageSubresource()};
   3599         imgsubIt = my_data->imageLayoutMap.find(imgpair);
   3600         if (imgsubIt == my_data->imageLayoutMap.end())
   3601             return false;
   3602     }
   3603     layout = imgsubIt->second.layout;
   3604     return true;
   3605 }
   3606 
   3607 bool FindLayout(const layer_data *my_data, VkImage image, VkImageSubresource range, VkImageLayout &layout) {
   3608     ImageSubresourcePair imgpair = {image, true, range};
   3609     return FindLayout(my_data, imgpair, layout);
   3610 }
   3611 
   3612 bool FindLayouts(const layer_data *my_data, VkImage image, std::vector<VkImageLayout> &layouts) {
   3613     auto sub_data = my_data->imageSubresourceMap.find(image);
   3614     if (sub_data == my_data->imageSubresourceMap.end())
   3615         return false;
   3616     auto imgIt = my_data->imageMap.find(image);
   3617     if (imgIt == my_data->imageMap.end())
   3618         return false;
   3619     bool ignoreGlobal = false;
   3620     // TODO: Make this robust for >1 aspect mask. Now it will just say ignore
   3621     // potential errors in this case.
   3622     if (sub_data->second.size() >= (imgIt->second.createInfo.arrayLayers * imgIt->second.createInfo.mipLevels + 1)) {
   3623         ignoreGlobal = true;
   3624     }
   3625     for (auto imgsubpair : sub_data->second) {
   3626         if (ignoreGlobal && !imgsubpair.hasSubresource)
   3627             continue;
   3628         auto img_data = my_data->imageLayoutMap.find(imgsubpair);
   3629         if (img_data != my_data->imageLayoutMap.end()) {
   3630             layouts.push_back(img_data->second.layout);
   3631         }
   3632     }
   3633     return true;
   3634 }
   3635 
   3636 // Set the layout on the global level
   3637 void SetLayout(layer_data *my_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
   3638     VkImage &image = imgpair.image;
   3639     // TODO (mlentine): Maybe set format if new? Not used atm.
   3640     my_data->imageLayoutMap[imgpair].layout = layout;
   3641     // TODO (mlentine): Maybe make vector a set?
   3642     auto subresource = std::find(my_data->imageSubresourceMap[image].begin(), my_data->imageSubresourceMap[image].end(), imgpair);
   3643     if (subresource == my_data->imageSubresourceMap[image].end()) {
   3644         my_data->imageSubresourceMap[image].push_back(imgpair);
   3645     }
   3646 }
   3647 
   3648 void SetLayout(layer_data *my_data, VkImage image, const VkImageLayout &layout) {
   3649     ImageSubresourcePair imgpair = {image, false, VkImageSubresource()};
   3650     SetLayout(my_data, imgpair, layout);
   3651 }
   3652 
   3653 void SetLayout(layer_data *my_data, VkImage image, VkImageSubresource range, const VkImageLayout &layout) {
   3654     ImageSubresourcePair imgpair = {image, true, range};
   3655     SetLayout(my_data, imgpair, layout);
   3656 }
   3657 
   3658 // Set the layout on the cmdbuf level
   3659 void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
   3660     pCB->imageLayoutMap[imgpair] = node;
   3661     // TODO (mlentine): Maybe make vector a set?
   3662     auto subresource = std::find(pCB->imageSubresourceMap[image].begin(), pCB->imageSubresourceMap[image].end(), imgpair);
   3663     if (subresource == pCB->imageSubresourceMap[image].end()) {
   3664         pCB->imageSubresourceMap[image].push_back(imgpair);
   3665     }
   3666 }
   3667 
   3668 void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
   3669     // TODO (mlentine): Maybe make vector a set?
   3670     if (std::find(pCB->imageSubresourceMap[image].begin(), pCB->imageSubresourceMap[image].end(), imgpair) !=
   3671         pCB->imageSubresourceMap[image].end()) {
   3672         pCB->imageLayoutMap[imgpair].layout = layout;
   3673     } else {
   3674         // TODO (mlentine): Could be expensive and might need to be removed.
   3675         assert(imgpair.hasSubresource);
   3676         IMAGE_CMD_BUF_LAYOUT_NODE node;
   3677         FindLayout(pCB, image, imgpair.subresource, node);
   3678         SetLayout(pCB, image, imgpair, {node.initialLayout, layout});
   3679     }
   3680 }
   3681 
   3682 void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
   3683     ImageSubresourcePair imgpair = {image, false, VkImageSubresource()};
   3684     SetLayout(pCB, image, imgpair, node);
   3685 }
   3686 
   3687 void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
   3688     ImageSubresourcePair imgpair = {image, true, range};
   3689     SetLayout(pCB, image, imgpair, node);
   3690 }
   3691 
   3692 void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, const VkImageLayout &layout) {
   3693     ImageSubresourcePair imgpair = {image, false, VkImageSubresource()};
   3694     SetLayout(pCB, image, imgpair, layout);
   3695 }
   3696 
   3697 void SetLayout(GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, const VkImageLayout &layout) {
   3698     ImageSubresourcePair imgpair = {image, true, range};
   3699     SetLayout(pCB, image, imgpair, layout);
   3700 }
   3701 
   3702 void SetLayout(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout) {
   3703     auto image_view_data = dev_data->imageViewMap.find(imageView);
   3704     assert(image_view_data != dev_data->imageViewMap.end());
   3705     const VkImage &image = image_view_data->second.image;
   3706     const VkImageSubresourceRange &subRange = image_view_data->second.subresourceRange;
   3707     // TODO: Do not iterate over every possibility - consolidate where possible
   3708     for (uint32_t j = 0; j < subRange.levelCount; j++) {
   3709         uint32_t level = subRange.baseMipLevel + j;
   3710         for (uint32_t k = 0; k < subRange.layerCount; k++) {
   3711             uint32_t layer = subRange.baseArrayLayer + k;
   3712             VkImageSubresource sub = {subRange.aspectMask, level, layer};
   3713             SetLayout(pCB, image, sub, layout);
   3714         }
   3715     }
   3716 }
   3717 
   3718 // Verify that given imageView is valid
   3719 static VkBool32 validateImageView(const layer_data *my_data, const VkImageView *pImageView, const VkImageLayout imageLayout) {
   3720     VkBool32 skipCall = VK_FALSE;
   3721     auto ivIt = my_data->imageViewMap.find(*pImageView);
   3722     if (ivIt == my_data->imageViewMap.end()) {
   3723         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
   3724                             (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
   3725                             "vkUpdateDescriptorSets: Attempt to update descriptor with invalid imageView %#" PRIxLEAST64,
   3726                             (uint64_t)*pImageView);
   3727     } else {
   3728         // Validate that imageLayout is compatible with aspectMask and image format
   3729         VkImageAspectFlags aspectMask = ivIt->second.subresourceRange.aspectMask;
   3730         VkImage image = ivIt->second.image;
   3731         // TODO : Check here in case we have a bad image
   3732         VkFormat format = VK_FORMAT_MAX_ENUM;
   3733         auto imgIt = my_data->imageMap.find(image);
   3734         if (imgIt != my_data->imageMap.end()) {
   3735             format = (*imgIt).second.createInfo.format;
   3736         } else {
   3737             // Also need to check the swapchains.
   3738             auto swapchainIt = my_data->device_extensions.imageToSwapchainMap.find(image);
   3739             if (swapchainIt != my_data->device_extensions.imageToSwapchainMap.end()) {
   3740                 VkSwapchainKHR swapchain = swapchainIt->second;
   3741                 auto swapchain_nodeIt = my_data->device_extensions.swapchainMap.find(swapchain);
   3742                 if (swapchain_nodeIt != my_data->device_extensions.swapchainMap.end()) {
   3743                     SWAPCHAIN_NODE *pswapchain_node = swapchain_nodeIt->second;
   3744                     format = pswapchain_node->createInfo.imageFormat;
   3745                 }
   3746             }
   3747         }
   3748         if (format == VK_FORMAT_MAX_ENUM) {
   3749             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   3750                                 (uint64_t)image, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
   3751                                 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid image %#" PRIxLEAST64
   3752                                 " in imageView %#" PRIxLEAST64,
   3753                                 (uint64_t)image, (uint64_t)*pImageView);
   3754         } else {
   3755             VkBool32 ds = vk_format_is_depth_or_stencil(format);
   3756             switch (imageLayout) {
   3757             case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
   3758                 // Only Color bit must be set
   3759                 if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
   3760                     skipCall |=
   3761                         log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
   3762                                 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
   3763                                 "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL "
   3764                                 "and imageView %#" PRIxLEAST64 ""
   3765                                 " that does not have VK_IMAGE_ASPECT_COLOR_BIT set.",
   3766                                 (uint64_t)*pImageView);
   3767                 }
   3768                 // format must NOT be DS
   3769                 if (ds) {
   3770                     skipCall |=
   3771                         log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
   3772                                 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
   3773                                 "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL "
   3774                                 "and imageView %#" PRIxLEAST64 ""
   3775                                 " but the image format is %s which is not a color format.",
   3776                                 (uint64_t)*pImageView, string_VkFormat(format));
   3777                 }
   3778                 break;
   3779             case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
   3780             case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
   3781                 // Depth or stencil bit must be set, but both must NOT be set
   3782                 if (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) {
   3783                     if (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
   3784                         // both  must NOT be set
   3785                         skipCall |=
   3786                             log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
   3787                                     (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
   3788                                     "vkUpdateDescriptorSets: Updating descriptor with imageView %#" PRIxLEAST64 ""
   3789                                     " that has both STENCIL and DEPTH aspects set",
   3790                                     (uint64_t)*pImageView);
   3791                     }
   3792                 } else if (!(aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
   3793                     // Neither were set
   3794                     skipCall |=
   3795                         log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
   3796                                 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
   3797                                 "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 ""
   3798                                 " that does not have STENCIL or DEPTH aspect set.",
   3799                                 string_VkImageLayout(imageLayout), (uint64_t)*pImageView);
   3800                 }
   3801                 // format must be DS
   3802                 if (!ds) {
   3803                     skipCall |=
   3804                         log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
   3805                                 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
   3806                                 "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 ""
   3807                                 " but the image format is %s which is not a depth/stencil format.",
   3808                                 string_VkImageLayout(imageLayout), (uint64_t)*pImageView, string_VkFormat(format));
   3809                 }
   3810                 break;
   3811             default:
   3812                 // anything to check for other layouts?
   3813                 break;
   3814             }
   3815         }
   3816     }
   3817     return skipCall;
   3818 }
   3819 
   3820 // Verify that given bufferView is valid
   3821 static VkBool32 validateBufferView(const layer_data *my_data, const VkBufferView *pBufferView) {
   3822     VkBool32 skipCall = VK_FALSE;
   3823     auto sampIt = my_data->bufferViewMap.find(*pBufferView);
   3824     if (sampIt == my_data->bufferViewMap.end()) {
   3825         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT,
   3826                             (uint64_t)*pBufferView, __LINE__, DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR, "DS",
   3827                             "vkUpdateDescriptorSets: Attempt to update descriptor with invalid bufferView %#" PRIxLEAST64,
   3828                             (uint64_t)*pBufferView);
   3829     } else {
   3830         // TODO : Any further checks we want to do on the bufferView?
   3831     }
   3832     return skipCall;
   3833 }
   3834 
   3835 // Verify that given bufferInfo is valid
   3836 static VkBool32 validateBufferInfo(const layer_data *my_data, const VkDescriptorBufferInfo *pBufferInfo) {
   3837     VkBool32 skipCall = VK_FALSE;
   3838     auto sampIt = my_data->bufferMap.find(pBufferInfo->buffer);
   3839     if (sampIt == my_data->bufferMap.end()) {
   3840         skipCall |=
   3841             log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3842                     (uint64_t)pBufferInfo->buffer, __LINE__, DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR, "DS",
   3843                     "vkUpdateDescriptorSets: Attempt to update descriptor where bufferInfo has invalid buffer %#" PRIxLEAST64,
   3844                     (uint64_t)pBufferInfo->buffer);
   3845     } else {
   3846         // TODO : Any further checks we want to do on the bufferView?
   3847     }
   3848     return skipCall;
   3849 }
   3850 
   3851 static VkBool32 validateUpdateContents(const layer_data *my_data, const VkWriteDescriptorSet *pWDS,
   3852                                        const VkDescriptorSetLayoutBinding *pLayoutBinding) {
   3853     VkBool32 skipCall = VK_FALSE;
   3854     // First verify that for the given Descriptor type, the correct DescriptorInfo data is supplied
   3855     const VkSampler *pSampler = NULL;
   3856     VkBool32 immutable = VK_FALSE;
   3857     uint32_t i = 0;
   3858     // For given update type, verify that update contents are correct
   3859     switch (pWDS->descriptorType) {
   3860     case VK_DESCRIPTOR_TYPE_SAMPLER:
   3861         for (i = 0; i < pWDS->descriptorCount; ++i) {
   3862             skipCall |= validateSampler(my_data, &(pWDS->pImageInfo[i].sampler), immutable);
   3863         }
   3864         break;
   3865     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
   3866         for (i = 0; i < pWDS->descriptorCount; ++i) {
   3867             if (NULL == pLayoutBinding->pImmutableSamplers) {
   3868                 pSampler = &(pWDS->pImageInfo[i].sampler);
   3869                 if (immutable) {
   3870                     skipCall |= log_msg(
   3871                         my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
   3872                         (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS",
   3873                         "vkUpdateDescriptorSets: Update #%u is not an immutable sampler %#" PRIxLEAST64
   3874                         ", but previous update(s) from this "
   3875                         "VkWriteDescriptorSet struct used an immutable sampler. All updates from a single struct must either "
   3876                         "use immutable or non-immutable samplers.",
   3877                         i, (uint64_t)*pSampler);
   3878                 }
   3879             } else {
   3880                 if (i > 0 && !immutable) {
   3881                     skipCall |= log_msg(
   3882                         my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
   3883                         (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS",
   3884                         "vkUpdateDescriptorSets: Update #%u is an immutable sampler, but previous update(s) from this "
   3885                         "VkWriteDescriptorSet struct used a non-immutable sampler. All updates from a single struct must either "
   3886                         "use immutable or non-immutable samplers.",
   3887                         i);
   3888                 }
   3889                 immutable = VK_TRUE;
   3890                 pSampler = &(pLayoutBinding->pImmutableSamplers[i]);
   3891             }
   3892             skipCall |= validateSampler(my_data, pSampler, immutable);
   3893         }
   3894     // Intentionally fall through here to also validate image stuff
   3895     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
   3896     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
   3897     case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
   3898         for (i = 0; i < pWDS->descriptorCount; ++i) {
   3899             skipCall |= validateImageView(my_data, &(pWDS->pImageInfo[i].imageView), pWDS->pImageInfo[i].imageLayout);
   3900         }
   3901         break;
   3902     case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
   3903     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
   3904         for (i = 0; i < pWDS->descriptorCount; ++i) {
   3905             skipCall |= validateBufferView(my_data, &(pWDS->pTexelBufferView[i]));
   3906         }
   3907         break;
   3908     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
   3909     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
   3910     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
   3911     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
   3912         for (i = 0; i < pWDS->descriptorCount; ++i) {
   3913             skipCall |= validateBufferInfo(my_data, &(pWDS->pBufferInfo[i]));
   3914         }
   3915         break;
   3916     default:
   3917         break;
   3918     }
   3919     return skipCall;
   3920 }
   3921 // Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
   3922 // func_str is the name of the calling function
   3923 // Return VK_FALSE if no errors occur
   3924 // Return VK_TRUE if validation error occurs and callback returns VK_TRUE (to skip upcoming API call down the chain)
   3925 VkBool32 validateIdleDescriptorSet(const layer_data *my_data, VkDescriptorSet set, std::string func_str) {
   3926     VkBool32 skip_call = VK_FALSE;
   3927     auto set_node = my_data->setMap.find(set);
   3928     if (set_node == my_data->setMap.end()) {
   3929         skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   3930                              (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
   3931                              "Cannot call %s() on descriptor set %" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
   3932                              (uint64_t)(set));
   3933     } else {
   3934         if (set_node->second->in_use.load()) {
   3935             skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   3936                                  VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)(set), __LINE__, DRAWSTATE_OBJECT_INUSE,
   3937                                  "DS", "Cannot call %s() on descriptor set %" PRIxLEAST64 " that is in use by a command buffer.",
   3938                                  func_str.c_str(), (uint64_t)(set));
   3939         }
   3940     }
   3941     return skip_call;
   3942 }
   3943 static void invalidateBoundCmdBuffers(layer_data *dev_data, const SET_NODE *pSet) {
   3944     // Flag any CBs this set is bound to as INVALID
   3945     for (auto cb : pSet->boundCmdBuffers) {
   3946         auto cb_node = dev_data->commandBufferMap.find(cb);
   3947         if (cb_node != dev_data->commandBufferMap.end()) {
   3948             cb_node->second->state = CB_INVALID;
   3949         }
   3950     }
   3951 }
   3952 // update DS mappings based on write and copy update arrays
   3953 static VkBool32 dsUpdate(layer_data *my_data, VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pWDS,
   3954                          uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pCDS) {
   3955     VkBool32 skipCall = VK_FALSE;
   3956 
   3957     LAYOUT_NODE *pLayout = NULL;
   3958     VkDescriptorSetLayoutCreateInfo *pLayoutCI = NULL;
   3959     // Validate Write updates
   3960     uint32_t i = 0;
   3961     for (i = 0; i < descriptorWriteCount; i++) {
   3962         VkDescriptorSet ds = pWDS[i].dstSet;
   3963         SET_NODE *pSet = my_data->setMap[ds];
   3964         // Set being updated cannot be in-flight
   3965         if ((skipCall = validateIdleDescriptorSet(my_data, ds, "VkUpdateDescriptorSets")) == VK_TRUE)
   3966             return skipCall;
   3967         // If set is bound to any cmdBuffers, mark them invalid
   3968         invalidateBoundCmdBuffers(my_data, pSet);
   3969         GENERIC_HEADER *pUpdate = (GENERIC_HEADER *)&pWDS[i];
   3970         pLayout = pSet->pLayout;
   3971         // First verify valid update struct
   3972         if ((skipCall = validUpdateStruct(my_data, device, pUpdate)) == VK_TRUE) {
   3973             break;
   3974         }
   3975         uint32_t binding = 0, endIndex = 0;
   3976         binding = pWDS[i].dstBinding;
   3977         auto bindingToIndex = pLayout->bindingToIndexMap.find(binding);
   3978         // Make sure that layout being updated has the binding being updated
   3979         if (bindingToIndex == pLayout->bindingToIndexMap.end()) {
   3980             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   3981                                 (uint64_t)(ds), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
   3982                                 "Descriptor Set %" PRIu64 " does not have binding to match "
   3983                                 "update binding %u for update type "
   3984                                 "%s!",
   3985                                 (uint64_t)(ds), binding, string_VkStructureType(pUpdate->sType));
   3986         } else {
   3987             // Next verify that update falls within size of given binding
   3988             endIndex = getUpdateEndIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate);
   3989             if (getBindingEndIndex(pLayout, binding) < endIndex) {
   3990                 pLayoutCI = &pLayout->createInfo;
   3991                 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS}    ");
   3992                 skipCall |=
   3993                     log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   3994                             (uint64_t)(ds), __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
   3995                             "Descriptor update type of %s is out of bounds for matching binding %u in Layout w/ CI:\n%s!",
   3996                             string_VkStructureType(pUpdate->sType), binding, DSstr.c_str());
   3997             } else { // TODO : should we skip update on a type mismatch or force it?
   3998                 uint32_t startIndex;
   3999                 startIndex = getUpdateStartIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate);
   4000                 // Layout bindings match w/ update, now verify that update type
   4001                 // & stageFlags are the same for entire update
   4002                 if ((skipCall = validateUpdateConsistency(my_data, device, pLayout, pUpdate, startIndex, endIndex)) == VK_FALSE) {
   4003                     // The update is within bounds and consistent, but need to
   4004                     // make sure contents make sense as well
   4005                     if ((skipCall = validateUpdateContents(my_data, &pWDS[i],
   4006                                                            &pLayout->createInfo.pBindings[bindingToIndex->second])) == VK_FALSE) {
   4007                         // Update is good. Save the update info
   4008                         // Create new update struct for this set's shadow copy
   4009                         GENERIC_HEADER *pNewNode = NULL;
   4010                         skipCall |= shadowUpdateNode(my_data, device, pUpdate, &pNewNode);
   4011                         if (NULL == pNewNode) {
   4012                             skipCall |= log_msg(
   4013                                 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   4014                                 (uint64_t)(ds), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
   4015                                 "Out of memory while attempting to allocate UPDATE struct in vkUpdateDescriptors()");
   4016                         } else {
   4017                             // Insert shadow node into LL of updates for this set
   4018                             pNewNode->pNext = pSet->pUpdateStructs;
   4019                             pSet->pUpdateStructs = pNewNode;
   4020                             // Now update appropriate descriptor(s) to point to new Update node
   4021                             for (uint32_t j = startIndex; j <= endIndex; j++) {
   4022                                 assert(j < pSet->descriptorCount);
   4023                                 pSet->ppDescriptors[j] = pNewNode;
   4024                             }
   4025                         }
   4026                     }
   4027                 }
   4028             }
   4029         }
   4030     }
   4031     // Now validate copy updates
   4032     for (i = 0; i < descriptorCopyCount; ++i) {
   4033         SET_NODE *pSrcSet = NULL, *pDstSet = NULL;
   4034         LAYOUT_NODE *pSrcLayout = NULL, *pDstLayout = NULL;
   4035         uint32_t srcStartIndex = 0, srcEndIndex = 0, dstStartIndex = 0, dstEndIndex = 0;
   4036         // For each copy make sure that update falls within given layout and that types match
   4037         pSrcSet = my_data->setMap[pCDS[i].srcSet];
   4038         pDstSet = my_data->setMap[pCDS[i].dstSet];
   4039         // Set being updated cannot be in-flight
   4040         if ((skipCall = validateIdleDescriptorSet(my_data, pDstSet->set, "VkUpdateDescriptorSets")) == VK_TRUE)
   4041             return skipCall;
   4042         invalidateBoundCmdBuffers(my_data, pDstSet);
   4043         pSrcLayout = pSrcSet->pLayout;
   4044         pDstLayout = pDstSet->pLayout;
   4045         // Validate that src binding is valid for src set layout
   4046         if (pSrcLayout->bindingToIndexMap.find(pCDS[i].srcBinding) == pSrcLayout->bindingToIndexMap.end()) {
   4047             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   4048                                 (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
   4049                                 "Copy descriptor update %u has srcBinding %u "
   4050                                 "which is out of bounds for underlying SetLayout "
   4051                                 "%#" PRIxLEAST64 " which only has bindings 0-%u.",
   4052                                 i, pCDS[i].srcBinding, (uint64_t)pSrcLayout->layout, pSrcLayout->createInfo.bindingCount - 1);
   4053         } else if (pDstLayout->bindingToIndexMap.find(pCDS[i].dstBinding) == pDstLayout->bindingToIndexMap.end()) {
   4054             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   4055                                 (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
   4056                                 "Copy descriptor update %u has dstBinding %u "
   4057                                 "which is out of bounds for underlying SetLayout "
   4058                                 "%#" PRIxLEAST64 " which only has bindings 0-%u.",
   4059                                 i, pCDS[i].dstBinding, (uint64_t)pDstLayout->layout, pDstLayout->createInfo.bindingCount - 1);
   4060         } else {
   4061             // Proceed with validation. Bindings are ok, but make sure update is within bounds of given layout
   4062             srcEndIndex = getUpdateEndIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement,
   4063                                             (const GENERIC_HEADER *)&(pCDS[i]));
   4064             dstEndIndex = getUpdateEndIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement,
   4065                                             (const GENERIC_HEADER *)&(pCDS[i]));
   4066             if (getBindingEndIndex(pSrcLayout, pCDS[i].srcBinding) < srcEndIndex) {
   4067                 pLayoutCI = &pSrcLayout->createInfo;
   4068                 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS}    ");
   4069                 skipCall |=
   4070                     log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   4071                             (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
   4072                             "Copy descriptor src update is out of bounds for matching binding %u in Layout w/ CI:\n%s!",
   4073                             pCDS[i].srcBinding, DSstr.c_str());
   4074             } else if (getBindingEndIndex(pDstLayout, pCDS[i].dstBinding) < dstEndIndex) {
   4075                 pLayoutCI = &pDstLayout->createInfo;
   4076                 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS}    ");
   4077                 skipCall |=
   4078                     log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   4079                             (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
   4080                             "Copy descriptor dest update is out of bounds for matching binding %u in Layout w/ CI:\n%s!",
   4081                             pCDS[i].dstBinding, DSstr.c_str());
   4082             } else {
   4083                 srcStartIndex = getUpdateStartIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement,
   4084                                                     (const GENERIC_HEADER *)&(pCDS[i]));
   4085                 dstStartIndex = getUpdateStartIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement,
   4086                                                     (const GENERIC_HEADER *)&(pCDS[i]));
   4087                 for (uint32_t j = 0; j < pCDS[i].descriptorCount; ++j) {
   4088                     // For copy just make sure that the types match and then perform the update
   4089                     if (pSrcLayout->descriptorTypes[srcStartIndex + j] != pDstLayout->descriptorTypes[dstStartIndex + j]) {
   4090                         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   4091                                             __LINE__, DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
   4092                                             "Copy descriptor update index %u, update count #%u, has src update descriptor type %s "
   4093                                             "that does not match overlapping dest descriptor type of %s!",
   4094                                             i, j + 1, string_VkDescriptorType(pSrcLayout->descriptorTypes[srcStartIndex + j]),
   4095                                             string_VkDescriptorType(pDstLayout->descriptorTypes[dstStartIndex + j]));
   4096                     } else {
   4097                         // point dst descriptor at corresponding src descriptor
   4098                         // TODO : This may be a hole. I believe copy should be its own copy,
   4099                         //  otherwise a subsequent write update to src will incorrectly affect the copy
   4100                         pDstSet->ppDescriptors[j + dstStartIndex] = pSrcSet->ppDescriptors[j + srcStartIndex];
   4101                         pDstSet->pUpdateStructs = pSrcSet->pUpdateStructs;
   4102                     }
   4103                 }
   4104             }
   4105         }
   4106     }
   4107     return skipCall;
   4108 }
   4109 
   4110 // Verify that given pool has descriptors that are being requested for allocation.
   4111 // NOTE : Calls to this function should be wrapped in mutex
   4112 static VkBool32 validate_descriptor_availability_in_pool(layer_data *dev_data, DESCRIPTOR_POOL_NODE *pPoolNode, uint32_t count,
   4113                                                          const VkDescriptorSetLayout *pSetLayouts) {
   4114     VkBool32 skipCall = VK_FALSE;
   4115     uint32_t i = 0;
   4116     uint32_t j = 0;
   4117 
   4118     // Track number of descriptorSets allowable in this pool
   4119     if (pPoolNode->availableSets < count) {
   4120         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
   4121                             reinterpret_cast<uint64_t &>(pPoolNode->pool), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
   4122                             "Unable to allocate %u descriptorSets from pool %#" PRIxLEAST64
   4123                             ". This pool only has %d descriptorSets remaining.",
   4124                             count, reinterpret_cast<uint64_t &>(pPoolNode->pool), pPoolNode->availableSets);
   4125     } else {
   4126         pPoolNode->availableSets -= count;
   4127     }
   4128 
   4129     for (i = 0; i < count; ++i) {
   4130         LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pSetLayouts[i]);
   4131         if (NULL == pLayout) {
   4132             skipCall |=
   4133                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
   4134                         (uint64_t)pSetLayouts[i], __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
   4135                         "Unable to find set layout node for layout %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call",
   4136                         (uint64_t)pSetLayouts[i]);
   4137         } else {
   4138             uint32_t typeIndex = 0, poolSizeCount = 0;
   4139             for (j = 0; j < pLayout->createInfo.bindingCount; ++j) {
   4140                 typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType);
   4141                 poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount;
   4142                 if (poolSizeCount > pPoolNode->availableDescriptorTypeCount[typeIndex]) {
   4143                     skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   4144                                         VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pLayout->layout, __LINE__,
   4145                                         DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
   4146                                         "Unable to allocate %u descriptors of type %s from pool %#" PRIxLEAST64
   4147                                         ". This pool only has %d descriptors of this type remaining.",
   4148                                         poolSizeCount, string_VkDescriptorType(pLayout->createInfo.pBindings[j].descriptorType),
   4149                                         (uint64_t)pPoolNode->pool, pPoolNode->availableDescriptorTypeCount[typeIndex]);
   4150                 } else { // Decrement available descriptors of this type
   4151                     pPoolNode->availableDescriptorTypeCount[typeIndex] -= poolSizeCount;
   4152                 }
   4153             }
   4154         }
   4155     }
   4156     return skipCall;
   4157 }
   4158 
   4159 // Free the shadowed update node for this Set
   4160 // NOTE : Calls to this function should be wrapped in mutex
   4161 static void freeShadowUpdateTree(SET_NODE *pSet) {
   4162     GENERIC_HEADER *pShadowUpdate = pSet->pUpdateStructs;
   4163     pSet->pUpdateStructs = NULL;
   4164     GENERIC_HEADER *pFreeUpdate = pShadowUpdate;
   4165     // Clear the descriptor mappings as they will now be invalid
   4166     memset(pSet->ppDescriptors, 0, pSet->descriptorCount * sizeof(GENERIC_HEADER *));
   4167     while (pShadowUpdate) {
   4168         pFreeUpdate = pShadowUpdate;
   4169         pShadowUpdate = (GENERIC_HEADER *)pShadowUpdate->pNext;
   4170         VkWriteDescriptorSet *pWDS = NULL;
   4171         switch (pFreeUpdate->sType) {
   4172         case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
   4173             pWDS = (VkWriteDescriptorSet *)pFreeUpdate;
   4174             switch (pWDS->descriptorType) {
   4175             case VK_DESCRIPTOR_TYPE_SAMPLER:
   4176             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
   4177             case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
   4178             case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
   4179                 delete[] pWDS->pImageInfo;
   4180             } break;
   4181             case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
   4182             case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
   4183                 delete[] pWDS->pTexelBufferView;
   4184             } break;
   4185             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
   4186             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
   4187             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
   4188             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
   4189                 delete[] pWDS->pBufferInfo;
   4190             } break;
   4191             default:
   4192                 break;
   4193             }
   4194             break;
   4195         case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
   4196             break;
   4197         default:
   4198             assert(0);
   4199             break;
   4200         }
   4201         delete pFreeUpdate;
   4202     }
   4203 }
   4204 
   4205 // Free all DS Pools including their Sets & related sub-structs
   4206 // NOTE : Calls to this function should be wrapped in mutex
   4207 static void deletePools(layer_data *my_data) {
   4208     if (my_data->descriptorPoolMap.size() <= 0)
   4209         return;
   4210     for (auto ii = my_data->descriptorPoolMap.begin(); ii != my_data->descriptorPoolMap.end(); ++ii) {
   4211         SET_NODE *pSet = (*ii).second->pSets;
   4212         SET_NODE *pFreeSet = pSet;
   4213         while (pSet) {
   4214             pFreeSet = pSet;
   4215             pSet = pSet->pNext;
   4216             // Freeing layouts handled in deleteLayouts() function
   4217             // Free Update shadow struct tree
   4218             freeShadowUpdateTree(pFreeSet);
   4219             delete[] pFreeSet->ppDescriptors;
   4220             delete pFreeSet;
   4221         }
   4222         delete (*ii).second;
   4223     }
   4224     my_data->descriptorPoolMap.clear();
   4225 }
   4226 
   4227 // WARN : Once deleteLayouts() called, any layout ptrs in Pool/Set data structure will be invalid
   4228 // NOTE : Calls to this function should be wrapped in mutex
   4229 static void deleteLayouts(layer_data *my_data) {
   4230     if (my_data->descriptorSetLayoutMap.size() <= 0)
   4231         return;
   4232     for (auto ii = my_data->descriptorSetLayoutMap.begin(); ii != my_data->descriptorSetLayoutMap.end(); ++ii) {
   4233         LAYOUT_NODE *pLayout = (*ii).second;
   4234         if (pLayout->createInfo.pBindings) {
   4235             for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) {
   4236                 delete[] pLayout->createInfo.pBindings[i].pImmutableSamplers;
   4237             }
   4238             delete[] pLayout->createInfo.pBindings;
   4239         }
   4240         delete pLayout;
   4241     }
   4242     my_data->descriptorSetLayoutMap.clear();
   4243 }
   4244 
   4245 // Currently clearing a set is removing all previous updates to that set
   4246 //  TODO : Validate if this is correct clearing behavior
   4247 static void clearDescriptorSet(layer_data *my_data, VkDescriptorSet set) {
   4248     SET_NODE *pSet = getSetNode(my_data, set);
   4249     if (!pSet) {
   4250         // TODO : Return error
   4251     } else {
   4252         freeShadowUpdateTree(pSet);
   4253     }
   4254 }
   4255 
   4256 static void clearDescriptorPool(layer_data *my_data, const VkDevice device, const VkDescriptorPool pool,
   4257                                 VkDescriptorPoolResetFlags flags) {
   4258     DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pool);
   4259     if (!pPool) {
   4260         log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
   4261                 (uint64_t)pool, __LINE__, DRAWSTATE_INVALID_POOL, "DS",
   4262                 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkResetDescriptorPool() call", (uint64_t)pool);
   4263     } else {
   4264         // TODO: validate flags
   4265         // For every set off of this pool, clear it
   4266         SET_NODE *pSet = pPool->pSets;
   4267         while (pSet) {
   4268             clearDescriptorSet(my_data, pSet->set);
   4269             pSet = pSet->pNext;
   4270         }
   4271         // Reset available count to max count for this pool
   4272         for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
   4273             pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
   4274         }
   4275     }
   4276 }
   4277 
   4278 // For given CB object, fetch associated CB Node from map
   4279 static GLOBAL_CB_NODE *getCBNode(layer_data *my_data, const VkCommandBuffer cb) {
   4280     if (my_data->commandBufferMap.count(cb) == 0) {
   4281         log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   4282                 reinterpret_cast<const uint64_t &>(cb), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   4283                 "Attempt to use CommandBuffer %#" PRIxLEAST64 " that doesn't exist!", (uint64_t)(cb));
   4284         return NULL;
   4285     }
   4286     return my_data->commandBufferMap[cb];
   4287 }
   4288 
   4289 // Free all CB Nodes
   4290 // NOTE : Calls to this function should be wrapped in mutex
   4291 static void deleteCommandBuffers(layer_data *my_data) {
   4292     if (my_data->commandBufferMap.size() <= 0) {
   4293         return;
   4294     }
   4295     for (auto ii = my_data->commandBufferMap.begin(); ii != my_data->commandBufferMap.end(); ++ii) {
   4296         delete (*ii).second;
   4297     }
   4298     my_data->commandBufferMap.clear();
   4299 }
   4300 
   4301 static VkBool32 report_error_no_cb_begin(const layer_data *dev_data, const VkCommandBuffer cb, const char *caller_name) {
   4302     return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   4303                    (uint64_t)cb, __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
   4304                    "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
   4305 }
   4306 
   4307 VkBool32 validateCmdsInCmdBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
   4308     if (!pCB->activeRenderPass)
   4309         return VK_FALSE;
   4310     VkBool32 skip_call = VK_FALSE;
   4311     if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS && cmd_type != CMD_EXECUTECOMMANDS) {
   4312         skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   4313                              DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   4314                              "Commands cannot be called in a subpass using secondary command buffers.");
   4315     } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
   4316         skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   4317                              DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   4318                              "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
   4319     }
   4320     return skip_call;
   4321 }
   4322 
   4323 static bool checkGraphicsBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
   4324     if (!(flags & VK_QUEUE_GRAPHICS_BIT))
   4325         return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   4326                        DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   4327                        "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
   4328     return false;
   4329 }
   4330 
   4331 static bool checkComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
   4332     if (!(flags & VK_QUEUE_COMPUTE_BIT))
   4333         return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   4334                        DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   4335                        "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name);
   4336     return false;
   4337 }
   4338 
   4339 static bool checkGraphicsOrComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
   4340     if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT)))
   4341         return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   4342                        DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   4343                        "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
   4344     return false;
   4345 }
   4346 
   4347 // Add specified CMD to the CmdBuffer in given pCB, flagging errors if CB is not
   4348 //  in the recording state or if there's an issue with the Cmd ordering
   4349 static VkBool32 addCmd(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) {
   4350     VkBool32 skipCall = VK_FALSE;
   4351     auto pool_data = my_data->commandPoolMap.find(pCB->createInfo.commandPool);
   4352     if (pool_data != my_data->commandPoolMap.end()) {
   4353         VkQueueFlags flags = my_data->physDevProperties.queue_family_properties[pool_data->second.queueFamilyIndex].queueFlags;
   4354         switch (cmd) {
   4355         case CMD_BINDPIPELINE:
   4356         case CMD_BINDPIPELINEDELTA:
   4357         case CMD_BINDDESCRIPTORSETS:
   4358         case CMD_FILLBUFFER:
   4359         case CMD_CLEARCOLORIMAGE:
   4360         case CMD_SETEVENT:
   4361         case CMD_RESETEVENT:
   4362         case CMD_WAITEVENTS:
   4363         case CMD_BEGINQUERY:
   4364         case CMD_ENDQUERY:
   4365         case CMD_RESETQUERYPOOL:
   4366         case CMD_COPYQUERYPOOLRESULTS:
   4367         case CMD_WRITETIMESTAMP:
   4368             skipCall |= checkGraphicsOrComputeBit(my_data, flags, cmdTypeToString(cmd).c_str());
   4369             break;
   4370         case CMD_SETVIEWPORTSTATE:
   4371         case CMD_SETSCISSORSTATE:
   4372         case CMD_SETLINEWIDTHSTATE:
   4373         case CMD_SETDEPTHBIASSTATE:
   4374         case CMD_SETBLENDSTATE:
   4375         case CMD_SETDEPTHBOUNDSSTATE:
   4376         case CMD_SETSTENCILREADMASKSTATE:
   4377         case CMD_SETSTENCILWRITEMASKSTATE:
   4378         case CMD_SETSTENCILREFERENCESTATE:
   4379         case CMD_BINDINDEXBUFFER:
   4380         case CMD_BINDVERTEXBUFFER:
   4381         case CMD_DRAW:
   4382         case CMD_DRAWINDEXED:
   4383         case CMD_DRAWINDIRECT:
   4384         case CMD_DRAWINDEXEDINDIRECT:
   4385         case CMD_BLITIMAGE:
   4386         case CMD_CLEARATTACHMENTS:
   4387         case CMD_CLEARDEPTHSTENCILIMAGE:
   4388         case CMD_RESOLVEIMAGE:
   4389         case CMD_BEGINRENDERPASS:
   4390         case CMD_NEXTSUBPASS:
   4391         case CMD_ENDRENDERPASS:
   4392             skipCall |= checkGraphicsBit(my_data, flags, cmdTypeToString(cmd).c_str());
   4393             break;
   4394         case CMD_DISPATCH:
   4395         case CMD_DISPATCHINDIRECT:
   4396             skipCall |= checkComputeBit(my_data, flags, cmdTypeToString(cmd).c_str());
   4397             break;
   4398         case CMD_COPYBUFFER:
   4399         case CMD_COPYIMAGE:
   4400         case CMD_COPYBUFFERTOIMAGE:
   4401         case CMD_COPYIMAGETOBUFFER:
   4402         case CMD_CLONEIMAGEDATA:
   4403         case CMD_UPDATEBUFFER:
   4404         case CMD_PIPELINEBARRIER:
   4405         case CMD_EXECUTECOMMANDS:
   4406             break;
   4407         default:
   4408             break;
   4409         }
   4410     }
   4411     if (pCB->state != CB_RECORDING) {
   4412         skipCall |= report_error_no_cb_begin(my_data, pCB->commandBuffer, caller_name);
   4413         skipCall |= validateCmdsInCmdBuffer(my_data, pCB, cmd);
   4414         CMD_NODE cmdNode = {};
   4415         // init cmd node and append to end of cmd LL
   4416         cmdNode.cmdNumber = ++pCB->numCmds;
   4417         cmdNode.type = cmd;
   4418         pCB->cmds.push_back(cmdNode);
   4419     }
   4420     return skipCall;
   4421 }
   4422 // Reset the command buffer state
   4423 //  Maintain the createInfo and set state to CB_NEW, but clear all other state
   4424 static void resetCB(layer_data *my_data, const VkCommandBuffer cb) {
   4425     GLOBAL_CB_NODE *pCB = my_data->commandBufferMap[cb];
   4426     if (pCB) {
   4427         pCB->cmds.clear();
   4428         // Reset CB state (note that createInfo is not cleared)
   4429         pCB->commandBuffer = cb;
   4430         memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
   4431         memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
   4432         pCB->numCmds = 0;
   4433         memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t));
   4434         pCB->state = CB_NEW;
   4435         pCB->submitCount = 0;
   4436         pCB->status = 0;
   4437         pCB->viewports.clear();
   4438         pCB->scissors.clear();
   4439         for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
   4440             // Before clearing lastBoundState, remove any CB bindings from all uniqueBoundSets
   4441             for (auto set : pCB->lastBound[i].uniqueBoundSets) {
   4442                 auto set_node = my_data->setMap.find(set);
   4443                 if (set_node != my_data->setMap.end()) {
   4444                     set_node->second->boundCmdBuffers.erase(pCB->commandBuffer);
   4445                 }
   4446             }
   4447             pCB->lastBound[i].reset();
   4448         }
   4449         memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
   4450         pCB->activeRenderPass = 0;
   4451         pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
   4452         pCB->activeSubpass = 0;
   4453         pCB->framebuffer = 0;
   4454         pCB->fenceId = 0;
   4455         pCB->lastSubmittedFence = VK_NULL_HANDLE;
   4456         pCB->lastSubmittedQueue = VK_NULL_HANDLE;
   4457         pCB->destroyedSets.clear();
   4458         pCB->updatedSets.clear();
   4459         pCB->destroyedFramebuffers.clear();
   4460         pCB->waitedEvents.clear();
   4461         pCB->semaphores.clear();
   4462         pCB->events.clear();
   4463         pCB->waitedEventsBeforeQueryReset.clear();
   4464         pCB->queryToStateMap.clear();
   4465         pCB->activeQueries.clear();
   4466         pCB->startedQueries.clear();
   4467         pCB->imageLayoutMap.clear();
   4468         pCB->eventToStageMap.clear();
   4469         pCB->drawData.clear();
   4470         pCB->currentDrawData.buffers.clear();
   4471         pCB->primaryCommandBuffer = VK_NULL_HANDLE;
   4472         pCB->secondaryCommandBuffers.clear();
   4473         pCB->activeDescriptorSets.clear();
   4474         pCB->validate_functions.clear();
   4475         pCB->pMemObjList.clear();
   4476         pCB->eventUpdates.clear();
   4477     }
   4478 }
   4479 
   4480 // Set PSO-related status bits for CB, including dynamic state set via PSO
   4481 static void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe) {
   4482     for (auto const & att : pPipe->attachments) {
   4483         if (0 != att.colorWriteMask) {
   4484             pCB->status |= CBSTATUS_COLOR_BLEND_WRITE_ENABLE;
   4485         }
   4486     }
   4487     if (pPipe->dsStateCI.depthWriteEnable) {
   4488         pCB->status |= CBSTATUS_DEPTH_WRITE_ENABLE;
   4489     }
   4490     if (pPipe->dsStateCI.stencilTestEnable) {
   4491         pCB->status |= CBSTATUS_STENCIL_TEST_ENABLE;
   4492     }
   4493     // Account for any dynamic state not set via this PSO
   4494     if (!pPipe->dynStateCI.dynamicStateCount) { // All state is static
   4495         pCB->status = CBSTATUS_ALL;
   4496     } else {
   4497         // First consider all state on
   4498         // Then unset any state that's noted as dynamic in PSO
   4499         // Finally OR that into CB statemask
   4500         CBStatusFlags psoDynStateMask = CBSTATUS_ALL;
   4501         for (uint32_t i = 0; i < pPipe->dynStateCI.dynamicStateCount; i++) {
   4502             switch (pPipe->dynStateCI.pDynamicStates[i]) {
   4503             case VK_DYNAMIC_STATE_VIEWPORT:
   4504                 psoDynStateMask &= ~CBSTATUS_VIEWPORT_SET;
   4505                 break;
   4506             case VK_DYNAMIC_STATE_SCISSOR:
   4507                 psoDynStateMask &= ~CBSTATUS_SCISSOR_SET;
   4508                 break;
   4509             case VK_DYNAMIC_STATE_LINE_WIDTH:
   4510                 psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
   4511                 break;
   4512             case VK_DYNAMIC_STATE_DEPTH_BIAS:
   4513                 psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
   4514                 break;
   4515             case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
   4516                 psoDynStateMask &= ~CBSTATUS_BLEND_SET;
   4517                 break;
   4518             case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
   4519                 psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
   4520                 break;
   4521             case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
   4522                 psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
   4523                 break;
   4524             case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
   4525                 psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
   4526                 break;
   4527             case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
   4528                 psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
   4529                 break;
   4530             default:
   4531                 // TODO : Flag error here
   4532                 break;
   4533             }
   4534         }
   4535         pCB->status |= psoDynStateMask;
   4536     }
   4537 }
   4538 
   4539 // Print the last bound Gfx Pipeline
   4540 static VkBool32 printPipeline(layer_data *my_data, const VkCommandBuffer cb) {
   4541     VkBool32 skipCall = VK_FALSE;
   4542     GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb);
   4543     if (pCB) {
   4544         PIPELINE_NODE *pPipeTrav = getPipeline(my_data, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
   4545         if (!pPipeTrav) {
   4546             // nothing to print
   4547         } else {
   4548             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   4549                                 __LINE__, DRAWSTATE_NONE, "DS", "%s",
   4550                                 vk_print_vkgraphicspipelinecreateinfo(&pPipeTrav->graphicsPipelineCI, "{DS}").c_str());
   4551         }
   4552     }
   4553     return skipCall;
   4554 }
   4555 
   4556 static void printCB(layer_data *my_data, const VkCommandBuffer cb) {
   4557     GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb);
   4558     if (pCB && pCB->cmds.size() > 0) {
   4559         log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   4560                 DRAWSTATE_NONE, "DS", "Cmds in CB %p", (void *)cb);
   4561         vector<CMD_NODE> cmds = pCB->cmds;
   4562         for (auto ii = cmds.begin(); ii != cmds.end(); ++ii) {
   4563             // TODO : Need to pass cb as srcObj here
   4564             log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   4565                     __LINE__, DRAWSTATE_NONE, "DS", "  CMD#%" PRIu64 ": %s", (*ii).cmdNumber, cmdTypeToString((*ii).type).c_str());
   4566         }
   4567     } else {
   4568         // Nothing to print
   4569     }
   4570 }
   4571 
   4572 static VkBool32 synchAndPrintDSConfig(layer_data *my_data, const VkCommandBuffer cb) {
   4573     VkBool32 skipCall = VK_FALSE;
   4574     if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
   4575         return skipCall;
   4576     }
   4577     skipCall |= printPipeline(my_data, cb);
   4578     return skipCall;
   4579 }
   4580 
   4581 // Flags validation error if the associated call is made inside a render pass. The apiName
   4582 // routine should ONLY be called outside a render pass.
   4583 static VkBool32 insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) {
   4584     VkBool32 inside = VK_FALSE;
   4585     if (pCB->activeRenderPass) {
   4586         inside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   4587                          (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
   4588                          "%s: It is invalid to issue this call inside an active render pass (%#" PRIxLEAST64 ")", apiName,
   4589                          (uint64_t)pCB->activeRenderPass);
   4590     }
   4591     return inside;
   4592 }
   4593 
   4594 // Flags validation error if the associated call is made outside a render pass. The apiName
   4595 // routine should ONLY be called inside a render pass.
   4596 static VkBool32 outsideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) {
   4597     VkBool32 outside = VK_FALSE;
   4598     if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
   4599         ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
   4600          !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
   4601         outside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   4602                           (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
   4603                           "%s: This call must be issued inside an active render pass.", apiName);
   4604     }
   4605     return outside;
   4606 }
   4607 
   4608 static void init_core_validation(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
   4609 
   4610     layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_core_validation");
   4611 
   4612     if (!globalLockInitialized) {
   4613         loader_platform_thread_create_mutex(&globalLock);
   4614         globalLockInitialized = 1;
   4615     }
   4616 #if MTMERGESOURCE
   4617     // Zero out memory property data
   4618     memset(&memProps, 0, sizeof(VkPhysicalDeviceMemoryProperties));
   4619 #endif
   4620 }
   4621 
   4622 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   4623 vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
   4624     VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
   4625 
   4626     assert(chain_info->u.pLayerInfo);
   4627     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
   4628     PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
   4629     if (fpCreateInstance == NULL)
   4630         return VK_ERROR_INITIALIZATION_FAILED;
   4631 
   4632     // Advance the link info for the next element on the chain
   4633     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
   4634 
   4635     VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
   4636     if (result != VK_SUCCESS)
   4637         return result;
   4638 
   4639     layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
   4640     my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
   4641     layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
   4642 
   4643     my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance,
   4644                                                         pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
   4645 
   4646     init_core_validation(my_data, pAllocator);
   4647 
   4648     ValidateLayerOrdering(*pCreateInfo);
   4649 
   4650     return result;
   4651 }
   4652 
   4653 /* hook DestroyInstance to remove tableInstanceMap entry */
   4654 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
   4655     // TODOSC : Shouldn't need any customization here
   4656     dispatch_key key = get_dispatch_key(instance);
   4657     // TBD: Need any locking this early, in case this function is called at the
   4658     // same time by more than one thread?
   4659     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
   4660     VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
   4661     pTable->DestroyInstance(instance, pAllocator);
   4662 
   4663     loader_platform_thread_lock_mutex(&globalLock);
   4664     // Clean up logging callback, if any
   4665     while (my_data->logging_callback.size() > 0) {
   4666         VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
   4667         layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
   4668         my_data->logging_callback.pop_back();
   4669     }
   4670 
   4671     layer_debug_report_destroy_instance(my_data->report_data);
   4672     delete my_data->instance_dispatch_table;
   4673     layer_data_map.erase(key);
   4674     loader_platform_thread_unlock_mutex(&globalLock);
   4675     if (layer_data_map.empty()) {
   4676         // Release mutex when destroying last instance.
   4677         loader_platform_thread_delete_mutex(&globalLock);
   4678         globalLockInitialized = 0;
   4679     }
   4680 }
   4681 
   4682 static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
   4683     uint32_t i;
   4684     // TBD: Need any locking, in case this function is called at the same time
   4685     // by more than one thread?
   4686     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   4687     dev_data->device_extensions.wsi_enabled = false;
   4688 
   4689     VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table;
   4690     PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr;
   4691     pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR");
   4692     pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR");
   4693     pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR");
   4694     pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR");
   4695     pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR");
   4696 
   4697     for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
   4698         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
   4699             dev_data->device_extensions.wsi_enabled = true;
   4700     }
   4701 }
   4702 
   4703 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
   4704                                                               const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
   4705     VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
   4706 
   4707     assert(chain_info->u.pLayerInfo);
   4708     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
   4709     PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
   4710     PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");
   4711     if (fpCreateDevice == NULL) {
   4712         return VK_ERROR_INITIALIZATION_FAILED;
   4713     }
   4714 
   4715     // Advance the link info for the next element on the chain
   4716     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
   4717 
   4718     VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
   4719     if (result != VK_SUCCESS) {
   4720         return result;
   4721     }
   4722 
   4723     loader_platform_thread_lock_mutex(&globalLock);
   4724     layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map);
   4725     layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
   4726 
   4727     // Setup device dispatch table
   4728     my_device_data->device_dispatch_table = new VkLayerDispatchTable;
   4729     layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
   4730 
   4731     my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
   4732     createDeviceRegisterExtensions(pCreateInfo, *pDevice);
   4733     // Get physical device limits for this device
   4734     my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(gpu, &(my_device_data->physDevProperties.properties));
   4735     uint32_t count;
   4736     my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
   4737     my_device_data->physDevProperties.queue_family_properties.resize(count);
   4738     my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(
   4739         gpu, &count, &my_device_data->physDevProperties.queue_family_properties[0]);
   4740     // TODO: device limits should make sure these are compatible
   4741     if (pCreateInfo->pEnabledFeatures) {
   4742         my_device_data->physDevProperties.features = *pCreateInfo->pEnabledFeatures;
   4743     } else {
   4744         memset(&my_device_data->physDevProperties.features, 0, sizeof(VkPhysicalDeviceFeatures));
   4745     }
   4746     loader_platform_thread_unlock_mutex(&globalLock);
   4747 
   4748     ValidateLayerOrdering(*pCreateInfo);
   4749 
   4750     return result;
   4751 }
   4752 
   4753 // prototype
   4754 static void deleteRenderPasses(layer_data *);
   4755 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
   4756     // TODOSC : Shouldn't need any customization here
   4757     dispatch_key key = get_dispatch_key(device);
   4758     layer_data *dev_data = get_my_data_ptr(key, layer_data_map);
   4759     // Free all the memory
   4760     loader_platform_thread_lock_mutex(&globalLock);
   4761     deletePipelines(dev_data);
   4762     deleteRenderPasses(dev_data);
   4763     deleteCommandBuffers(dev_data);
   4764     deletePools(dev_data);
   4765     deleteLayouts(dev_data);
   4766     dev_data->imageViewMap.clear();
   4767     dev_data->imageMap.clear();
   4768     dev_data->imageSubresourceMap.clear();
   4769     dev_data->imageLayoutMap.clear();
   4770     dev_data->bufferViewMap.clear();
   4771     dev_data->bufferMap.clear();
   4772     loader_platform_thread_unlock_mutex(&globalLock);
   4773 #if MTMERGESOURCE
   4774     VkBool32 skipCall = VK_FALSE;
   4775     loader_platform_thread_lock_mutex(&globalLock);
   4776     log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   4777             (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "Printing List details prior to vkDestroyDevice()");
   4778     log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   4779             (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "================================================");
   4780     print_mem_list(dev_data, device);
   4781     printCBList(dev_data, device);
   4782     delete_cmd_buf_info_list(dev_data);
   4783     // Report any memory leaks
   4784     DEVICE_MEM_INFO *pInfo = NULL;
   4785     if (dev_data->memObjMap.size() > 0) {
   4786         for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) {
   4787             pInfo = &(*ii).second;
   4788             if (pInfo->allocInfo.allocationSize != 0) {
   4789                 // Valid Usage: All child objects created on device must have been destroyed prior to destroying device
   4790                 skipCall |=
   4791                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   4792                             VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pInfo->mem, __LINE__, MEMTRACK_MEMORY_LEAK,
   4793                             "MEM", "Mem Object %" PRIu64 " has not been freed. You should clean up this memory by calling "
   4794                                    "vkFreeMemory(%" PRIu64 ") prior to vkDestroyDevice().",
   4795                             (uint64_t)(pInfo->mem), (uint64_t)(pInfo->mem));
   4796             }
   4797         }
   4798     }
   4799     // Queues persist until device is destroyed
   4800     delete_queue_info_list(dev_data);
   4801     layer_debug_report_destroy_device(device);
   4802     loader_platform_thread_unlock_mutex(&globalLock);
   4803 
   4804 #if DISPATCH_MAP_DEBUG
   4805     fprintf(stderr, "Device: %p, key: %p\n", device, key);
   4806 #endif
   4807     VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table;
   4808     if (VK_FALSE == skipCall) {
   4809         pDisp->DestroyDevice(device, pAllocator);
   4810     }
   4811 #else
   4812     dev_data->device_dispatch_table->DestroyDevice(device, pAllocator);
   4813 #endif
   4814     delete dev_data->device_dispatch_table;
   4815     layer_data_map.erase(key);
   4816 }
   4817 
   4818 #if MTMERGESOURCE
   4819 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   4820 vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties) {
   4821     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
   4822     VkLayerInstanceDispatchTable *pInstanceTable = my_data->instance_dispatch_table;
   4823     pInstanceTable->GetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties);
   4824     memcpy(&memProps, pMemoryProperties, sizeof(VkPhysicalDeviceMemoryProperties));
   4825 }
   4826 #endif
   4827 
   4828 static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
   4829 
   4830 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   4831 vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) {
   4832     return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
   4833 }
   4834 
   4835 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   4836 vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
   4837     return util_GetLayerProperties(ARRAY_SIZE(cv_global_layers), cv_global_layers, pCount, pProperties);
   4838 }
   4839 
   4840 // TODO: Why does this exist - can we just use global?
   4841 static const VkLayerProperties cv_device_layers[] = {{
   4842     "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
   4843 }};
   4844 
   4845 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
   4846                                                                                     const char *pLayerName, uint32_t *pCount,
   4847                                                                                     VkExtensionProperties *pProperties) {
   4848     if (pLayerName == NULL) {
   4849         dispatch_key key = get_dispatch_key(physicalDevice);
   4850         layer_data *my_data = get_my_data_ptr(key, layer_data_map);
   4851         return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
   4852     } else {
   4853         return util_GetExtensionProperties(0, NULL, pCount, pProperties);
   4854     }
   4855 }
   4856 
   4857 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   4858 vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) {
   4859     /* draw_state physical device layers are the same as global */
   4860     return util_GetLayerProperties(ARRAY_SIZE(cv_device_layers), cv_device_layers, pCount, pProperties);
   4861 }
   4862 
   4863 // This validates that the initial layout specified in the command buffer for
   4864 // the IMAGE is the same
   4865 // as the global IMAGE layout
   4866 VkBool32 ValidateCmdBufImageLayouts(VkCommandBuffer cmdBuffer) {
   4867     VkBool32 skip_call = VK_FALSE;
   4868     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
   4869     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
   4870     for (auto cb_image_data : pCB->imageLayoutMap) {
   4871         VkImageLayout imageLayout;
   4872         if (!FindLayout(dev_data, cb_image_data.first, imageLayout)) {
   4873             skip_call |=
   4874                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   4875                         __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot submit cmd buffer using deleted image %" PRIu64 ".",
   4876                         reinterpret_cast<const uint64_t &>(cb_image_data.first));
   4877         } else {
   4878             if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
   4879                 // TODO: Set memory invalid which is in mem_tracker currently
   4880             } else if (imageLayout != cb_image_data.second.initialLayout) {
   4881                 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   4882                                      VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT,
   4883                                      "DS", "Cannot submit cmd buffer using image with layout %s when "
   4884                                            "first use is %s.",
   4885                                      string_VkImageLayout(imageLayout), string_VkImageLayout(cb_image_data.second.initialLayout));
   4886             }
   4887             SetLayout(dev_data, cb_image_data.first, cb_image_data.second.layout);
   4888         }
   4889     }
   4890     return skip_call;
   4891 }
   4892 // Track which resources are in-flight by atomically incrementing their "in_use" count
   4893 VkBool32 validateAndIncrementResources(layer_data *my_data, GLOBAL_CB_NODE *pCB) {
   4894     VkBool32 skip_call = VK_FALSE;
   4895     for (auto drawDataElement : pCB->drawData) {
   4896         for (auto buffer : drawDataElement.buffers) {
   4897             auto buffer_data = my_data->bufferMap.find(buffer);
   4898             if (buffer_data == my_data->bufferMap.end()) {
   4899                 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   4900                                      (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
   4901                                      "Cannot submit cmd buffer using deleted buffer %" PRIu64 ".", (uint64_t)(buffer));
   4902             } else {
   4903                 buffer_data->second.in_use.fetch_add(1);
   4904             }
   4905         }
   4906     }
   4907     for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
   4908         for (auto set : pCB->lastBound[i].uniqueBoundSets) {
   4909             auto setNode = my_data->setMap.find(set);
   4910             if (setNode == my_data->setMap.end()) {
   4911                 skip_call |=
   4912                     log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   4913                             (uint64_t)(set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS",
   4914                             "Cannot submit cmd buffer using deleted descriptor set %" PRIu64 ".", (uint64_t)(set));
   4915             } else {
   4916                 setNode->second->in_use.fetch_add(1);
   4917             }
   4918         }
   4919     }
   4920     for (auto semaphore : pCB->semaphores) {
   4921         auto semaphoreNode = my_data->semaphoreMap.find(semaphore);
   4922         if (semaphoreNode == my_data->semaphoreMap.end()) {
   4923             skip_call |=
   4924                 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   4925                         reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS",
   4926                         "Cannot submit cmd buffer using deleted semaphore %" PRIu64 ".", reinterpret_cast<uint64_t &>(semaphore));
   4927         } else {
   4928             semaphoreNode->second.in_use.fetch_add(1);
   4929         }
   4930     }
   4931     for (auto event : pCB->events) {
   4932         auto eventNode = my_data->eventMap.find(event);
   4933         if (eventNode == my_data->eventMap.end()) {
   4934             skip_call |=
   4935                 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   4936                         reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
   4937                         "Cannot submit cmd buffer using deleted event %" PRIu64 ".", reinterpret_cast<uint64_t &>(event));
   4938         } else {
   4939             eventNode->second.in_use.fetch_add(1);
   4940         }
   4941     }
   4942     return skip_call;
   4943 }
   4944 
   4945 void decrementResources(layer_data *my_data, VkCommandBuffer cmdBuffer) {
   4946     GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer);
   4947     for (auto drawDataElement : pCB->drawData) {
   4948         for (auto buffer : drawDataElement.buffers) {
   4949             auto buffer_data = my_data->bufferMap.find(buffer);
   4950             if (buffer_data != my_data->bufferMap.end()) {
   4951                 buffer_data->second.in_use.fetch_sub(1);
   4952             }
   4953         }
   4954     }
   4955     for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
   4956         for (auto set : pCB->lastBound[i].uniqueBoundSets) {
   4957             auto setNode = my_data->setMap.find(set);
   4958             if (setNode != my_data->setMap.end()) {
   4959                 setNode->second->in_use.fetch_sub(1);
   4960             }
   4961         }
   4962     }
   4963     for (auto semaphore : pCB->semaphores) {
   4964         auto semaphoreNode = my_data->semaphoreMap.find(semaphore);
   4965         if (semaphoreNode != my_data->semaphoreMap.end()) {
   4966             semaphoreNode->second.in_use.fetch_sub(1);
   4967         }
   4968     }
   4969     for (auto event : pCB->events) {
   4970         auto eventNode = my_data->eventMap.find(event);
   4971         if (eventNode != my_data->eventMap.end()) {
   4972             eventNode->second.in_use.fetch_sub(1);
   4973         }
   4974     }
   4975     for (auto queryStatePair : pCB->queryToStateMap) {
   4976         my_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
   4977     }
   4978     for (auto eventStagePair : pCB->eventToStageMap) {
   4979         my_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
   4980     }
   4981 }
   4982 
   4983 void decrementResources(layer_data *my_data, uint32_t fenceCount, const VkFence *pFences) {
   4984     for (uint32_t i = 0; i < fenceCount; ++i) {
   4985         auto fence_data = my_data->fenceMap.find(pFences[i]);
   4986         if (fence_data == my_data->fenceMap.end() || !fence_data->second.needsSignaled)
   4987             return;
   4988         fence_data->second.needsSignaled = false;
   4989         fence_data->second.in_use.fetch_sub(1);
   4990         decrementResources(my_data, fence_data->second.priorFences.size(), fence_data->second.priorFences.data());
   4991         for (auto cmdBuffer : fence_data->second.cmdBuffers) {
   4992             decrementResources(my_data, cmdBuffer);
   4993         }
   4994     }
   4995 }
   4996 
   4997 void decrementResources(layer_data *my_data, VkQueue queue) {
   4998     auto queue_data = my_data->queueMap.find(queue);
   4999     if (queue_data != my_data->queueMap.end()) {
   5000         for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) {
   5001             decrementResources(my_data, cmdBuffer);
   5002         }
   5003         queue_data->second.untrackedCmdBuffers.clear();
   5004         decrementResources(my_data, queue_data->second.lastFences.size(), queue_data->second.lastFences.data());
   5005     }
   5006 }
   5007 
   5008 void updateTrackedCommandBuffers(layer_data *dev_data, VkQueue queue, VkQueue other_queue, VkFence fence) {
   5009     if (queue == other_queue) {
   5010         return;
   5011     }
   5012     auto queue_data = dev_data->queueMap.find(queue);
   5013     auto other_queue_data = dev_data->queueMap.find(other_queue);
   5014     if (queue_data == dev_data->queueMap.end() || other_queue_data == dev_data->queueMap.end()) {
   5015         return;
   5016     }
   5017     for (auto fence : other_queue_data->second.lastFences) {
   5018         queue_data->second.lastFences.push_back(fence);
   5019     }
   5020     if (fence != VK_NULL_HANDLE) {
   5021         auto fence_data = dev_data->fenceMap.find(fence);
   5022         if (fence_data == dev_data->fenceMap.end()) {
   5023             return;
   5024         }
   5025         for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) {
   5026             fence_data->second.cmdBuffers.push_back(cmdbuffer);
   5027         }
   5028         other_queue_data->second.untrackedCmdBuffers.clear();
   5029     } else {
   5030         for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) {
   5031             queue_data->second.untrackedCmdBuffers.push_back(cmdbuffer);
   5032         }
   5033         other_queue_data->second.untrackedCmdBuffers.clear();
   5034     }
   5035     for (auto eventStagePair : other_queue_data->second.eventToStageMap) {
   5036         queue_data->second.eventToStageMap[eventStagePair.first] = eventStagePair.second;
   5037     }
   5038 }
   5039 
   5040 void trackCommandBuffers(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
   5041     auto queue_data = my_data->queueMap.find(queue);
   5042     if (fence != VK_NULL_HANDLE) {
   5043         vector<VkFence> prior_fences;
   5044         auto fence_data = my_data->fenceMap.find(fence);
   5045         if (fence_data == my_data->fenceMap.end()) {
   5046             return;
   5047         }
   5048         if (queue_data != my_data->queueMap.end()) {
   5049             prior_fences = queue_data->second.lastFences;
   5050             queue_data->second.lastFences.clear();
   5051             queue_data->second.lastFences.push_back(fence);
   5052             for (auto cmdbuffer : queue_data->second.untrackedCmdBuffers) {
   5053                 fence_data->second.cmdBuffers.push_back(cmdbuffer);
   5054             }
   5055             queue_data->second.untrackedCmdBuffers.clear();
   5056         }
   5057         fence_data->second.cmdBuffers.clear();
   5058         fence_data->second.priorFences = prior_fences;
   5059         fence_data->second.needsSignaled = true;
   5060         fence_data->second.queue = queue;
   5061         fence_data->second.in_use.fetch_add(1);
   5062         for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
   5063             const VkSubmitInfo *submit = &pSubmits[submit_idx];
   5064             for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
   5065                 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
   5066                     fence_data->second.cmdBuffers.push_back(secondaryCmdBuffer);
   5067                 }
   5068                 fence_data->second.cmdBuffers.push_back(submit->pCommandBuffers[i]);
   5069             }
   5070         }
   5071     } else {
   5072         if (queue_data != my_data->queueMap.end()) {
   5073             for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
   5074                 const VkSubmitInfo *submit = &pSubmits[submit_idx];
   5075                 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
   5076                     for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
   5077                         queue_data->second.untrackedCmdBuffers.push_back(secondaryCmdBuffer);
   5078                     }
   5079                     queue_data->second.untrackedCmdBuffers.push_back(submit->pCommandBuffers[i]);
   5080                 }
   5081             }
   5082         }
   5083     }
   5084     if (queue_data != my_data->queueMap.end()) {
   5085         for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
   5086             const VkSubmitInfo *submit = &pSubmits[submit_idx];
   5087             for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
   5088                 // Add cmdBuffers to both the global set and queue set
   5089                 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
   5090                     my_data->globalInFlightCmdBuffers.insert(secondaryCmdBuffer);
   5091                     queue_data->second.inFlightCmdBuffers.insert(secondaryCmdBuffer);
   5092                 }
   5093                 my_data->globalInFlightCmdBuffers.insert(submit->pCommandBuffers[i]);
   5094                 queue_data->second.inFlightCmdBuffers.insert(submit->pCommandBuffers[i]);
   5095             }
   5096         }
   5097     }
   5098 }
   5099 
   5100 bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
   5101     bool skip_call = false;
   5102     if (dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) &&
   5103         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
   5104         skip_call |=
   5105             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   5106                     __LINE__, DRAWSTATE_INVALID_FENCE, "DS", "Command Buffer %#" PRIx64 " is already in use and is not marked "
   5107                                                              "for simultaneous use.",
   5108                     reinterpret_cast<uint64_t>(pCB->commandBuffer));
   5109     }
   5110     return skip_call;
   5111 }
   5112 
   5113 static bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
   5114     bool skipCall = false;
   5115     // Validate that cmd buffers have been updated
   5116     if (CB_RECORDED != pCB->state) {
   5117         if (CB_INVALID == pCB->state) {
   5118             // Inform app of reason CB invalid
   5119             bool causeReported = false;
   5120             if (!pCB->destroyedSets.empty()) {
   5121                 std::stringstream set_string;
   5122                 for (auto set : pCB->destroyedSets)
   5123                     set_string << " " << set;
   5124 
   5125                 skipCall |=
   5126                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   5127                             (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   5128                             "You are submitting command buffer %#" PRIxLEAST64
   5129                             " that is invalid because it had the following bound descriptor set(s) destroyed: %s",
   5130                             (uint64_t)(pCB->commandBuffer), set_string.str().c_str());
   5131                 causeReported = true;
   5132             }
   5133             if (!pCB->updatedSets.empty()) {
   5134                 std::stringstream set_string;
   5135                 for (auto set : pCB->updatedSets)
   5136                     set_string << " " << set;
   5137 
   5138                 skipCall |=
   5139                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   5140                             (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   5141                             "You are submitting command buffer %#" PRIxLEAST64
   5142                             " that is invalid because it had the following bound descriptor set(s) updated: %s",
   5143                             (uint64_t)(pCB->commandBuffer), set_string.str().c_str());
   5144                 causeReported = true;
   5145             }
   5146             if (!pCB->destroyedFramebuffers.empty()) {
   5147                 std::stringstream fb_string;
   5148                 for (auto fb : pCB->destroyedFramebuffers)
   5149                     fb_string << " " << fb;
   5150 
   5151                 skipCall |=
   5152                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   5153                             reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   5154                             "You are submitting command buffer %#" PRIxLEAST64 " that is invalid because it had the following "
   5155                             "referenced framebuffers destroyed: %s",
   5156                             reinterpret_cast<uint64_t &>(pCB->commandBuffer), fb_string.str().c_str());
   5157                 causeReported = true;
   5158             }
   5159             // TODO : This is defensive programming to make sure an error is
   5160             //  flagged if we hit this INVALID cmd buffer case and none of the
   5161             //  above cases are hit. As the number of INVALID cases grows, this
   5162             //  code should be updated to seemlessly handle all the cases.
   5163             if (!causeReported) {
   5164                 skipCall |= log_msg(
   5165                     dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   5166                     reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   5167                     "You are submitting command buffer %#" PRIxLEAST64 " that is invalid due to an unknown cause. Validation "
   5168                     "should "
   5169                     "be improved to report the exact cause.",
   5170                     reinterpret_cast<uint64_t &>(pCB->commandBuffer));
   5171             }
   5172         } else { // Flag error for using CB w/o vkEndCommandBuffer() called
   5173             skipCall |=
   5174                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   5175                         (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
   5176                         "You must call vkEndCommandBuffer() on CB %#" PRIxLEAST64 " before this call to vkQueueSubmit()!",
   5177                         (uint64_t)(pCB->commandBuffer));
   5178         }
   5179     }
   5180     return skipCall;
   5181 }
   5182 
   5183 static VkBool32 validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
   5184     // Track in-use for resources off of primary and any secondary CBs
   5185     VkBool32 skipCall = validateAndIncrementResources(dev_data, pCB);
   5186     if (!pCB->secondaryCommandBuffers.empty()) {
   5187         for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
   5188             skipCall |= validateAndIncrementResources(dev_data, dev_data->commandBufferMap[secondaryCmdBuffer]);
   5189             GLOBAL_CB_NODE *pSubCB = getCBNode(dev_data, secondaryCmdBuffer);
   5190             if (pSubCB->primaryCommandBuffer != pCB->commandBuffer) {
   5191                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   5192                         __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
   5193                         "CB %#" PRIxLEAST64 " was submitted with secondary buffer %#" PRIxLEAST64
   5194                         " but that buffer has subsequently been bound to "
   5195                         "primary cmd buffer %#" PRIxLEAST64 ".",
   5196                         reinterpret_cast<uint64_t>(pCB->commandBuffer), reinterpret_cast<uint64_t>(secondaryCmdBuffer),
   5197                         reinterpret_cast<uint64_t>(pSubCB->primaryCommandBuffer));
   5198             }
   5199         }
   5200     }
   5201     // TODO : Verify if this also needs to be checked for secondary command
   5202     //  buffers. If so, this block of code can move to
   5203     //   validateCommandBufferState() function. vulkan GL106 filed to clarify
   5204     if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount > 1)) {
   5205         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   5206                             __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
   5207                             "CB %#" PRIxLEAST64 " was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
   5208                             "set, but has been submitted %#" PRIxLEAST64 " times.",
   5209                             (uint64_t)(pCB->commandBuffer), pCB->submitCount);
   5210     }
   5211     skipCall |= validateCommandBufferState(dev_data, pCB);
   5212     // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
   5213     // on device
   5214     skipCall |= validateCommandBufferSimultaneousUse(dev_data, pCB);
   5215     return skipCall;
   5216 }
   5217 
   5218 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   5219 vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
   5220     VkBool32 skipCall = VK_FALSE;
   5221     GLOBAL_CB_NODE *pCBNode = NULL;
   5222     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
   5223     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   5224     loader_platform_thread_lock_mutex(&globalLock);
   5225 #if MTMERGESOURCE
   5226     // TODO : Need to track fence and clear mem references when fence clears
   5227     // MTMTODO : Merge this code with code below to avoid duplicating efforts
   5228     uint64_t fenceId = 0;
   5229     skipCall = add_fence_info(dev_data, fence, queue, &fenceId);
   5230 
   5231     print_mem_list(dev_data, queue);
   5232     printCBList(dev_data, queue);
   5233     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
   5234         const VkSubmitInfo *submit = &pSubmits[submit_idx];
   5235         for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
   5236             pCBNode = getCBNode(dev_data, submit->pCommandBuffers[i]);
   5237             if (pCBNode) {
   5238                 pCBNode->fenceId = fenceId;
   5239                 pCBNode->lastSubmittedFence = fence;
   5240                 pCBNode->lastSubmittedQueue = queue;
   5241                 for (auto &function : pCBNode->validate_functions) {
   5242                     skipCall |= function();
   5243                 }
   5244                 for (auto &function : pCBNode->eventUpdates) {
   5245                     skipCall |= static_cast<VkBool32>(function(queue));
   5246                 }
   5247             }
   5248         }
   5249 
   5250         for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) {
   5251             VkSemaphore sem = submit->pWaitSemaphores[i];
   5252 
   5253             if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) {
   5254                 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_SIGNALLED) {
   5255                     skipCall =
   5256                         log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
   5257                                 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE",
   5258                                 "vkQueueSubmit: Semaphore must be in signaled state before passing to pWaitSemaphores");
   5259                 }
   5260                 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_WAIT;
   5261             }
   5262         }
   5263         for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) {
   5264             VkSemaphore sem = submit->pSignalSemaphores[i];
   5265 
   5266             if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) {
   5267                 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_UNSET) {
   5268                     skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   5269                                        VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, (uint64_t)sem, __LINE__, MEMTRACK_NONE,
   5270                                        "SEMAPHORE", "vkQueueSubmit: Semaphore must not be currently signaled or in a wait state");
   5271                 }
   5272                 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED;
   5273             }
   5274         }
   5275     }
   5276 #endif
   5277     // First verify that fence is not in use
   5278     if ((fence != VK_NULL_HANDLE) && (submitCount != 0) && dev_data->fenceMap[fence].in_use.load()) {
   5279         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
   5280                             (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
   5281                             "Fence %#" PRIx64 " is already in use by another submission.", (uint64_t)(fence));
   5282     }
   5283     // Now verify each individual submit
   5284     std::unordered_set<VkQueue> processed_other_queues;
   5285     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
   5286         const VkSubmitInfo *submit = &pSubmits[submit_idx];
   5287         vector<VkSemaphore> semaphoreList;
   5288         for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
   5289             const VkSemaphore &semaphore = submit->pWaitSemaphores[i];
   5290             semaphoreList.push_back(semaphore);
   5291             if (dev_data->semaphoreMap[semaphore].signaled) {
   5292                 dev_data->semaphoreMap[semaphore].signaled = 0;
   5293             } else {
   5294                 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   5295                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS,
   5296                                     "DS", "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.",
   5297                                     reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
   5298             }
   5299             const VkQueue &other_queue = dev_data->semaphoreMap[semaphore].queue;
   5300             if (other_queue != VK_NULL_HANDLE && !processed_other_queues.count(other_queue)) {
   5301                 updateTrackedCommandBuffers(dev_data, queue, other_queue, fence);
   5302                 processed_other_queues.insert(other_queue);
   5303             }
   5304         }
   5305         for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
   5306             const VkSemaphore &semaphore = submit->pSignalSemaphores[i];
   5307             semaphoreList.push_back(semaphore);
   5308             if (dev_data->semaphoreMap[semaphore].signaled) {
   5309                 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   5310                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS,
   5311                                     "DS", "Queue %#" PRIx64 " is signaling semaphore %#" PRIx64
   5312                                           " that has already been signaled but not waited on by queue %#" PRIx64 ".",
   5313                                     reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore),
   5314                                     reinterpret_cast<uint64_t &>(dev_data->semaphoreMap[semaphore].queue));
   5315             } else {
   5316                 dev_data->semaphoreMap[semaphore].signaled = 1;
   5317                 dev_data->semaphoreMap[semaphore].queue = queue;
   5318             }
   5319         }
   5320         for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
   5321             skipCall |= ValidateCmdBufImageLayouts(submit->pCommandBuffers[i]);
   5322             pCBNode = getCBNode(dev_data, submit->pCommandBuffers[i]);
   5323             pCBNode->semaphores = semaphoreList;
   5324             pCBNode->submitCount++; // increment submit count
   5325             skipCall |= validatePrimaryCommandBufferState(dev_data, pCBNode);
   5326         }
   5327     }
   5328     // Update cmdBuffer-related data structs and mark fence in-use
   5329     trackCommandBuffers(dev_data, queue, submitCount, pSubmits, fence);
   5330     loader_platform_thread_unlock_mutex(&globalLock);
   5331     if (VK_FALSE == skipCall)
   5332         result = dev_data->device_dispatch_table->QueueSubmit(queue, submitCount, pSubmits, fence);
   5333 #if MTMERGESOURCE
   5334     loader_platform_thread_lock_mutex(&globalLock);
   5335     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
   5336         const VkSubmitInfo *submit = &pSubmits[submit_idx];
   5337         for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) {
   5338             VkSemaphore sem = submit->pWaitSemaphores[i];
   5339 
   5340             if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) {
   5341                 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET;
   5342             }
   5343         }
   5344     }
   5345     loader_platform_thread_unlock_mutex(&globalLock);
   5346 #endif
   5347     return result;
   5348 }
   5349 
   5350 #if MTMERGESOURCE
   5351 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
   5352                                                                 const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
   5353     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5354     VkResult result = my_data->device_dispatch_table->AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
   5355     // TODO : Track allocations and overall size here
   5356     loader_platform_thread_lock_mutex(&globalLock);
   5357     add_mem_obj_info(my_data, device, *pMemory, pAllocateInfo);
   5358     print_mem_list(my_data, device);
   5359     loader_platform_thread_unlock_mutex(&globalLock);
   5360     return result;
   5361 }
   5362 
   5363 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5364 vkFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
   5365     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5366 
   5367     // From spec : A memory object is freed by calling vkFreeMemory() when it is no longer needed.
   5368     // Before freeing a memory object, an application must ensure the memory object is no longer
   5369     // in use by the devicefor example by command buffers queued for execution. The memory need
   5370     // not yet be unbound from all images and buffers, but any further use of those images or
   5371     // buffers (on host or device) for anything other than destroying those objects will result in
   5372     // undefined behavior.
   5373 
   5374     loader_platform_thread_lock_mutex(&globalLock);
   5375     freeMemObjInfo(my_data, device, mem, VK_FALSE);
   5376     print_mem_list(my_data, device);
   5377     printCBList(my_data, device);
   5378     loader_platform_thread_unlock_mutex(&globalLock);
   5379     my_data->device_dispatch_table->FreeMemory(device, mem, pAllocator);
   5380 }
   5381 
   5382 VkBool32 validateMemRange(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
   5383     VkBool32 skipCall = VK_FALSE;
   5384 
   5385     if (size == 0) {
   5386         // TODO: a size of 0 is not listed as an invalid use in the spec, should it be?
   5387         skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
   5388                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
   5389                            "VkMapMemory: Attempting to map memory range of size zero");
   5390     }
   5391 
   5392     auto mem_element = my_data->memObjMap.find(mem);
   5393     if (mem_element != my_data->memObjMap.end()) {
   5394         // It is an application error to call VkMapMemory on an object that is already mapped
   5395         if (mem_element->second.memRange.size != 0) {
   5396             skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
   5397                                (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
   5398                                "VkMapMemory: Attempting to map memory on an already-mapped object %#" PRIxLEAST64, (uint64_t)mem);
   5399         }
   5400 
   5401         // Validate that offset + size is within object's allocationSize
   5402         if (size == VK_WHOLE_SIZE) {
   5403             if (offset >= mem_element->second.allocInfo.allocationSize) {
   5404                 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   5405                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP,
   5406                                    "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset,
   5407                                    mem_element->second.allocInfo.allocationSize, mem_element->second.allocInfo.allocationSize);
   5408             }
   5409         } else {
   5410             if ((offset + size) > mem_element->second.allocInfo.allocationSize) {
   5411                 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   5412                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP,
   5413                                    "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset,
   5414                                    size + offset, mem_element->second.allocInfo.allocationSize);
   5415             }
   5416         }
   5417     }
   5418     return skipCall;
   5419 }
   5420 
   5421 void storeMemRanges(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
   5422     auto mem_element = my_data->memObjMap.find(mem);
   5423     if (mem_element != my_data->memObjMap.end()) {
   5424         MemRange new_range;
   5425         new_range.offset = offset;
   5426         new_range.size = size;
   5427         mem_element->second.memRange = new_range;
   5428     }
   5429 }
   5430 
   5431 VkBool32 deleteMemRanges(layer_data *my_data, VkDeviceMemory mem) {
   5432     VkBool32 skipCall = VK_FALSE;
   5433     auto mem_element = my_data->memObjMap.find(mem);
   5434     if (mem_element != my_data->memObjMap.end()) {
   5435         if (!mem_element->second.memRange.size) {
   5436             // Valid Usage: memory must currently be mapped
   5437             skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
   5438                                (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
   5439                                "Unmapping Memory without memory being mapped: mem obj %#" PRIxLEAST64, (uint64_t)mem);
   5440         }
   5441         mem_element->second.memRange.size = 0;
   5442         if (mem_element->second.pData) {
   5443             free(mem_element->second.pData);
   5444             mem_element->second.pData = 0;
   5445         }
   5446     }
   5447     return skipCall;
   5448 }
   5449 
   5450 static char NoncoherentMemoryFillValue = 0xb;
   5451 
   5452 void initializeAndTrackMemory(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize size, void **ppData) {
   5453     auto mem_element = my_data->memObjMap.find(mem);
   5454     if (mem_element != my_data->memObjMap.end()) {
   5455         mem_element->second.pDriverData = *ppData;
   5456         uint32_t index = mem_element->second.allocInfo.memoryTypeIndex;
   5457         if (memProps.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
   5458             mem_element->second.pData = 0;
   5459         } else {
   5460             if (size == VK_WHOLE_SIZE) {
   5461                 size = mem_element->second.allocInfo.allocationSize;
   5462             }
   5463             size_t convSize = (size_t)(size);
   5464             mem_element->second.pData = malloc(2 * convSize);
   5465             memset(mem_element->second.pData, NoncoherentMemoryFillValue, 2 * convSize);
   5466             *ppData = static_cast<char *>(mem_element->second.pData) + (convSize / 2);
   5467         }
   5468     }
   5469 }
   5470 #endif
   5471 // Note: This function assumes that the global lock is held by the calling
   5472 // thread.
   5473 VkBool32 cleanInFlightCmdBuffer(layer_data *my_data, VkCommandBuffer cmdBuffer) {
   5474     VkBool32 skip_call = VK_FALSE;
   5475     GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer);
   5476     if (pCB) {
   5477         for (auto queryEventsPair : pCB->waitedEventsBeforeQueryReset) {
   5478             for (auto event : queryEventsPair.second) {
   5479                 if (my_data->eventMap[event].needsSignaled) {
   5480                     skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   5481                                          VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
   5482                                          "Cannot get query results on queryPool %" PRIu64
   5483                                          " with index %d which was guarded by unsignaled event %" PRIu64 ".",
   5484                                          (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event));
   5485                 }
   5486             }
   5487         }
   5488     }
   5489     return skip_call;
   5490 }
   5491 // Remove given cmd_buffer from the global inFlight set.
   5492 //  Also, if given queue is valid, then remove the cmd_buffer from that queues
   5493 //  inFlightCmdBuffer set. Finally, check all other queues and if given cmd_buffer
   5494 //  is still in flight on another queue, add it back into the global set.
   5495 // Note: This function assumes that the global lock is held by the calling
   5496 // thread.
   5497 static inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkQueue queue) {
   5498     // Pull it off of global list initially, but if we find it in any other queue list, add it back in
   5499     dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
   5500     if (dev_data->queueMap.find(queue) != dev_data->queueMap.end()) {
   5501         dev_data->queueMap[queue].inFlightCmdBuffers.erase(cmd_buffer);
   5502         for (auto q : dev_data->queues) {
   5503             if ((q != queue) &&
   5504                 (dev_data->queueMap[q].inFlightCmdBuffers.find(cmd_buffer) != dev_data->queueMap[q].inFlightCmdBuffers.end())) {
   5505                 dev_data->globalInFlightCmdBuffers.insert(cmd_buffer);
   5506                 break;
   5507             }
   5508         }
   5509     }
   5510 }
   5511 #if MTMERGESOURCE
   5512 static inline bool verifyFenceStatus(VkDevice device, VkFence fence, const char *apiCall) {
   5513     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5514     VkBool32 skipCall = false;
   5515     auto pFenceInfo = my_data->fenceMap.find(fence);
   5516     if (pFenceInfo != my_data->fenceMap.end()) {
   5517         if (pFenceInfo->second.firstTimeFlag != VK_TRUE) {
   5518             if ((pFenceInfo->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT) &&
   5519                 pFenceInfo->second.firstTimeFlag != VK_TRUE) {
   5520                 skipCall |=
   5521                     log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
   5522                             (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
   5523                             "%s specified fence %#" PRIxLEAST64 " already in SIGNALED state.", apiCall, (uint64_t)fence);
   5524             }
   5525             if (!pFenceInfo->second.queue && !pFenceInfo->second.swapchain) { // Checking status of unsubmitted fence
   5526                 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
   5527                                     reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
   5528                                     "%s called for fence %#" PRIxLEAST64 " which has not been submitted on a Queue or during "
   5529                                     "acquire next image.",
   5530                                     apiCall, reinterpret_cast<uint64_t &>(fence));
   5531             }
   5532         } else {
   5533             pFenceInfo->second.firstTimeFlag = VK_FALSE;
   5534         }
   5535     }
   5536     return skipCall;
   5537 }
   5538 #endif
   5539 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   5540 vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) {
   5541     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5542     VkBool32 skip_call = VK_FALSE;
   5543 #if MTMERGESOURCE
   5544     // Verify fence status of submitted fences
   5545     loader_platform_thread_lock_mutex(&globalLock);
   5546     for (uint32_t i = 0; i < fenceCount; i++) {
   5547         skip_call |= verifyFenceStatus(device, pFences[i], "vkWaitForFences");
   5548     }
   5549     loader_platform_thread_unlock_mutex(&globalLock);
   5550     if (skip_call)
   5551         return VK_ERROR_VALIDATION_FAILED_EXT;
   5552 #endif
   5553     VkResult result = dev_data->device_dispatch_table->WaitForFences(device, fenceCount, pFences, waitAll, timeout);
   5554 
   5555     if (result == VK_SUCCESS) {
   5556         loader_platform_thread_lock_mutex(&globalLock);
   5557         // When we know that all fences are complete we can clean/remove their CBs
   5558         if (waitAll || fenceCount == 1) {
   5559             for (uint32_t i = 0; i < fenceCount; ++i) {
   5560 #if MTMERGESOURCE
   5561                 update_fence_tracking(dev_data, pFences[i]);
   5562 #endif
   5563                 VkQueue fence_queue = dev_data->fenceMap[pFences[i]].queue;
   5564                 for (auto cmdBuffer : dev_data->fenceMap[pFences[i]].cmdBuffers) {
   5565                     skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer);
   5566                     removeInFlightCmdBuffer(dev_data, cmdBuffer, fence_queue);
   5567                 }
   5568             }
   5569             decrementResources(dev_data, fenceCount, pFences);
   5570         }
   5571         // NOTE : Alternate case not handled here is when some fences have completed. In
   5572         //  this case for app to guarantee which fences completed it will have to call
   5573         //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
   5574         loader_platform_thread_unlock_mutex(&globalLock);
   5575     }
   5576     if (VK_FALSE != skip_call)
   5577         return VK_ERROR_VALIDATION_FAILED_EXT;
   5578     return result;
   5579 }
   5580 
   5581 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence) {
   5582     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5583     bool skipCall = false;
   5584     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   5585 #if MTMERGESOURCE
   5586     loader_platform_thread_lock_mutex(&globalLock);
   5587     skipCall = verifyFenceStatus(device, fence, "vkGetFenceStatus");
   5588     loader_platform_thread_unlock_mutex(&globalLock);
   5589     if (skipCall)
   5590         return result;
   5591 #endif
   5592     result = dev_data->device_dispatch_table->GetFenceStatus(device, fence);
   5593     VkBool32 skip_call = VK_FALSE;
   5594     loader_platform_thread_lock_mutex(&globalLock);
   5595     if (result == VK_SUCCESS) {
   5596 #if MTMERGESOURCE
   5597         update_fence_tracking(dev_data, fence);
   5598 #endif
   5599         auto fence_queue = dev_data->fenceMap[fence].queue;
   5600         for (auto cmdBuffer : dev_data->fenceMap[fence].cmdBuffers) {
   5601             skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer);
   5602             removeInFlightCmdBuffer(dev_data, cmdBuffer, fence_queue);
   5603         }
   5604         decrementResources(dev_data, 1, &fence);
   5605     }
   5606     loader_platform_thread_unlock_mutex(&globalLock);
   5607     if (VK_FALSE != skip_call)
   5608         return VK_ERROR_VALIDATION_FAILED_EXT;
   5609     return result;
   5610 }
   5611 
   5612 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5613 vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
   5614     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5615     dev_data->device_dispatch_table->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
   5616     loader_platform_thread_lock_mutex(&globalLock);
   5617     dev_data->queues.push_back(*pQueue);
   5618     QUEUE_NODE *pQNode = &dev_data->queueMap[*pQueue];
   5619     pQNode->device = device;
   5620 #if MTMERGESOURCE
   5621     pQNode->lastRetiredId = 0;
   5622     pQNode->lastSubmittedId = 0;
   5623 #endif
   5624     loader_platform_thread_unlock_mutex(&globalLock);
   5625 }
   5626 
   5627 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue) {
   5628     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
   5629     decrementResources(dev_data, queue);
   5630     VkBool32 skip_call = VK_FALSE;
   5631     loader_platform_thread_lock_mutex(&globalLock);
   5632     // Iterate over local set since we erase set members as we go in for loop
   5633     auto local_cb_set = dev_data->queueMap[queue].inFlightCmdBuffers;
   5634     for (auto cmdBuffer : local_cb_set) {
   5635         skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer);
   5636         removeInFlightCmdBuffer(dev_data, cmdBuffer, queue);
   5637     }
   5638     dev_data->queueMap[queue].inFlightCmdBuffers.clear();
   5639     loader_platform_thread_unlock_mutex(&globalLock);
   5640     if (VK_FALSE != skip_call)
   5641         return VK_ERROR_VALIDATION_FAILED_EXT;
   5642     VkResult result = dev_data->device_dispatch_table->QueueWaitIdle(queue);
   5643 #if MTMERGESOURCE
   5644     if (VK_SUCCESS == result) {
   5645         loader_platform_thread_lock_mutex(&globalLock);
   5646         retire_queue_fences(dev_data, queue);
   5647         loader_platform_thread_unlock_mutex(&globalLock);
   5648     }
   5649 #endif
   5650     return result;
   5651 }
   5652 
   5653 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(VkDevice device) {
   5654     VkBool32 skip_call = VK_FALSE;
   5655     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5656     loader_platform_thread_lock_mutex(&globalLock);
   5657     for (auto queue : dev_data->queues) {
   5658         decrementResources(dev_data, queue);
   5659         if (dev_data->queueMap.find(queue) != dev_data->queueMap.end()) {
   5660             // Clear all of the queue inFlightCmdBuffers (global set cleared below)
   5661             dev_data->queueMap[queue].inFlightCmdBuffers.clear();
   5662         }
   5663     }
   5664     for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) {
   5665         skip_call |= cleanInFlightCmdBuffer(dev_data, cmdBuffer);
   5666     }
   5667     dev_data->globalInFlightCmdBuffers.clear();
   5668     loader_platform_thread_unlock_mutex(&globalLock);
   5669     if (VK_FALSE != skip_call)
   5670         return VK_ERROR_VALIDATION_FAILED_EXT;
   5671     VkResult result = dev_data->device_dispatch_table->DeviceWaitIdle(device);
   5672 #if MTMERGESOURCE
   5673     if (VK_SUCCESS == result) {
   5674         loader_platform_thread_lock_mutex(&globalLock);
   5675         retire_device_fences(dev_data, device);
   5676         loader_platform_thread_unlock_mutex(&globalLock);
   5677     }
   5678 #endif
   5679     return result;
   5680 }
   5681 
   5682 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
   5683     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5684     bool skipCall = false;
   5685     loader_platform_thread_lock_mutex(&globalLock);
   5686     if (dev_data->fenceMap[fence].in_use.load()) {
   5687         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
   5688                             (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
   5689                             "Fence %#" PRIx64 " is in use by a command buffer.", (uint64_t)(fence));
   5690     }
   5691 #if MTMERGESOURCE
   5692     delete_fence_info(dev_data, fence);
   5693     auto item = dev_data->fenceMap.find(fence);
   5694     if (item != dev_data->fenceMap.end()) {
   5695         dev_data->fenceMap.erase(item);
   5696     }
   5697 #endif
   5698     loader_platform_thread_unlock_mutex(&globalLock);
   5699     if (!skipCall)
   5700         dev_data->device_dispatch_table->DestroyFence(device, fence, pAllocator);
   5701 }
   5702 
   5703 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5704 vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
   5705     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5706     dev_data->device_dispatch_table->DestroySemaphore(device, semaphore, pAllocator);
   5707     loader_platform_thread_lock_mutex(&globalLock);
   5708     auto item = dev_data->semaphoreMap.find(semaphore);
   5709     if (item != dev_data->semaphoreMap.end()) {
   5710         if (item->second.in_use.load()) {
   5711             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
   5712                     reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS",
   5713                     "Cannot delete semaphore %" PRIx64 " which is in use.", reinterpret_cast<uint64_t &>(semaphore));
   5714         }
   5715         dev_data->semaphoreMap.erase(semaphore);
   5716     }
   5717     loader_platform_thread_unlock_mutex(&globalLock);
   5718     // TODO : Clean up any internal data structures using this obj.
   5719 }
   5720 
   5721 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
   5722     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5723     bool skip_call = false;
   5724     loader_platform_thread_lock_mutex(&globalLock);
   5725     auto event_data = dev_data->eventMap.find(event);
   5726     if (event_data != dev_data->eventMap.end()) {
   5727         if (event_data->second.in_use.load()) {
   5728             skip_call |= log_msg(
   5729                 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   5730                 reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
   5731                 "Cannot delete event %" PRIx64 " which is in use by a command buffer.", reinterpret_cast<uint64_t &>(event));
   5732         }
   5733         dev_data->eventMap.erase(event_data);
   5734     }
   5735     loader_platform_thread_unlock_mutex(&globalLock);
   5736     if (!skip_call)
   5737         dev_data->device_dispatch_table->DestroyEvent(device, event, pAllocator);
   5738     // TODO : Clean up any internal data structures using this obj.
   5739 }
   5740 
   5741 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5742 vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
   5743     get_my_data_ptr(get_dispatch_key(device), layer_data_map)
   5744         ->device_dispatch_table->DestroyQueryPool(device, queryPool, pAllocator);
   5745     // TODO : Clean up any internal data structures using this obj.
   5746 }
   5747 
   5748 VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
   5749                                                      uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride,
   5750                                                      VkQueryResultFlags flags) {
   5751     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5752     unordered_map<QueryObject, vector<VkCommandBuffer>> queriesInFlight;
   5753     GLOBAL_CB_NODE *pCB = nullptr;
   5754     loader_platform_thread_lock_mutex(&globalLock);
   5755     for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) {
   5756         pCB = getCBNode(dev_data, cmdBuffer);
   5757         for (auto queryStatePair : pCB->queryToStateMap) {
   5758             queriesInFlight[queryStatePair.first].push_back(cmdBuffer);
   5759         }
   5760     }
   5761     VkBool32 skip_call = VK_FALSE;
   5762     for (uint32_t i = 0; i < queryCount; ++i) {
   5763         QueryObject query = {queryPool, firstQuery + i};
   5764         auto queryElement = queriesInFlight.find(query);
   5765         auto queryToStateElement = dev_data->queryToStateMap.find(query);
   5766         if (queryToStateElement != dev_data->queryToStateMap.end()) {
   5767         }
   5768         // Available and in flight
   5769         if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() &&
   5770             queryToStateElement->second) {
   5771             for (auto cmdBuffer : queryElement->second) {
   5772                 pCB = getCBNode(dev_data, cmdBuffer);
   5773                 auto queryEventElement = pCB->waitedEventsBeforeQueryReset.find(query);
   5774                 if (queryEventElement == pCB->waitedEventsBeforeQueryReset.end()) {
   5775                     skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   5776                                          VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
   5777                                          "Cannot get query results on queryPool %" PRIu64 " with index %d which is in flight.",
   5778                                          (uint64_t)(queryPool), firstQuery + i);
   5779                 } else {
   5780                     for (auto event : queryEventElement->second) {
   5781                         dev_data->eventMap[event].needsSignaled = true;
   5782                     }
   5783                 }
   5784             }
   5785             // Unavailable and in flight
   5786         } else if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() &&
   5787                    !queryToStateElement->second) {
   5788             // TODO : Can there be the same query in use by multiple command buffers in flight?
   5789             bool make_available = false;
   5790             for (auto cmdBuffer : queryElement->second) {
   5791                 pCB = getCBNode(dev_data, cmdBuffer);
   5792                 make_available |= pCB->queryToStateMap[query];
   5793             }
   5794             if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
   5795                 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   5796                                      VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
   5797                                      "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.",
   5798                                      (uint64_t)(queryPool), firstQuery + i);
   5799             }
   5800             // Unavailable
   5801         } else if (queryToStateElement != dev_data->queryToStateMap.end() && !queryToStateElement->second) {
   5802             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT,
   5803                                  0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
   5804                                  "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.",
   5805                                  (uint64_t)(queryPool), firstQuery + i);
   5806             // Unitialized
   5807         } else if (queryToStateElement == dev_data->queryToStateMap.end()) {
   5808             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT,
   5809                                  0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
   5810                                  "Cannot get query results on queryPool %" PRIu64 " with index %d which is uninitialized.",
   5811                                  (uint64_t)(queryPool), firstQuery + i);
   5812         }
   5813     }
   5814     loader_platform_thread_unlock_mutex(&globalLock);
   5815     if (skip_call)
   5816         return VK_ERROR_VALIDATION_FAILED_EXT;
   5817     return dev_data->device_dispatch_table->GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride,
   5818                                                                 flags);
   5819 }
   5820 
   5821 VkBool32 validateIdleBuffer(const layer_data *my_data, VkBuffer buffer) {
   5822     VkBool32 skip_call = VK_FALSE;
   5823     auto buffer_data = my_data->bufferMap.find(buffer);
   5824     if (buffer_data == my_data->bufferMap.end()) {
   5825         skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   5826                              (uint64_t)(buffer), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
   5827                              "Cannot free buffer %" PRIxLEAST64 " that has not been allocated.", (uint64_t)(buffer));
   5828     } else {
   5829         if (buffer_data->second.in_use.load()) {
   5830             skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   5831                                  (uint64_t)(buffer), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS",
   5832                                  "Cannot free buffer %" PRIxLEAST64 " that is in use by a command buffer.", (uint64_t)(buffer));
   5833         }
   5834     }
   5835     return skip_call;
   5836 }
   5837 
   5838 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5839 vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
   5840     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5841     VkBool32 skipCall = VK_FALSE;
   5842     loader_platform_thread_lock_mutex(&globalLock);
   5843 #if MTMERGESOURCE
   5844     auto item = dev_data->bufferBindingMap.find((uint64_t)buffer);
   5845     if (item != dev_data->bufferBindingMap.end()) {
   5846         skipCall = clear_object_binding(dev_data, device, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT);
   5847         dev_data->bufferBindingMap.erase(item);
   5848     }
   5849 #endif
   5850     if (!validateIdleBuffer(dev_data, buffer) && (VK_FALSE == skipCall)) {
   5851         loader_platform_thread_unlock_mutex(&globalLock);
   5852         dev_data->device_dispatch_table->DestroyBuffer(device, buffer, pAllocator);
   5853         loader_platform_thread_lock_mutex(&globalLock);
   5854     }
   5855     dev_data->bufferMap.erase(buffer);
   5856     loader_platform_thread_unlock_mutex(&globalLock);
   5857 }
   5858 
   5859 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5860 vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
   5861     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5862     dev_data->device_dispatch_table->DestroyBufferView(device, bufferView, pAllocator);
   5863     loader_platform_thread_lock_mutex(&globalLock);
   5864     auto item = dev_data->bufferViewMap.find(bufferView);
   5865     if (item != dev_data->bufferViewMap.end()) {
   5866         dev_data->bufferViewMap.erase(item);
   5867     }
   5868     loader_platform_thread_unlock_mutex(&globalLock);
   5869 }
   5870 
   5871 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
   5872     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5873     VkBool32 skipCall = VK_FALSE;
   5874 #if MTMERGESOURCE
   5875     loader_platform_thread_lock_mutex(&globalLock);
   5876     auto item = dev_data->imageBindingMap.find((uint64_t)image);
   5877     if (item != dev_data->imageBindingMap.end()) {
   5878         skipCall = clear_object_binding(dev_data, device, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
   5879         dev_data->imageBindingMap.erase(item);
   5880     }
   5881     loader_platform_thread_unlock_mutex(&globalLock);
   5882 #endif
   5883     if (VK_FALSE == skipCall)
   5884         dev_data->device_dispatch_table->DestroyImage(device, image, pAllocator);
   5885 
   5886     loader_platform_thread_lock_mutex(&globalLock);
   5887     const auto& entry = dev_data->imageMap.find(image);
   5888     if (entry != dev_data->imageMap.end()) {
   5889         // Clear any memory mapping for this image
   5890         const auto &mem_entry = dev_data->memObjMap.find(entry->second.mem);
   5891         if (mem_entry != dev_data->memObjMap.end())
   5892             mem_entry->second.image = VK_NULL_HANDLE;
   5893 
   5894         // Remove image from imageMap
   5895         dev_data->imageMap.erase(entry);
   5896     }
   5897     const auto& subEntry = dev_data->imageSubresourceMap.find(image);
   5898     if (subEntry != dev_data->imageSubresourceMap.end()) {
   5899         for (const auto& pair : subEntry->second) {
   5900             dev_data->imageLayoutMap.erase(pair);
   5901         }
   5902         dev_data->imageSubresourceMap.erase(subEntry);
   5903     }
   5904     loader_platform_thread_unlock_mutex(&globalLock);
   5905 }
   5906 #if MTMERGESOURCE
   5907 VkBool32 print_memory_range_error(layer_data *dev_data, const uint64_t object_handle, const uint64_t other_handle,
   5908                                   VkDebugReportObjectTypeEXT object_type) {
   5909     if (object_type == VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT) {
   5910         return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0,
   5911                        MEMTRACK_INVALID_ALIASING, "MEM", "Buffer %" PRIx64 " is alised with image %" PRIx64, object_handle,
   5912                        other_handle);
   5913     } else {
   5914         return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0,
   5915                        MEMTRACK_INVALID_ALIASING, "MEM", "Image %" PRIx64 " is alised with buffer %" PRIx64, object_handle,
   5916                        other_handle);
   5917     }
   5918 }
   5919 
   5920 VkBool32 validate_memory_range(layer_data *dev_data, const vector<MEMORY_RANGE> &ranges, const MEMORY_RANGE &new_range,
   5921                                VkDebugReportObjectTypeEXT object_type) {
   5922     VkBool32 skip_call = false;
   5923 
   5924     for (auto range : ranges) {
   5925         if ((range.end & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1)) <
   5926             (new_range.start & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1)))
   5927             continue;
   5928         if ((range.start & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1)) >
   5929             (new_range.end & ~(dev_data->physDevProperties.properties.limits.bufferImageGranularity - 1)))
   5930             continue;
   5931         skip_call |= print_memory_range_error(dev_data, new_range.handle, range.handle, object_type);
   5932     }
   5933     return skip_call;
   5934 }
   5935 
   5936 VkBool32 validate_buffer_image_aliasing(layer_data *dev_data, uint64_t handle, VkDeviceMemory mem, VkDeviceSize memoryOffset,
   5937                                         VkMemoryRequirements memRequirements, vector<MEMORY_RANGE> &ranges,
   5938                                         const vector<MEMORY_RANGE> &other_ranges, VkDebugReportObjectTypeEXT object_type) {
   5939     MEMORY_RANGE range;
   5940     range.handle = handle;
   5941     range.memory = mem;
   5942     range.start = memoryOffset;
   5943     range.end = memoryOffset + memRequirements.size - 1;
   5944     ranges.push_back(range);
   5945     return validate_memory_range(dev_data, other_ranges, range, object_type);
   5946 }
   5947 
   5948 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   5949 vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
   5950     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5951     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   5952     loader_platform_thread_lock_mutex(&globalLock);
   5953     // Track objects tied to memory
   5954     uint64_t buffer_handle = (uint64_t)(buffer);
   5955     VkBool32 skipCall =
   5956         set_mem_binding(dev_data, device, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory");
   5957     add_object_binding_info(dev_data, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, mem);
   5958     {
   5959         VkMemoryRequirements memRequirements;
   5960         // MTMTODO : Shouldn't this call down the chain?
   5961         vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
   5962         skipCall |= validate_buffer_image_aliasing(dev_data, buffer_handle, mem, memoryOffset, memRequirements,
   5963                                                    dev_data->memObjMap[mem].bufferRanges, dev_data->memObjMap[mem].imageRanges,
   5964                                                    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT);
   5965     }
   5966     print_mem_list(dev_data, device);
   5967     loader_platform_thread_unlock_mutex(&globalLock);
   5968     if (VK_FALSE == skipCall) {
   5969         result = dev_data->device_dispatch_table->BindBufferMemory(device, buffer, mem, memoryOffset);
   5970     }
   5971     return result;
   5972 }
   5973 
   5974 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5975 vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) {
   5976     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5977     // TODO : What to track here?
   5978     //   Could potentially save returned mem requirements and validate values passed into BindBufferMemory
   5979     my_data->device_dispatch_table->GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
   5980 }
   5981 
   5982 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5983 vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
   5984     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   5985     // TODO : What to track here?
   5986     //   Could potentially save returned mem requirements and validate values passed into BindImageMemory
   5987     my_data->device_dispatch_table->GetImageMemoryRequirements(device, image, pMemoryRequirements);
   5988 }
   5989 #endif
   5990 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5991 vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
   5992     get_my_data_ptr(get_dispatch_key(device), layer_data_map)
   5993         ->device_dispatch_table->DestroyImageView(device, imageView, pAllocator);
   5994     // TODO : Clean up any internal data structures using this obj.
   5995 }
   5996 
   5997 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   5998 vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) {
   5999     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6000 
   6001     loader_platform_thread_lock_mutex(&globalLock);
   6002 
   6003     my_data->shaderModuleMap.erase(shaderModule);
   6004 
   6005     loader_platform_thread_unlock_mutex(&globalLock);
   6006 
   6007     my_data->device_dispatch_table->DestroyShaderModule(device, shaderModule, pAllocator);
   6008 }
   6009 
   6010 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6011 vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
   6012     get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroyPipeline(device, pipeline, pAllocator);
   6013     // TODO : Clean up any internal data structures using this obj.
   6014 }
   6015 
   6016 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6017 vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) {
   6018     get_my_data_ptr(get_dispatch_key(device), layer_data_map)
   6019         ->device_dispatch_table->DestroyPipelineLayout(device, pipelineLayout, pAllocator);
   6020     // TODO : Clean up any internal data structures using this obj.
   6021 }
   6022 
   6023 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6024 vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
   6025     get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroySampler(device, sampler, pAllocator);
   6026     // TODO : Clean up any internal data structures using this obj.
   6027 }
   6028 
   6029 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6030 vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) {
   6031     get_my_data_ptr(get_dispatch_key(device), layer_data_map)
   6032         ->device_dispatch_table->DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
   6033     // TODO : Clean up any internal data structures using this obj.
   6034 }
   6035 
   6036 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6037 vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) {
   6038     get_my_data_ptr(get_dispatch_key(device), layer_data_map)
   6039         ->device_dispatch_table->DestroyDescriptorPool(device, descriptorPool, pAllocator);
   6040     // TODO : Clean up any internal data structures using this obj.
   6041 }
   6042 
   6043 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6044 vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) {
   6045     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6046 
   6047     bool skip_call = false;
   6048     loader_platform_thread_lock_mutex(&globalLock);
   6049     for (uint32_t i = 0; i < commandBufferCount; i++) {
   6050 #if MTMERGESOURCE
   6051         clear_cmd_buf_and_mem_references(dev_data, pCommandBuffers[i]);
   6052 #endif
   6053         if (dev_data->globalInFlightCmdBuffers.count(pCommandBuffers[i])) {
   6054             skip_call |=
   6055                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   6056                         reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
   6057                         "Attempt to free command buffer (%#" PRIxLEAST64 ") which is in use.",
   6058                         reinterpret_cast<uint64_t>(pCommandBuffers[i]));
   6059         }
   6060         // Delete CB information structure, and remove from commandBufferMap
   6061         auto cb = dev_data->commandBufferMap.find(pCommandBuffers[i]);
   6062         if (cb != dev_data->commandBufferMap.end()) {
   6063             // reset prior to delete for data clean-up
   6064             resetCB(dev_data, (*cb).second->commandBuffer);
   6065             delete (*cb).second;
   6066             dev_data->commandBufferMap.erase(cb);
   6067         }
   6068 
   6069         // Remove commandBuffer reference from commandPoolMap
   6070         dev_data->commandPoolMap[commandPool].commandBuffers.remove(pCommandBuffers[i]);
   6071     }
   6072 #if MTMERGESOURCE
   6073     printCBList(dev_data, device);
   6074 #endif
   6075     loader_platform_thread_unlock_mutex(&globalLock);
   6076 
   6077     if (!skip_call)
   6078         dev_data->device_dispatch_table->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
   6079 }
   6080 
   6081 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
   6082                                                                    const VkAllocationCallbacks *pAllocator,
   6083                                                                    VkCommandPool *pCommandPool) {
   6084     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6085 
   6086     VkResult result = dev_data->device_dispatch_table->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
   6087 
   6088     if (VK_SUCCESS == result) {
   6089         loader_platform_thread_lock_mutex(&globalLock);
   6090         dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
   6091         dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
   6092         loader_platform_thread_unlock_mutex(&globalLock);
   6093     }
   6094     return result;
   6095 }
   6096 
   6097 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
   6098                                                                  const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
   6099 
   6100     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6101     VkResult result = dev_data->device_dispatch_table->CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
   6102     if (result == VK_SUCCESS) {
   6103         loader_platform_thread_lock_mutex(&globalLock);
   6104         dev_data->queryPoolMap[*pQueryPool].createInfo = *pCreateInfo;
   6105         loader_platform_thread_unlock_mutex(&globalLock);
   6106     }
   6107     return result;
   6108 }
   6109 
   6110 VkBool32 validateCommandBuffersNotInUse(const layer_data *dev_data, VkCommandPool commandPool) {
   6111     VkBool32 skipCall = VK_FALSE;
   6112     auto pool_data = dev_data->commandPoolMap.find(commandPool);
   6113     if (pool_data != dev_data->commandPoolMap.end()) {
   6114         for (auto cmdBuffer : pool_data->second.commandBuffers) {
   6115             if (dev_data->globalInFlightCmdBuffers.count(cmdBuffer)) {
   6116                 skipCall |=
   6117                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT,
   6118                             (uint64_t)(commandPool), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS",
   6119                             "Cannot reset command pool %" PRIx64 " when allocated command buffer %" PRIx64 " is in use.",
   6120                             (uint64_t)(commandPool), (uint64_t)(cmdBuffer));
   6121             }
   6122         }
   6123     }
   6124     return skipCall;
   6125 }
   6126 
   6127 // Destroy commandPool along with all of the commandBuffers allocated from that pool
   6128 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6129 vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
   6130     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6131     bool commandBufferComplete = false;
   6132     bool skipCall = false;
   6133     loader_platform_thread_lock_mutex(&globalLock);
   6134 #if MTMERGESOURCE
   6135     // Verify that command buffers in pool are complete (not in-flight)
   6136     // MTMTODO : Merge this with code below (separate *NotInUse() call)
   6137     for (auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin();
   6138          it != dev_data->commandPoolMap[commandPool].commandBuffers.end(); it++) {
   6139         commandBufferComplete = VK_FALSE;
   6140         skipCall = checkCBCompleted(dev_data, *it, &commandBufferComplete);
   6141         if (VK_FALSE == commandBufferComplete) {
   6142             skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   6143                                 (uint64_t)(*it), __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM",
   6144                                 "Destroying Command Pool 0x%" PRIxLEAST64 " before "
   6145                                 "its command buffer (0x%" PRIxLEAST64 ") has completed.",
   6146                                 (uint64_t)(commandPool), reinterpret_cast<uint64_t>(*it));
   6147         }
   6148     }
   6149 #endif
   6150     // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandPoolMap
   6151     if (dev_data->commandPoolMap.find(commandPool) != dev_data->commandPoolMap.end()) {
   6152         for (auto poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.begin();
   6153              poolCb != dev_data->commandPoolMap[commandPool].commandBuffers.end();) {
   6154             auto del_cb = dev_data->commandBufferMap.find(*poolCb);
   6155             delete (*del_cb).second;                  // delete CB info structure
   6156             dev_data->commandBufferMap.erase(del_cb); // Remove this command buffer
   6157             poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.erase(
   6158                 poolCb); // Remove CB reference from commandPoolMap's list
   6159         }
   6160     }
   6161     dev_data->commandPoolMap.erase(commandPool);
   6162 
   6163     loader_platform_thread_unlock_mutex(&globalLock);
   6164 
   6165     if (VK_TRUE == validateCommandBuffersNotInUse(dev_data, commandPool))
   6166         return;
   6167 
   6168     if (!skipCall)
   6169         dev_data->device_dispatch_table->DestroyCommandPool(device, commandPool, pAllocator);
   6170 #if MTMERGESOURCE
   6171     loader_platform_thread_lock_mutex(&globalLock);
   6172     auto item = dev_data->commandPoolMap[commandPool].commandBuffers.begin();
   6173     // Remove command buffers from command buffer map
   6174     while (item != dev_data->commandPoolMap[commandPool].commandBuffers.end()) {
   6175         auto del_item = item++;
   6176         delete_cmd_buf_info(dev_data, commandPool, *del_item);
   6177     }
   6178     dev_data->commandPoolMap.erase(commandPool);
   6179     loader_platform_thread_unlock_mutex(&globalLock);
   6180 #endif
   6181 }
   6182 
   6183 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6184 vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
   6185     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6186     bool commandBufferComplete = false;
   6187     bool skipCall = false;
   6188     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   6189 #if MTMERGESOURCE
   6190     // MTMTODO : Merge this with *NotInUse() call below
   6191     loader_platform_thread_lock_mutex(&globalLock);
   6192     auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin();
   6193     // Verify that CB's in pool are complete (not in-flight)
   6194     while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) {
   6195         skipCall = checkCBCompleted(dev_data, (*it), &commandBufferComplete);
   6196         if (!commandBufferComplete) {
   6197             skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   6198                                 (uint64_t)(*it), __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM",
   6199                                 "Resetting CB %p before it has completed. You must check CB "
   6200                                 "flag before calling vkResetCommandBuffer().",
   6201                                 (*it));
   6202         } else {
   6203             // Clear memory references at this point.
   6204             clear_cmd_buf_and_mem_references(dev_data, (*it));
   6205         }
   6206         ++it;
   6207     }
   6208     loader_platform_thread_unlock_mutex(&globalLock);
   6209 #endif
   6210     if (VK_TRUE == validateCommandBuffersNotInUse(dev_data, commandPool))
   6211         return VK_ERROR_VALIDATION_FAILED_EXT;
   6212 
   6213     if (!skipCall)
   6214         result = dev_data->device_dispatch_table->ResetCommandPool(device, commandPool, flags);
   6215 
   6216     // Reset all of the CBs allocated from this pool
   6217     if (VK_SUCCESS == result) {
   6218         loader_platform_thread_lock_mutex(&globalLock);
   6219         auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin();
   6220         while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) {
   6221             resetCB(dev_data, (*it));
   6222             ++it;
   6223         }
   6224         loader_platform_thread_unlock_mutex(&globalLock);
   6225     }
   6226     return result;
   6227 }
   6228 
   6229 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
   6230     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6231     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   6232     bool skipCall = false;
   6233     loader_platform_thread_lock_mutex(&globalLock);
   6234     for (uint32_t i = 0; i < fenceCount; ++i) {
   6235 #if MTMERGESOURCE
   6236         // Reset fence state in fenceCreateInfo structure
   6237         // MTMTODO : Merge with code below
   6238         auto fence_item = dev_data->fenceMap.find(pFences[i]);
   6239         if (fence_item != dev_data->fenceMap.end()) {
   6240             // Validate fences in SIGNALED state
   6241             if (!(fence_item->second.createInfo.flags & VK_FENCE_CREATE_SIGNALED_BIT)) {
   6242                 // TODO: I don't see a Valid Usage section for ResetFences. This behavior should be documented there.
   6243                 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
   6244                                    (uint64_t)pFences[i], __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
   6245                                    "Fence %#" PRIxLEAST64 " submitted to VkResetFences in UNSIGNALED STATE", (uint64_t)pFences[i]);
   6246             } else {
   6247                 fence_item->second.createInfo.flags =
   6248                     static_cast<VkFenceCreateFlags>(fence_item->second.createInfo.flags & ~VK_FENCE_CREATE_SIGNALED_BIT);
   6249             }
   6250         }
   6251 #endif
   6252         if (dev_data->fenceMap[pFences[i]].in_use.load()) {
   6253             skipCall |=
   6254                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
   6255                         reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
   6256                         "Fence %#" PRIx64 " is in use by a command buffer.", reinterpret_cast<const uint64_t &>(pFences[i]));
   6257         }
   6258     }
   6259     loader_platform_thread_unlock_mutex(&globalLock);
   6260     if (!skipCall)
   6261         result = dev_data->device_dispatch_table->ResetFences(device, fenceCount, pFences);
   6262     return result;
   6263 }
   6264 
   6265 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6266 vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
   6267     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6268     auto fbNode = dev_data->frameBufferMap.find(framebuffer);
   6269     if (fbNode != dev_data->frameBufferMap.end()) {
   6270         for (auto cb : fbNode->second.referencingCmdBuffers) {
   6271             auto cbNode = dev_data->commandBufferMap.find(cb);
   6272             if (cbNode != dev_data->commandBufferMap.end()) {
   6273                 // Set CB as invalid and record destroyed framebuffer
   6274                 cbNode->second->state = CB_INVALID;
   6275                 loader_platform_thread_lock_mutex(&globalLock);
   6276                 cbNode->second->destroyedFramebuffers.insert(framebuffer);
   6277                 loader_platform_thread_unlock_mutex(&globalLock);
   6278             }
   6279         }
   6280         loader_platform_thread_lock_mutex(&globalLock);
   6281         dev_data->frameBufferMap.erase(framebuffer);
   6282         loader_platform_thread_unlock_mutex(&globalLock);
   6283     }
   6284     dev_data->device_dispatch_table->DestroyFramebuffer(device, framebuffer, pAllocator);
   6285 }
   6286 
   6287 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6288 vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
   6289     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6290     dev_data->device_dispatch_table->DestroyRenderPass(device, renderPass, pAllocator);
   6291     loader_platform_thread_lock_mutex(&globalLock);
   6292     dev_data->renderPassMap.erase(renderPass);
   6293     loader_platform_thread_unlock_mutex(&globalLock);
   6294 }
   6295 
   6296 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
   6297                                                               const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
   6298     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6299 
   6300     VkResult result = dev_data->device_dispatch_table->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
   6301 
   6302     if (VK_SUCCESS == result) {
   6303         loader_platform_thread_lock_mutex(&globalLock);
   6304 #if MTMERGESOURCE
   6305         add_object_create_info(dev_data, (uint64_t)*pBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, pCreateInfo);
   6306 #endif
   6307         // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid
   6308         dev_data->bufferMap[*pBuffer].create_info = unique_ptr<VkBufferCreateInfo>(new VkBufferCreateInfo(*pCreateInfo));
   6309         dev_data->bufferMap[*pBuffer].in_use.store(0);
   6310         loader_platform_thread_unlock_mutex(&globalLock);
   6311     }
   6312     return result;
   6313 }
   6314 
   6315 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
   6316                                                                   const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
   6317     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6318     VkResult result = dev_data->device_dispatch_table->CreateBufferView(device, pCreateInfo, pAllocator, pView);
   6319     if (VK_SUCCESS == result) {
   6320         loader_platform_thread_lock_mutex(&globalLock);
   6321         dev_data->bufferViewMap[*pView] = VkBufferViewCreateInfo(*pCreateInfo);
   6322 #if MTMERGESOURCE
   6323         // In order to create a valid buffer view, the buffer must have been created with at least one of the
   6324         // following flags:  UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT
   6325         validate_buffer_usage_flags(dev_data, device, pCreateInfo->buffer,
   6326                                     VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, VK_FALSE,
   6327                                     "vkCreateBufferView()", "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT");
   6328 #endif
   6329         loader_platform_thread_unlock_mutex(&globalLock);
   6330     }
   6331     return result;
   6332 }
   6333 
   6334 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
   6335                                                              const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
   6336     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6337 
   6338     VkResult result = dev_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage);
   6339 
   6340     if (VK_SUCCESS == result) {
   6341         loader_platform_thread_lock_mutex(&globalLock);
   6342 #if MTMERGESOURCE
   6343         add_object_create_info(dev_data, (uint64_t)*pImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, pCreateInfo);
   6344 #endif
   6345         IMAGE_LAYOUT_NODE image_node;
   6346         image_node.layout = pCreateInfo->initialLayout;
   6347         image_node.format = pCreateInfo->format;
   6348         dev_data->imageMap[*pImage].createInfo = *pCreateInfo;
   6349         ImageSubresourcePair subpair = {*pImage, false, VkImageSubresource()};
   6350         dev_data->imageSubresourceMap[*pImage].push_back(subpair);
   6351         dev_data->imageLayoutMap[subpair] = image_node;
   6352         loader_platform_thread_unlock_mutex(&globalLock);
   6353     }
   6354     return result;
   6355 }
   6356 
   6357 static void ResolveRemainingLevelsLayers(layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) {
   6358     /* expects globalLock to be held by caller */
   6359 
   6360     auto image_node_it = dev_data->imageMap.find(image);
   6361     if (image_node_it != dev_data->imageMap.end()) {
   6362         /* If the caller used the special values VK_REMAINING_MIP_LEVELS and
   6363          * VK_REMAINING_ARRAY_LAYERS, resolve them now in our internal state to
   6364          * the actual values.
   6365          */
   6366         if (range->levelCount == VK_REMAINING_MIP_LEVELS) {
   6367             range->levelCount = image_node_it->second.createInfo.mipLevels - range->baseMipLevel;
   6368         }
   6369 
   6370         if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) {
   6371             range->layerCount = image_node_it->second.createInfo.arrayLayers - range->baseArrayLayer;
   6372         }
   6373     }
   6374 }
   6375 
   6376 // Return the correct layer/level counts if the caller used the special
   6377 // values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS.
   6378 static void ResolveRemainingLevelsLayers(layer_data *dev_data, uint32_t *levels, uint32_t *layers, VkImageSubresourceRange range,
   6379                                          VkImage image) {
   6380     /* expects globalLock to be held by caller */
   6381 
   6382     *levels = range.levelCount;
   6383     *layers = range.layerCount;
   6384     auto image_node_it = dev_data->imageMap.find(image);
   6385     if (image_node_it != dev_data->imageMap.end()) {
   6386         if (range.levelCount == VK_REMAINING_MIP_LEVELS) {
   6387             *levels = image_node_it->second.createInfo.mipLevels - range.baseMipLevel;
   6388         }
   6389         if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) {
   6390             *layers = image_node_it->second.createInfo.arrayLayers - range.baseArrayLayer;
   6391         }
   6392     }
   6393 }
   6394 
   6395 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
   6396                                                                  const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
   6397     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6398     VkResult result = dev_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView);
   6399     if (VK_SUCCESS == result) {
   6400         loader_platform_thread_lock_mutex(&globalLock);
   6401         VkImageViewCreateInfo localCI = VkImageViewCreateInfo(*pCreateInfo);
   6402         ResolveRemainingLevelsLayers(dev_data, &localCI.subresourceRange, pCreateInfo->image);
   6403         dev_data->imageViewMap[*pView] = localCI;
   6404 #if MTMERGESOURCE
   6405         // Validate that img has correct usage flags set
   6406         validate_image_usage_flags(dev_data, device, pCreateInfo->image,
   6407                                    VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
   6408                                        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
   6409                                    VK_FALSE, "vkCreateImageView()", "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT]_BIT");
   6410 #endif
   6411         loader_platform_thread_unlock_mutex(&globalLock);
   6412     }
   6413     return result;
   6414 }
   6415 
   6416 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6417 vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
   6418     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6419     VkResult result = dev_data->device_dispatch_table->CreateFence(device, pCreateInfo, pAllocator, pFence);
   6420     if (VK_SUCCESS == result) {
   6421         loader_platform_thread_lock_mutex(&globalLock);
   6422         FENCE_NODE *pFN = &dev_data->fenceMap[*pFence];
   6423 #if MTMERGESOURCE
   6424         memset(pFN, 0, sizeof(MT_FENCE_INFO));
   6425         memcpy(&(pFN->createInfo), pCreateInfo, sizeof(VkFenceCreateInfo));
   6426         if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
   6427             pFN->firstTimeFlag = VK_TRUE;
   6428         }
   6429 #endif
   6430         pFN->in_use.store(0);
   6431         loader_platform_thread_unlock_mutex(&globalLock);
   6432     }
   6433     return result;
   6434 }
   6435 
   6436 // TODO handle pipeline caches
   6437 VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
   6438                                                      const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
   6439     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6440     VkResult result = dev_data->device_dispatch_table->CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
   6441     return result;
   6442 }
   6443 
   6444 VKAPI_ATTR void VKAPI_CALL
   6445 vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator) {
   6446     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6447     dev_data->device_dispatch_table->DestroyPipelineCache(device, pipelineCache, pAllocator);
   6448 }
   6449 
   6450 VKAPI_ATTR VkResult VKAPI_CALL
   6451 vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) {
   6452     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6453     VkResult result = dev_data->device_dispatch_table->GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
   6454     return result;
   6455 }
   6456 
   6457 VKAPI_ATTR VkResult VKAPI_CALL
   6458 vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches) {
   6459     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6460     VkResult result = dev_data->device_dispatch_table->MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
   6461     return result;
   6462 }
   6463 
   6464 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6465 vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
   6466                           const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
   6467                           VkPipeline *pPipelines) {
   6468     VkResult result = VK_SUCCESS;
   6469     // TODO What to do with pipelineCache?
   6470     // The order of operations here is a little convoluted but gets the job done
   6471     //  1. Pipeline create state is first shadowed into PIPELINE_NODE struct
   6472     //  2. Create state is then validated (which uses flags setup during shadowing)
   6473     //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
   6474     VkBool32 skipCall = VK_FALSE;
   6475     // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
   6476     vector<PIPELINE_NODE *> pPipeNode(count);
   6477     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6478 
   6479     uint32_t i = 0;
   6480     loader_platform_thread_lock_mutex(&globalLock);
   6481 
   6482     for (i = 0; i < count; i++) {
   6483         pPipeNode[i] = initGraphicsPipeline(dev_data, &pCreateInfos[i]);
   6484         skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode, i);
   6485     }
   6486 
   6487     if (VK_FALSE == skipCall) {
   6488         loader_platform_thread_unlock_mutex(&globalLock);
   6489         result = dev_data->device_dispatch_table->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
   6490                                                                           pPipelines);
   6491         loader_platform_thread_lock_mutex(&globalLock);
   6492         for (i = 0; i < count; i++) {
   6493             pPipeNode[i]->pipeline = pPipelines[i];
   6494             dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i];
   6495         }
   6496         loader_platform_thread_unlock_mutex(&globalLock);
   6497     } else {
   6498         for (i = 0; i < count; i++) {
   6499             delete pPipeNode[i];
   6500         }
   6501         loader_platform_thread_unlock_mutex(&globalLock);
   6502         return VK_ERROR_VALIDATION_FAILED_EXT;
   6503     }
   6504     return result;
   6505 }
   6506 
   6507 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6508 vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
   6509                          const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
   6510                          VkPipeline *pPipelines) {
   6511     VkResult result = VK_SUCCESS;
   6512     VkBool32 skipCall = VK_FALSE;
   6513 
   6514     // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
   6515     vector<PIPELINE_NODE *> pPipeNode(count);
   6516     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6517 
   6518     uint32_t i = 0;
   6519     loader_platform_thread_lock_mutex(&globalLock);
   6520     for (i = 0; i < count; i++) {
   6521         // TODO: Verify compute stage bits
   6522 
   6523         // Create and initialize internal tracking data structure
   6524         pPipeNode[i] = new PIPELINE_NODE;
   6525         memcpy(&pPipeNode[i]->computePipelineCI, (const void *)&pCreateInfos[i], sizeof(VkComputePipelineCreateInfo));
   6526 
   6527         // TODO: Add Compute Pipeline Verification
   6528         // skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode[i]);
   6529     }
   6530 
   6531     if (VK_FALSE == skipCall) {
   6532         loader_platform_thread_unlock_mutex(&globalLock);
   6533         result = dev_data->device_dispatch_table->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
   6534                                                                          pPipelines);
   6535         loader_platform_thread_lock_mutex(&globalLock);
   6536         for (i = 0; i < count; i++) {
   6537             pPipeNode[i]->pipeline = pPipelines[i];
   6538             dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i];
   6539         }
   6540         loader_platform_thread_unlock_mutex(&globalLock);
   6541     } else {
   6542         for (i = 0; i < count; i++) {
   6543             // Clean up any locally allocated data structures
   6544             delete pPipeNode[i];
   6545         }
   6546         loader_platform_thread_unlock_mutex(&globalLock);
   6547         return VK_ERROR_VALIDATION_FAILED_EXT;
   6548     }
   6549     return result;
   6550 }
   6551 
   6552 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
   6553                                                                const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
   6554     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6555     VkResult result = dev_data->device_dispatch_table->CreateSampler(device, pCreateInfo, pAllocator, pSampler);
   6556     if (VK_SUCCESS == result) {
   6557         loader_platform_thread_lock_mutex(&globalLock);
   6558         dev_data->sampleMap[*pSampler] = unique_ptr<SAMPLER_NODE>(new SAMPLER_NODE(pSampler, pCreateInfo));
   6559         loader_platform_thread_unlock_mutex(&globalLock);
   6560     }
   6561     return result;
   6562 }
   6563 
   6564 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6565 vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
   6566                             const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) {
   6567     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6568     VkResult result = dev_data->device_dispatch_table->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
   6569     if (VK_SUCCESS == result) {
   6570         // TODOSC : Capture layout bindings set
   6571         LAYOUT_NODE *pNewNode = new LAYOUT_NODE;
   6572         if (NULL == pNewNode) {
   6573             if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
   6574                         (uint64_t)*pSetLayout, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
   6575                         "Out of memory while attempting to allocate LAYOUT_NODE in vkCreateDescriptorSetLayout()"))
   6576                 return VK_ERROR_VALIDATION_FAILED_EXT;
   6577         }
   6578         memcpy((void *)&pNewNode->createInfo, pCreateInfo, sizeof(VkDescriptorSetLayoutCreateInfo));
   6579         pNewNode->createInfo.pBindings = new VkDescriptorSetLayoutBinding[pCreateInfo->bindingCount];
   6580         memcpy((void *)pNewNode->createInfo.pBindings, pCreateInfo->pBindings,
   6581                sizeof(VkDescriptorSetLayoutBinding) * pCreateInfo->bindingCount);
   6582         // g++ does not like reserve with size 0
   6583         if (pCreateInfo->bindingCount)
   6584             pNewNode->bindingToIndexMap.reserve(pCreateInfo->bindingCount);
   6585         uint32_t totalCount = 0;
   6586         for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
   6587             if (!pNewNode->bindingToIndexMap.emplace(pCreateInfo->pBindings[i].binding, i).second) {
   6588                 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   6589                             VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)*pSetLayout, __LINE__,
   6590                             DRAWSTATE_INVALID_LAYOUT, "DS", "duplicated binding number in "
   6591                                                             "VkDescriptorSetLayoutBinding"))
   6592                     return VK_ERROR_VALIDATION_FAILED_EXT;
   6593             } else {
   6594                 pNewNode->bindingToIndexMap[pCreateInfo->pBindings[i].binding] = i;
   6595             }
   6596             totalCount += pCreateInfo->pBindings[i].descriptorCount;
   6597             if (pCreateInfo->pBindings[i].pImmutableSamplers) {
   6598                 VkSampler **ppIS = (VkSampler **)&pNewNode->createInfo.pBindings[i].pImmutableSamplers;
   6599                 *ppIS = new VkSampler[pCreateInfo->pBindings[i].descriptorCount];
   6600                 memcpy(*ppIS, pCreateInfo->pBindings[i].pImmutableSamplers,
   6601                        pCreateInfo->pBindings[i].descriptorCount * sizeof(VkSampler));
   6602             }
   6603         }
   6604         pNewNode->layout = *pSetLayout;
   6605         pNewNode->startIndex = 0;
   6606         if (totalCount > 0) {
   6607             pNewNode->descriptorTypes.resize(totalCount);
   6608             pNewNode->stageFlags.resize(totalCount);
   6609             uint32_t offset = 0;
   6610             uint32_t j = 0;
   6611             VkDescriptorType dType;
   6612             for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
   6613                 dType = pCreateInfo->pBindings[i].descriptorType;
   6614                 for (j = 0; j < pCreateInfo->pBindings[i].descriptorCount; j++) {
   6615                     pNewNode->descriptorTypes[offset + j] = dType;
   6616                     pNewNode->stageFlags[offset + j] = pCreateInfo->pBindings[i].stageFlags;
   6617                     if ((dType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
   6618                         (dType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
   6619                         pNewNode->dynamicDescriptorCount++;
   6620                     }
   6621                 }
   6622                 offset += j;
   6623             }
   6624             pNewNode->endIndex = pNewNode->startIndex + totalCount - 1;
   6625         } else { // no descriptors
   6626             pNewNode->endIndex = 0;
   6627         }
   6628         // Put new node at Head of global Layer list
   6629         loader_platform_thread_lock_mutex(&globalLock);
   6630         dev_data->descriptorSetLayoutMap[*pSetLayout] = pNewNode;
   6631         loader_platform_thread_unlock_mutex(&globalLock);
   6632     }
   6633     return result;
   6634 }
   6635 
   6636 static bool validatePushConstantSize(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
   6637                                      const char *caller_name) {
   6638     bool skipCall = false;
   6639     if ((offset + size) > dev_data->physDevProperties.properties.limits.maxPushConstantsSize) {
   6640         skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   6641                            DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants with offset %u and size %u that "
   6642                                                                  "exceeds this device's maxPushConstantSize of %u.",
   6643                            caller_name, offset, size, dev_data->physDevProperties.properties.limits.maxPushConstantsSize);
   6644     }
   6645     return skipCall;
   6646 }
   6647 
   6648 VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
   6649                                                       const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
   6650     bool skipCall = false;
   6651     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6652     uint32_t i = 0;
   6653     for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
   6654         skipCall |= validatePushConstantSize(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
   6655                                              pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()");
   6656         if ((pCreateInfo->pPushConstantRanges[i].size == 0) || ((pCreateInfo->pPushConstantRanges[i].size & 0x3) != 0)) {
   6657             skipCall |=
   6658                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   6659                         DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCreatePipelineLayout() call has push constant index %u with "
   6660                                                               "size %u. Size must be greater than zero and a multiple of 4.",
   6661                         i, pCreateInfo->pPushConstantRanges[i].size);
   6662         }
   6663         // TODO : Add warning if ranges overlap
   6664     }
   6665     VkResult result = dev_data->device_dispatch_table->CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
   6666     if (VK_SUCCESS == result) {
   6667         loader_platform_thread_lock_mutex(&globalLock);
   6668         // TODOSC : Merge capture of the setLayouts per pipeline
   6669         PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
   6670         plNode.descriptorSetLayouts.resize(pCreateInfo->setLayoutCount);
   6671         for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
   6672             plNode.descriptorSetLayouts[i] = pCreateInfo->pSetLayouts[i];
   6673         }
   6674         plNode.pushConstantRanges.resize(pCreateInfo->pushConstantRangeCount);
   6675         for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
   6676             plNode.pushConstantRanges[i] = pCreateInfo->pPushConstantRanges[i];
   6677         }
   6678         loader_platform_thread_unlock_mutex(&globalLock);
   6679     }
   6680     return result;
   6681 }
   6682 
   6683 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6684 vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
   6685                        VkDescriptorPool *pDescriptorPool) {
   6686     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6687     VkResult result = dev_data->device_dispatch_table->CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
   6688     if (VK_SUCCESS == result) {
   6689         // Insert this pool into Global Pool LL at head
   6690         if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
   6691                     (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool %#" PRIxLEAST64,
   6692                     (uint64_t)*pDescriptorPool))
   6693             return VK_ERROR_VALIDATION_FAILED_EXT;
   6694         DESCRIPTOR_POOL_NODE *pNewNode = new DESCRIPTOR_POOL_NODE(*pDescriptorPool, pCreateInfo);
   6695         if (NULL == pNewNode) {
   6696             if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
   6697                         (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
   6698                         "Out of memory while attempting to allocate DESCRIPTOR_POOL_NODE in vkCreateDescriptorPool()"))
   6699                 return VK_ERROR_VALIDATION_FAILED_EXT;
   6700         } else {
   6701             loader_platform_thread_lock_mutex(&globalLock);
   6702             dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
   6703             loader_platform_thread_unlock_mutex(&globalLock);
   6704         }
   6705     } else {
   6706         // Need to do anything if pool create fails?
   6707     }
   6708     return result;
   6709 }
   6710 
   6711 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6712 vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) {
   6713     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6714     VkResult result = dev_data->device_dispatch_table->ResetDescriptorPool(device, descriptorPool, flags);
   6715     if (VK_SUCCESS == result) {
   6716         loader_platform_thread_lock_mutex(&globalLock);
   6717         clearDescriptorPool(dev_data, device, descriptorPool, flags);
   6718         loader_platform_thread_unlock_mutex(&globalLock);
   6719     }
   6720     return result;
   6721 }
   6722 
   6723 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6724 vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) {
   6725     VkBool32 skipCall = VK_FALSE;
   6726     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6727 
   6728     loader_platform_thread_lock_mutex(&globalLock);
   6729     // Verify that requested descriptorSets are available in pool
   6730     DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
   6731     if (!pPoolNode) {
   6732         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
   6733                             (uint64_t)pAllocateInfo->descriptorPool, __LINE__, DRAWSTATE_INVALID_POOL, "DS",
   6734                             "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call",
   6735                             (uint64_t)pAllocateInfo->descriptorPool);
   6736     } else { // Make sure pool has all the available descriptors before calling down chain
   6737         skipCall |= validate_descriptor_availability_in_pool(dev_data, pPoolNode, pAllocateInfo->descriptorSetCount,
   6738                                                              pAllocateInfo->pSetLayouts);
   6739     }
   6740     loader_platform_thread_unlock_mutex(&globalLock);
   6741     if (skipCall)
   6742         return VK_ERROR_VALIDATION_FAILED_EXT;
   6743     VkResult result = dev_data->device_dispatch_table->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
   6744     if (VK_SUCCESS == result) {
   6745         loader_platform_thread_lock_mutex(&globalLock);
   6746         DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
   6747         if (pPoolNode) {
   6748             if (pAllocateInfo->descriptorSetCount == 0) {
   6749                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   6750                         pAllocateInfo->descriptorSetCount, __LINE__, DRAWSTATE_NONE, "DS",
   6751                         "AllocateDescriptorSets called with 0 count");
   6752             }
   6753             for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
   6754                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   6755                         (uint64_t)pDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS", "Created Descriptor Set %#" PRIxLEAST64,
   6756                         (uint64_t)pDescriptorSets[i]);
   6757                 // Create new set node and add to head of pool nodes
   6758                 SET_NODE *pNewNode = new SET_NODE;
   6759                 if (NULL == pNewNode) {
   6760                     if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   6761                                 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
   6762                                 DRAWSTATE_OUT_OF_MEMORY, "DS",
   6763                                 "Out of memory while attempting to allocate SET_NODE in vkAllocateDescriptorSets()"))
   6764                         return VK_ERROR_VALIDATION_FAILED_EXT;
   6765                 } else {
   6766                     // TODO : Pool should store a total count of each type of Descriptor available
   6767                     //  When descriptors are allocated, decrement the count and validate here
   6768                     //  that the count doesn't go below 0. One reset/free need to bump count back up.
   6769                     // Insert set at head of Set LL for this pool
   6770                     pNewNode->pNext = pPoolNode->pSets;
   6771                     pNewNode->in_use.store(0);
   6772                     pPoolNode->pSets = pNewNode;
   6773                     LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pAllocateInfo->pSetLayouts[i]);
   6774                     if (NULL == pLayout) {
   6775                         if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   6776                                     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pAllocateInfo->pSetLayouts[i],
   6777                                     __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
   6778                                     "Unable to find set layout node for layout %#" PRIxLEAST64
   6779                                     " specified in vkAllocateDescriptorSets() call",
   6780                                     (uint64_t)pAllocateInfo->pSetLayouts[i]))
   6781                             return VK_ERROR_VALIDATION_FAILED_EXT;
   6782                     }
   6783                     pNewNode->pLayout = pLayout;
   6784                     pNewNode->pool = pAllocateInfo->descriptorPool;
   6785                     pNewNode->set = pDescriptorSets[i];
   6786                     pNewNode->descriptorCount = (pLayout->createInfo.bindingCount != 0) ? pLayout->endIndex + 1 : 0;
   6787                     if (pNewNode->descriptorCount) {
   6788                         size_t descriptorArraySize = sizeof(GENERIC_HEADER *) * pNewNode->descriptorCount;
   6789                         pNewNode->ppDescriptors = new GENERIC_HEADER *[descriptorArraySize];
   6790                         memset(pNewNode->ppDescriptors, 0, descriptorArraySize);
   6791                     }
   6792                     dev_data->setMap[pDescriptorSets[i]] = pNewNode;
   6793                 }
   6794             }
   6795         }
   6796         loader_platform_thread_unlock_mutex(&globalLock);
   6797     }
   6798     return result;
   6799 }
   6800 
   6801 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6802 vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count, const VkDescriptorSet *pDescriptorSets) {
   6803     VkBool32 skipCall = VK_FALSE;
   6804     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6805     // Make sure that no sets being destroyed are in-flight
   6806     loader_platform_thread_lock_mutex(&globalLock);
   6807     for (uint32_t i = 0; i < count; ++i)
   6808         skipCall |= validateIdleDescriptorSet(dev_data, pDescriptorSets[i], "vkFreeDesriptorSets");
   6809     DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool);
   6810     if (pPoolNode && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pPoolNode->createInfo.flags)) {
   6811         // Can't Free from a NON_FREE pool
   6812         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   6813                             (uint64_t)device, __LINE__, DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL, "DS",
   6814                             "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
   6815                             "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT.");
   6816     }
   6817     loader_platform_thread_unlock_mutex(&globalLock);
   6818     if (VK_FALSE != skipCall)
   6819         return VK_ERROR_VALIDATION_FAILED_EXT;
   6820     VkResult result = dev_data->device_dispatch_table->FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
   6821     if (VK_SUCCESS == result) {
   6822         loader_platform_thread_lock_mutex(&globalLock);
   6823 
   6824         // Update available descriptor sets in pool
   6825         pPoolNode->availableSets += count;
   6826 
   6827         // For each freed descriptor add it back into the pool as available
   6828         for (uint32_t i = 0; i < count; ++i) {
   6829             SET_NODE *pSet = dev_data->setMap[pDescriptorSets[i]]; // getSetNode() without locking
   6830             invalidateBoundCmdBuffers(dev_data, pSet);
   6831             LAYOUT_NODE *pLayout = pSet->pLayout;
   6832             uint32_t typeIndex = 0, poolSizeCount = 0;
   6833             for (uint32_t j = 0; j < pLayout->createInfo.bindingCount; ++j) {
   6834                 typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType);
   6835                 poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount;
   6836                 pPoolNode->availableDescriptorTypeCount[typeIndex] += poolSizeCount;
   6837             }
   6838         }
   6839         loader_platform_thread_unlock_mutex(&globalLock);
   6840     }
   6841     // TODO : Any other clean-up or book-keeping to do here?
   6842     return result;
   6843 }
   6844 
   6845 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   6846 vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites,
   6847                        uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) {
   6848     // dsUpdate will return VK_TRUE only if a bailout error occurs, so we want to call down tree when update returns VK_FALSE
   6849     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6850     loader_platform_thread_lock_mutex(&globalLock);
   6851 #if MTMERGESOURCE
   6852     // MTMTODO : Merge this in with existing update code below and handle descriptor copies case
   6853     uint32_t j = 0;
   6854     for (uint32_t i = 0; i < descriptorWriteCount; ++i) {
   6855         if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
   6856             for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) {
   6857                 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].images.push_back(
   6858                     pDescriptorWrites[i].pImageInfo[j].imageView);
   6859             }
   6860         } else if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
   6861             for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) {
   6862                 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].buffers.push_back(
   6863                     dev_data->bufferViewMap[pDescriptorWrites[i].pTexelBufferView[j]].buffer);
   6864             }
   6865         } else if (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
   6866                    pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
   6867             for (j = 0; j < pDescriptorWrites[i].descriptorCount; ++j) {
   6868                 dev_data->descriptorSetMap[pDescriptorWrites[i].dstSet].buffers.push_back(
   6869                     pDescriptorWrites[i].pBufferInfo[j].buffer);
   6870             }
   6871         }
   6872     }
   6873 #endif
   6874     VkBool32 rtn = dsUpdate(dev_data, device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies);
   6875     loader_platform_thread_unlock_mutex(&globalLock);
   6876     if (!rtn) {
   6877         dev_data->device_dispatch_table->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
   6878                                                               pDescriptorCopies);
   6879     }
   6880 }
   6881 
   6882 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6883 vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo, VkCommandBuffer *pCommandBuffer) {
   6884     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   6885     VkResult result = dev_data->device_dispatch_table->AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
   6886     if (VK_SUCCESS == result) {
   6887         loader_platform_thread_lock_mutex(&globalLock);
   6888         auto const &cp_it = dev_data->commandPoolMap.find(pCreateInfo->commandPool);
   6889         if (cp_it != dev_data->commandPoolMap.end()) {
   6890             for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
   6891                 // Add command buffer to its commandPool map
   6892                 cp_it->second.commandBuffers.push_back(pCommandBuffer[i]);
   6893                 GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
   6894                 // Add command buffer to map
   6895                 dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
   6896                 resetCB(dev_data, pCommandBuffer[i]);
   6897                 pCB->createInfo = *pCreateInfo;
   6898                 pCB->device = device;
   6899             }
   6900         }
   6901 #if MTMERGESOURCE
   6902         printCBList(dev_data, device);
   6903 #endif
   6904         loader_platform_thread_unlock_mutex(&globalLock);
   6905     }
   6906     return result;
   6907 }
   6908 
   6909 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   6910 vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
   6911     VkBool32 skipCall = VK_FALSE;
   6912     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   6913     loader_platform_thread_lock_mutex(&globalLock);
   6914     // Validate command buffer level
   6915     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   6916     if (pCB) {
   6917 #if MTMERGESOURCE
   6918         bool commandBufferComplete = false;
   6919         // MTMTODO : Merge this with code below
   6920         // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
   6921         skipCall = checkCBCompleted(dev_data, commandBuffer, &commandBufferComplete);
   6922 
   6923         if (!commandBufferComplete) {
   6924             skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   6925                                 (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM",
   6926                                 "Calling vkBeginCommandBuffer() on active CB %p before it has completed. "
   6927                                 "You must check CB flag before this call.",
   6928                                 commandBuffer);
   6929         }
   6930 #endif
   6931         if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
   6932             // Secondary Command Buffer
   6933             const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
   6934             if (!pInfo) {
   6935                 skipCall |=
   6936                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   6937                             reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
   6938                             "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must have inheritance info.",
   6939                             reinterpret_cast<void *>(commandBuffer));
   6940             } else {
   6941                 if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
   6942                     if (!pInfo->renderPass) { // renderpass should NOT be null for an Secondary CB
   6943                         skipCall |= log_msg(
   6944                             dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   6945                             reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
   6946                             "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must specify a valid renderpass parameter.",
   6947                             reinterpret_cast<void *>(commandBuffer));
   6948                     }
   6949                     if (!pInfo->framebuffer) { // framebuffer may be null for an Secondary CB, but this affects perf
   6950                         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
   6951                                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   6952                                             reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE,
   6953                                             "DS", "vkBeginCommandBuffer(): Secondary Command Buffers (%p) may perform better if a "
   6954                                                   "valid framebuffer parameter is specified.",
   6955                                             reinterpret_cast<void *>(commandBuffer));
   6956                     } else {
   6957                         string errorString = "";
   6958                         auto fbNode = dev_data->frameBufferMap.find(pInfo->framebuffer);
   6959                         if (fbNode != dev_data->frameBufferMap.end()) {
   6960                             VkRenderPass fbRP = fbNode->second.createInfo.renderPass;
   6961                             if (!verify_renderpass_compatibility(dev_data, fbRP, pInfo->renderPass, errorString)) {
   6962                                 // renderPass that framebuffer was created with
   6963                                 // must
   6964                                 // be compatible with local renderPass
   6965                                 skipCall |=
   6966                                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   6967                                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   6968                                             reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE,
   6969                                             "DS", "vkBeginCommandBuffer(): Secondary Command "
   6970                                                   "Buffer (%p) renderPass (%#" PRIxLEAST64 ") is incompatible w/ framebuffer "
   6971                                                   "(%#" PRIxLEAST64 ") w/ render pass (%#" PRIxLEAST64 ") due to: %s",
   6972                                             reinterpret_cast<void *>(commandBuffer), (uint64_t)(pInfo->renderPass),
   6973                                             (uint64_t)(pInfo->framebuffer), (uint64_t)(fbRP), errorString.c_str());
   6974                             }
   6975                             // Connect this framebuffer to this cmdBuffer
   6976                             fbNode->second.referencingCmdBuffers.insert(pCB->commandBuffer);
   6977                         }
   6978                     }
   6979                 }
   6980                 if ((pInfo->occlusionQueryEnable == VK_FALSE ||
   6981                      dev_data->physDevProperties.features.occlusionQueryPrecise == VK_FALSE) &&
   6982                     (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
   6983                     skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   6984                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer),
   6985                                         __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
   6986                                         "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must not have "
   6987                                         "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
   6988                                         "support precise occlusion queries.",
   6989                                         reinterpret_cast<void *>(commandBuffer));
   6990                 }
   6991             }
   6992             if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
   6993                 auto rp_data = dev_data->renderPassMap.find(pInfo->renderPass);
   6994                 if (rp_data != dev_data->renderPassMap.end() && rp_data->second && rp_data->second->pCreateInfo) {
   6995                     if (pInfo->subpass >= rp_data->second->pCreateInfo->subpassCount) {
   6996                         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   6997                                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   6998                                             DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
   6999                                             "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must has a subpass index (%d) "
   7000                                             "that is less than the number of subpasses (%d).",
   7001                                             (void *)commandBuffer, pInfo->subpass, rp_data->second->pCreateInfo->subpassCount);
   7002                     }
   7003                 }
   7004             }
   7005         }
   7006         if (CB_RECORDING == pCB->state) {
   7007             skipCall |=
   7008                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   7009                         (uint64_t)commandBuffer, __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
   7010                         "vkBeginCommandBuffer(): Cannot call Begin on CB (%#" PRIxLEAST64
   7011                         ") in the RECORDING state. Must first call vkEndCommandBuffer().",
   7012                         (uint64_t)commandBuffer);
   7013         } else if (CB_RECORDED == pCB->state) {
   7014             VkCommandPool cmdPool = pCB->createInfo.commandPool;
   7015             if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) {
   7016                 skipCall |=
   7017                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   7018                             (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
   7019                             "Call to vkBeginCommandBuffer() on command buffer (%#" PRIxLEAST64
   7020                             ") attempts to implicitly reset cmdBuffer created from command pool (%#" PRIxLEAST64
   7021                             ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
   7022                             (uint64_t)commandBuffer, (uint64_t)cmdPool);
   7023             }
   7024             resetCB(dev_data, commandBuffer);
   7025         }
   7026         // Set updated state here in case implicit reset occurs above
   7027         pCB->state = CB_RECORDING;
   7028         pCB->beginInfo = *pBeginInfo;
   7029         if (pCB->beginInfo.pInheritanceInfo) {
   7030             pCB->inheritanceInfo = *(pCB->beginInfo.pInheritanceInfo);
   7031             pCB->beginInfo.pInheritanceInfo = &pCB->inheritanceInfo;
   7032         }
   7033     } else {
   7034         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   7035                             (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   7036                             "In vkBeginCommandBuffer() and unable to find CommandBuffer Node for CB %p!", (void *)commandBuffer);
   7037     }
   7038     loader_platform_thread_unlock_mutex(&globalLock);
   7039     if (VK_FALSE != skipCall) {
   7040         return VK_ERROR_VALIDATION_FAILED_EXT;
   7041     }
   7042     VkResult result = dev_data->device_dispatch_table->BeginCommandBuffer(commandBuffer, pBeginInfo);
   7043 #if MTMERGESOURCE
   7044     loader_platform_thread_lock_mutex(&globalLock);
   7045     clear_cmd_buf_and_mem_references(dev_data, commandBuffer);
   7046     loader_platform_thread_unlock_mutex(&globalLock);
   7047 #endif
   7048     return result;
   7049 }
   7050 
   7051 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer) {
   7052     VkBool32 skipCall = VK_FALSE;
   7053     VkResult result = VK_SUCCESS;
   7054     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7055     loader_platform_thread_lock_mutex(&globalLock);
   7056     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7057     if (pCB) {
   7058         if (pCB->state != CB_RECORDING) {
   7059             skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkEndCommandBuffer()");
   7060         }
   7061         for (auto query : pCB->activeQueries) {
   7062             skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   7063                                 DRAWSTATE_INVALID_QUERY, "DS",
   7064                                 "Ending command buffer with in progress query: queryPool %" PRIu64 ", index %d",
   7065                                 (uint64_t)(query.pool), query.index);
   7066         }
   7067     }
   7068     if (VK_FALSE == skipCall) {
   7069         loader_platform_thread_unlock_mutex(&globalLock);
   7070         result = dev_data->device_dispatch_table->EndCommandBuffer(commandBuffer);
   7071         loader_platform_thread_lock_mutex(&globalLock);
   7072         if (VK_SUCCESS == result) {
   7073             pCB->state = CB_RECORDED;
   7074             // Reset CB status flags
   7075             pCB->status = 0;
   7076             printCB(dev_data, commandBuffer);
   7077         }
   7078     } else {
   7079         result = VK_ERROR_VALIDATION_FAILED_EXT;
   7080     }
   7081     loader_platform_thread_unlock_mutex(&globalLock);
   7082     return result;
   7083 }
   7084 
   7085 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   7086 vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
   7087     VkBool32 skipCall = VK_FALSE;
   7088     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7089     loader_platform_thread_lock_mutex(&globalLock);
   7090 #if MTMERGESOURCE
   7091     bool commandBufferComplete = false;
   7092     // Verify that CB is complete (not in-flight)
   7093     skipCall = checkCBCompleted(dev_data, commandBuffer, &commandBufferComplete);
   7094     if (!commandBufferComplete) {
   7095         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   7096                             (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM",
   7097                             "Resetting CB %p before it has completed. You must check CB "
   7098                             "flag before calling vkResetCommandBuffer().",
   7099                             commandBuffer);
   7100     }
   7101     // Clear memory references as this point.
   7102     clear_cmd_buf_and_mem_references(dev_data, commandBuffer);
   7103 #endif
   7104     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7105     VkCommandPool cmdPool = pCB->createInfo.commandPool;
   7106     if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) {
   7107         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   7108                             (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
   7109                             "Attempt to reset command buffer (%#" PRIxLEAST64 ") created from command pool (%#" PRIxLEAST64
   7110                             ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
   7111                             (uint64_t)commandBuffer, (uint64_t)cmdPool);
   7112     }
   7113     if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) {
   7114         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   7115                             (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
   7116                             "Attempt to reset command buffer (%#" PRIxLEAST64 ") which is in use.",
   7117                             reinterpret_cast<uint64_t>(commandBuffer));
   7118     }
   7119     loader_platform_thread_unlock_mutex(&globalLock);
   7120     if (skipCall != VK_FALSE)
   7121         return VK_ERROR_VALIDATION_FAILED_EXT;
   7122     VkResult result = dev_data->device_dispatch_table->ResetCommandBuffer(commandBuffer, flags);
   7123     if (VK_SUCCESS == result) {
   7124         loader_platform_thread_lock_mutex(&globalLock);
   7125         resetCB(dev_data, commandBuffer);
   7126         loader_platform_thread_unlock_mutex(&globalLock);
   7127     }
   7128     return result;
   7129 }
   7130 #if MTMERGESOURCE
   7131 // TODO : For any vkCmdBind* calls that include an object which has mem bound to it,
   7132 //    need to account for that mem now having binding to given commandBuffer
   7133 #endif
   7134 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7135 vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) {
   7136     VkBool32 skipCall = VK_FALSE;
   7137     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7138     loader_platform_thread_lock_mutex(&globalLock);
   7139     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7140     if (pCB) {
   7141         skipCall |= addCmd(dev_data, pCB, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
   7142         if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) {
   7143             skipCall |=
   7144                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
   7145                         (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
   7146                         "Incorrectly binding compute pipeline (%#" PRIxLEAST64 ") during active RenderPass (%#" PRIxLEAST64 ")",
   7147                         (uint64_t)pipeline, (uint64_t)pCB->activeRenderPass);
   7148         }
   7149 
   7150         PIPELINE_NODE *pPN = getPipeline(dev_data, pipeline);
   7151         if (pPN) {
   7152             pCB->lastBound[pipelineBindPoint].pipeline = pipeline;
   7153             set_cb_pso_status(pCB, pPN);
   7154             skipCall |= validatePipelineState(dev_data, pCB, pipelineBindPoint, pipeline);
   7155         } else {
   7156             skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
   7157                                 (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS",
   7158                                 "Attempt to bind Pipeline %#" PRIxLEAST64 " that doesn't exist!", (uint64_t)(pipeline));
   7159         }
   7160     }
   7161     loader_platform_thread_unlock_mutex(&globalLock);
   7162     if (VK_FALSE == skipCall)
   7163         dev_data->device_dispatch_table->CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
   7164 }
   7165 
   7166 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7167 vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) {
   7168     VkBool32 skipCall = VK_FALSE;
   7169     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7170     loader_platform_thread_lock_mutex(&globalLock);
   7171     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7172     if (pCB) {
   7173         skipCall |= addCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
   7174         pCB->status |= CBSTATUS_VIEWPORT_SET;
   7175         pCB->viewports.resize(viewportCount);
   7176         memcpy(pCB->viewports.data(), pViewports, viewportCount * sizeof(VkViewport));
   7177     }
   7178     loader_platform_thread_unlock_mutex(&globalLock);
   7179     if (VK_FALSE == skipCall)
   7180         dev_data->device_dispatch_table->CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
   7181 }
   7182 
   7183 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7184 vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) {
   7185     VkBool32 skipCall = VK_FALSE;
   7186     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7187     loader_platform_thread_lock_mutex(&globalLock);
   7188     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7189     if (pCB) {
   7190         skipCall |= addCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
   7191         pCB->status |= CBSTATUS_SCISSOR_SET;
   7192         pCB->scissors.resize(scissorCount);
   7193         memcpy(pCB->scissors.data(), pScissors, scissorCount * sizeof(VkRect2D));
   7194     }
   7195     loader_platform_thread_unlock_mutex(&globalLock);
   7196     if (VK_FALSE == skipCall)
   7197         dev_data->device_dispatch_table->CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
   7198 }
   7199 
   7200 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
   7201     VkBool32 skipCall = VK_FALSE;
   7202     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7203     loader_platform_thread_lock_mutex(&globalLock);
   7204     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7205     if (pCB) {
   7206         skipCall |= addCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
   7207         pCB->status |= CBSTATUS_LINE_WIDTH_SET;
   7208     }
   7209     loader_platform_thread_unlock_mutex(&globalLock);
   7210     if (VK_FALSE == skipCall)
   7211         dev_data->device_dispatch_table->CmdSetLineWidth(commandBuffer, lineWidth);
   7212 }
   7213 
   7214 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7215 vkCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) {
   7216     VkBool32 skipCall = VK_FALSE;
   7217     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7218     loader_platform_thread_lock_mutex(&globalLock);
   7219     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7220     if (pCB) {
   7221         skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
   7222         pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
   7223     }
   7224     loader_platform_thread_unlock_mutex(&globalLock);
   7225     if (VK_FALSE == skipCall)
   7226         dev_data->device_dispatch_table->CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp,
   7227                                                          depthBiasSlopeFactor);
   7228 }
   7229 
   7230 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
   7231     VkBool32 skipCall = VK_FALSE;
   7232     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7233     loader_platform_thread_lock_mutex(&globalLock);
   7234     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7235     if (pCB) {
   7236         skipCall |= addCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
   7237         pCB->status |= CBSTATUS_BLEND_SET;
   7238     }
   7239     loader_platform_thread_unlock_mutex(&globalLock);
   7240     if (VK_FALSE == skipCall)
   7241         dev_data->device_dispatch_table->CmdSetBlendConstants(commandBuffer, blendConstants);
   7242 }
   7243 
   7244 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7245 vkCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
   7246     VkBool32 skipCall = VK_FALSE;
   7247     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7248     loader_platform_thread_lock_mutex(&globalLock);
   7249     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7250     if (pCB) {
   7251         skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
   7252         pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
   7253     }
   7254     loader_platform_thread_unlock_mutex(&globalLock);
   7255     if (VK_FALSE == skipCall)
   7256         dev_data->device_dispatch_table->CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
   7257 }
   7258 
   7259 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7260 vkCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) {
   7261     VkBool32 skipCall = VK_FALSE;
   7262     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7263     loader_platform_thread_lock_mutex(&globalLock);
   7264     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7265     if (pCB) {
   7266         skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
   7267         pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
   7268     }
   7269     loader_platform_thread_unlock_mutex(&globalLock);
   7270     if (VK_FALSE == skipCall)
   7271         dev_data->device_dispatch_table->CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
   7272 }
   7273 
   7274 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7275 vkCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
   7276     VkBool32 skipCall = VK_FALSE;
   7277     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7278     loader_platform_thread_lock_mutex(&globalLock);
   7279     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7280     if (pCB) {
   7281         skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
   7282         pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
   7283     }
   7284     loader_platform_thread_unlock_mutex(&globalLock);
   7285     if (VK_FALSE == skipCall)
   7286         dev_data->device_dispatch_table->CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
   7287 }
   7288 
   7289 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7290 vkCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
   7291     VkBool32 skipCall = VK_FALSE;
   7292     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7293     loader_platform_thread_lock_mutex(&globalLock);
   7294     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7295     if (pCB) {
   7296         skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
   7297         pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
   7298     }
   7299     loader_platform_thread_unlock_mutex(&globalLock);
   7300     if (VK_FALSE == skipCall)
   7301         dev_data->device_dispatch_table->CmdSetStencilReference(commandBuffer, faceMask, reference);
   7302 }
   7303 
   7304 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7305 vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout,
   7306                         uint32_t firstSet, uint32_t setCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
   7307                         const uint32_t *pDynamicOffsets) {
   7308     VkBool32 skipCall = VK_FALSE;
   7309     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7310     loader_platform_thread_lock_mutex(&globalLock);
   7311 #if MTMERGESOURCE
   7312     // MTMTODO : Merge this with code below
   7313     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   7314     if (cb_data != dev_data->commandBufferMap.end()) {
   7315         // MTMTODO : activeDescriptorSets should be merged with lastBound.boundDescriptorSets
   7316         std::vector<VkDescriptorSet> &activeDescriptorSets = cb_data->second->activeDescriptorSets;
   7317         if (activeDescriptorSets.size() < (setCount + firstSet)) {
   7318             activeDescriptorSets.resize(setCount + firstSet);
   7319         }
   7320         for (uint32_t i = 0; i < setCount; ++i) {
   7321             activeDescriptorSets[i + firstSet] = pDescriptorSets[i];
   7322         }
   7323     }
   7324     // TODO : Somewhere need to verify that all textures referenced by shaders in DS are in some type of *SHADER_READ* state
   7325 #endif
   7326     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7327     if (pCB) {
   7328         if (pCB->state == CB_RECORDING) {
   7329             // Track total count of dynamic descriptor types to make sure we have an offset for each one
   7330             uint32_t totalDynamicDescriptors = 0;
   7331             string errorString = "";
   7332             uint32_t lastSetIndex = firstSet + setCount - 1;
   7333             if (lastSetIndex >= pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size())
   7334                 pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
   7335             VkDescriptorSet oldFinalBoundSet = pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex];
   7336             for (uint32_t i = 0; i < setCount; i++) {
   7337                 SET_NODE *pSet = getSetNode(dev_data, pDescriptorSets[i]);
   7338                 if (pSet) {
   7339                     pCB->lastBound[pipelineBindPoint].uniqueBoundSets.insert(pDescriptorSets[i]);
   7340                     pSet->boundCmdBuffers.insert(commandBuffer);
   7341                     pCB->lastBound[pipelineBindPoint].pipelineLayout = layout;
   7342                     pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i + firstSet] = pDescriptorSets[i];
   7343                     skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
   7344                                         VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
   7345                                         DRAWSTATE_NONE, "DS", "DS %#" PRIxLEAST64 " bound on pipeline %s",
   7346                                         (uint64_t)pDescriptorSets[i], string_VkPipelineBindPoint(pipelineBindPoint));
   7347                     if (!pSet->pUpdateStructs && (pSet->descriptorCount != 0)) {
   7348                         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
   7349                                             VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i],
   7350                                             __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
   7351                                             "DS %#" PRIxLEAST64
   7352                                             " bound but it was never updated. You may want to either update it or not bind it.",
   7353                                             (uint64_t)pDescriptorSets[i]);
   7354                     }
   7355                     // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
   7356                     if (!verify_set_layout_compatibility(dev_data, pSet, layout, i + firstSet, errorString)) {
   7357                         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   7358                                             VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i],
   7359                                             __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
   7360                                             "descriptorSet #%u being bound is not compatible with overlapping layout in "
   7361                                             "pipelineLayout due to: %s",
   7362                                             i, errorString.c_str());
   7363                     }
   7364                     if (pSet->pLayout->dynamicDescriptorCount) {
   7365                         // First make sure we won't overstep bounds of pDynamicOffsets array
   7366                         if ((totalDynamicDescriptors + pSet->pLayout->dynamicDescriptorCount) > dynamicOffsetCount) {
   7367                             skipCall |=
   7368                                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   7369                                         VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
   7370                                         DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
   7371                                         "descriptorSet #%u (%#" PRIxLEAST64
   7372                                         ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
   7373                                         "array. There must be one dynamic offset for each dynamic descriptor being bound.",
   7374                                         i, (uint64_t)pDescriptorSets[i], pSet->pLayout->dynamicDescriptorCount,
   7375                                         (dynamicOffsetCount - totalDynamicDescriptors));
   7376                         } else { // Validate and store dynamic offsets with the set
   7377                             // Validate Dynamic Offset Minimums
   7378                             uint32_t cur_dyn_offset = totalDynamicDescriptors;
   7379                             for (uint32_t d = 0; d < pSet->descriptorCount; d++) {
   7380                                 if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
   7381                                     if (vk_safe_modulo(
   7382                                             pDynamicOffsets[cur_dyn_offset],
   7383                                             dev_data->physDevProperties.properties.limits.minUniformBufferOffsetAlignment) !=
   7384                                         0) {
   7385                                         skipCall |= log_msg(
   7386                                             dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   7387                                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
   7388                                             DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, "DS",
   7389                                             "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
   7390                                             "device limit minUniformBufferOffsetAlignment %#" PRIxLEAST64,
   7391                                             cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
   7392                                             dev_data->physDevProperties.properties.limits.minUniformBufferOffsetAlignment);
   7393                                     }
   7394                                     cur_dyn_offset++;
   7395                                 } else if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
   7396                                     if (vk_safe_modulo(
   7397                                             pDynamicOffsets[cur_dyn_offset],
   7398                                             dev_data->physDevProperties.properties.limits.minStorageBufferOffsetAlignment) !=
   7399                                         0) {
   7400                                         skipCall |= log_msg(
   7401                                             dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   7402                                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
   7403                                             DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, "DS",
   7404                                             "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
   7405                                             "device limit minStorageBufferOffsetAlignment %#" PRIxLEAST64,
   7406                                             cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
   7407                                             dev_data->physDevProperties.properties.limits.minStorageBufferOffsetAlignment);
   7408                                     }
   7409                                     cur_dyn_offset++;
   7410                                 }
   7411                             }
   7412                             // Keep running total of dynamic descriptor count to verify at the end
   7413                             totalDynamicDescriptors += pSet->pLayout->dynamicDescriptorCount;
   7414                         }
   7415                     }
   7416                 } else {
   7417                     skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   7418                                         VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
   7419                                         DRAWSTATE_INVALID_SET, "DS", "Attempt to bind DS %#" PRIxLEAST64 " that doesn't exist!",
   7420                                         (uint64_t)pDescriptorSets[i]);
   7421                 }
   7422                 skipCall |= addCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
   7423                 // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
   7424                 if (firstSet > 0) { // Check set #s below the first bound set
   7425                     for (uint32_t i = 0; i < firstSet; ++i) {
   7426                         if (pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
   7427                             !verify_set_layout_compatibility(
   7428                                 dev_data, dev_data->setMap[pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i]], layout, i,
   7429                                 errorString)) {
   7430                             skipCall |= log_msg(
   7431                                 dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   7432                                 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
   7433                                 (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS",
   7434                                 "DescriptorSetDS %#" PRIxLEAST64
   7435                                 " previously bound as set #%u was disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")",
   7436                                 (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout);
   7437                             pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
   7438                         }
   7439                     }
   7440                 }
   7441                 // Check if newly last bound set invalidates any remaining bound sets
   7442                 if ((pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (lastSetIndex)) {
   7443                     if (oldFinalBoundSet &&
   7444                         !verify_set_layout_compatibility(dev_data, dev_data->setMap[oldFinalBoundSet], layout, lastSetIndex,
   7445                                                          errorString)) {
   7446                         skipCall |=
   7447                             log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   7448                                     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)oldFinalBoundSet, __LINE__,
   7449                                     DRAWSTATE_NONE, "DS", "DescriptorSetDS %#" PRIxLEAST64
   7450                                                           " previously bound as set #%u is incompatible with set %#" PRIxLEAST64
   7451                                                           " newly bound as set #%u so set #%u and any subsequent sets were "
   7452                                                           "disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")",
   7453                                     (uint64_t)oldFinalBoundSet, lastSetIndex,
   7454                                     (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex], lastSetIndex,
   7455                                     lastSetIndex + 1, (uint64_t)layout);
   7456                         pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
   7457                     }
   7458                 }
   7459                 //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
   7460                 if (totalDynamicDescriptors != dynamicOffsetCount) {
   7461                     skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   7462                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   7463                                         DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
   7464                                         "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
   7465                                         "is %u. It should exactly match the number of dynamic descriptors.",
   7466                                         setCount, totalDynamicDescriptors, dynamicOffsetCount);
   7467                 }
   7468                 // Save dynamicOffsets bound to this CB
   7469                 for (uint32_t i = 0; i < dynamicOffsetCount; i++) {
   7470                     pCB->lastBound[pipelineBindPoint].dynamicOffsets.push_back(pDynamicOffsets[i]);
   7471                 }
   7472             }
   7473             //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
   7474             if (totalDynamicDescriptors != dynamicOffsetCount) {
   7475                 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   7476                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   7477                                     DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
   7478                                     "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
   7479                                     "is %u. It should exactly match the number of dynamic descriptors.",
   7480                                     setCount, totalDynamicDescriptors, dynamicOffsetCount);
   7481             }
   7482             // Save dynamicOffsets bound to this CB
   7483             for (uint32_t i = 0; i < dynamicOffsetCount; i++) {
   7484                 pCB->dynamicOffsets.emplace_back(pDynamicOffsets[i]);
   7485             }
   7486         } else {
   7487             skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindDescriptorSets()");
   7488         }
   7489     }
   7490     loader_platform_thread_unlock_mutex(&globalLock);
   7491     if (VK_FALSE == skipCall)
   7492         dev_data->device_dispatch_table->CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
   7493                                                                pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
   7494 }
   7495 
   7496 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7497 vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) {
   7498     VkBool32 skipCall = VK_FALSE;
   7499     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7500     loader_platform_thread_lock_mutex(&globalLock);
   7501 #if MTMERGESOURCE
   7502     VkDeviceMemory mem;
   7503     skipCall =
   7504         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   7505     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   7506     if (cb_data != dev_data->commandBufferMap.end()) {
   7507         std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindIndexBuffer()"); };
   7508         cb_data->second->validate_functions.push_back(function);
   7509     }
   7510     // TODO : Somewhere need to verify that IBs have correct usage state flagged
   7511 #endif
   7512     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7513     if (pCB) {
   7514         skipCall |= addCmd(dev_data, pCB, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
   7515         VkDeviceSize offset_align = 0;
   7516         switch (indexType) {
   7517         case VK_INDEX_TYPE_UINT16:
   7518             offset_align = 2;
   7519             break;
   7520         case VK_INDEX_TYPE_UINT32:
   7521             offset_align = 4;
   7522             break;
   7523         default:
   7524             // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
   7525             break;
   7526         }
   7527         if (!offset_align || (offset % offset_align)) {
   7528             skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   7529                                 DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
   7530                                 "vkCmdBindIndexBuffer() offset (%#" PRIxLEAST64 ") does not fall on alignment (%s) boundary.",
   7531                                 offset, string_VkIndexType(indexType));
   7532         }
   7533         pCB->status |= CBSTATUS_INDEX_BUFFER_BOUND;
   7534     }
   7535     loader_platform_thread_unlock_mutex(&globalLock);
   7536     if (VK_FALSE == skipCall)
   7537         dev_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
   7538 }
   7539 
   7540 void updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
   7541     uint32_t end = firstBinding + bindingCount;
   7542     if (pCB->currentDrawData.buffers.size() < end) {
   7543         pCB->currentDrawData.buffers.resize(end);
   7544     }
   7545     for (uint32_t i = 0; i < bindingCount; ++i) {
   7546         pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
   7547     }
   7548 }
   7549 
   7550 void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
   7551 
   7552 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding,
   7553                                                                   uint32_t bindingCount, const VkBuffer *pBuffers,
   7554                                                                   const VkDeviceSize *pOffsets) {
   7555     VkBool32 skipCall = VK_FALSE;
   7556     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7557     loader_platform_thread_lock_mutex(&globalLock);
   7558 #if MTMERGESOURCE
   7559     for (uint32_t i = 0; i < bindingCount; ++i) {
   7560         VkDeviceMemory mem;
   7561         skipCall |= get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)(pBuffers[i]),
   7562                                                  VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   7563         auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   7564         if (cb_data != dev_data->commandBufferMap.end()) {
   7565             std::function<VkBool32()> function =
   7566                 [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindVertexBuffers()"); };
   7567             cb_data->second->validate_functions.push_back(function);
   7568         }
   7569     }
   7570     // TODO : Somewhere need to verify that VBs have correct usage state flagged
   7571 #endif
   7572     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7573     if (pCB) {
   7574         addCmd(dev_data, pCB, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()");
   7575         updateResourceTracking(pCB, firstBinding, bindingCount, pBuffers);
   7576     } else {
   7577         skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindVertexBuffer()");
   7578     }
   7579     loader_platform_thread_unlock_mutex(&globalLock);
   7580     if (VK_FALSE == skipCall)
   7581         dev_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
   7582 }
   7583 
   7584 #if MTMERGESOURCE
   7585 /* expects globalLock to be held by caller */
   7586 bool markStoreImagesAndBuffersAsWritten(VkCommandBuffer commandBuffer) {
   7587     bool skip_call = false;
   7588     layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7589     auto cb_data = my_data->commandBufferMap.find(commandBuffer);
   7590     if (cb_data == my_data->commandBufferMap.end())
   7591         return skip_call;
   7592     std::vector<VkDescriptorSet> &activeDescriptorSets = cb_data->second->activeDescriptorSets;
   7593     for (auto descriptorSet : activeDescriptorSets) {
   7594         auto ds_data = my_data->descriptorSetMap.find(descriptorSet);
   7595         if (ds_data == my_data->descriptorSetMap.end())
   7596             continue;
   7597         std::vector<VkImageView> images = ds_data->second.images;
   7598         std::vector<VkBuffer> buffers = ds_data->second.buffers;
   7599         for (auto imageView : images) {
   7600             auto iv_data = my_data->imageViewMap.find(imageView);
   7601             if (iv_data == my_data->imageViewMap.end())
   7602                 continue;
   7603             VkImage image = iv_data->second.image;
   7604             VkDeviceMemory mem;
   7605             skip_call |=
   7606                 get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   7607             std::function<VkBool32()> function = [=]() {
   7608                 set_memory_valid(my_data, mem, true, image);
   7609                 return VK_FALSE;
   7610             };
   7611             cb_data->second->validate_functions.push_back(function);
   7612         }
   7613         for (auto buffer : buffers) {
   7614             VkDeviceMemory mem;
   7615             skip_call |=
   7616                 get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   7617             std::function<VkBool32()> function = [=]() {
   7618                 set_memory_valid(my_data, mem, true);
   7619                 return VK_FALSE;
   7620             };
   7621             cb_data->second->validate_functions.push_back(function);
   7622         }
   7623     }
   7624     return skip_call;
   7625 }
   7626 #endif
   7627 
   7628 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
   7629                                                      uint32_t firstVertex, uint32_t firstInstance) {
   7630     VkBool32 skipCall = VK_FALSE;
   7631     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7632     loader_platform_thread_lock_mutex(&globalLock);
   7633 #if MTMERGESOURCE
   7634     // MTMTODO : merge with code below
   7635     skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer);
   7636 #endif
   7637     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7638     if (pCB) {
   7639         skipCall |= addCmd(dev_data, pCB, CMD_DRAW, "vkCmdDraw()");
   7640         pCB->drawCount[DRAW]++;
   7641         skipCall |= validate_draw_state(dev_data, pCB, VK_FALSE);
   7642         // TODO : Need to pass commandBuffer as srcObj here
   7643         skipCall |=
   7644             log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   7645                     __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDraw() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW]++);
   7646         skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
   7647         if (VK_FALSE == skipCall) {
   7648             updateResourceTrackingOnDraw(pCB);
   7649         }
   7650         skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDraw");
   7651     }
   7652     loader_platform_thread_unlock_mutex(&globalLock);
   7653     if (VK_FALSE == skipCall)
   7654         dev_data->device_dispatch_table->CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
   7655 }
   7656 
   7657 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount,
   7658                                                             uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset,
   7659                                                             uint32_t firstInstance) {
   7660     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7661     VkBool32 skipCall = VK_FALSE;
   7662     loader_platform_thread_lock_mutex(&globalLock);
   7663 #if MTMERGESOURCE
   7664     // MTMTODO : merge with code below
   7665     skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer);
   7666 #endif
   7667     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7668     if (pCB) {
   7669         skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXED, "vkCmdDrawIndexed()");
   7670         pCB->drawCount[DRAW_INDEXED]++;
   7671         skipCall |= validate_draw_state(dev_data, pCB, VK_TRUE);
   7672         // TODO : Need to pass commandBuffer as srcObj here
   7673         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
   7674                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS",
   7675                             "vkCmdDrawIndexed() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDEXED]++);
   7676         skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
   7677         if (VK_FALSE == skipCall) {
   7678             updateResourceTrackingOnDraw(pCB);
   7679         }
   7680         skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexed");
   7681     }
   7682     loader_platform_thread_unlock_mutex(&globalLock);
   7683     if (VK_FALSE == skipCall)
   7684         dev_data->device_dispatch_table->CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset,
   7685                                                         firstInstance);
   7686 }
   7687 
   7688 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7689 vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
   7690     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7691     VkBool32 skipCall = VK_FALSE;
   7692     loader_platform_thread_lock_mutex(&globalLock);
   7693 #if MTMERGESOURCE
   7694     VkDeviceMemory mem;
   7695     // MTMTODO : merge with code below
   7696     skipCall =
   7697         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   7698     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndirect");
   7699     skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer);
   7700 #endif
   7701     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7702     if (pCB) {
   7703         skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDIRECT, "vkCmdDrawIndirect()");
   7704         pCB->drawCount[DRAW_INDIRECT]++;
   7705         skipCall |= validate_draw_state(dev_data, pCB, VK_FALSE);
   7706         // TODO : Need to pass commandBuffer as srcObj here
   7707         skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
   7708                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS",
   7709                             "vkCmdDrawIndirect() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDIRECT]++);
   7710         skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
   7711         if (VK_FALSE == skipCall) {
   7712             updateResourceTrackingOnDraw(pCB);
   7713         }
   7714         skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndirect");
   7715     }
   7716     loader_platform_thread_unlock_mutex(&globalLock);
   7717     if (VK_FALSE == skipCall)
   7718         dev_data->device_dispatch_table->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
   7719 }
   7720 
   7721 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7722 vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
   7723     VkBool32 skipCall = VK_FALSE;
   7724     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7725     loader_platform_thread_lock_mutex(&globalLock);
   7726 #if MTMERGESOURCE
   7727     VkDeviceMemory mem;
   7728     // MTMTODO : merge with code below
   7729     skipCall =
   7730         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   7731     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndexedIndirect");
   7732     skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer);
   7733 #endif
   7734     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7735     if (pCB) {
   7736         skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXEDINDIRECT, "vkCmdDrawIndexedIndirect()");
   7737         pCB->drawCount[DRAW_INDEXED_INDIRECT]++;
   7738         loader_platform_thread_unlock_mutex(&globalLock);
   7739         skipCall |= validate_draw_state(dev_data, pCB, VK_TRUE);
   7740         loader_platform_thread_lock_mutex(&globalLock);
   7741         // TODO : Need to pass commandBuffer as srcObj here
   7742         skipCall |=
   7743             log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   7744                     __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDrawIndexedIndirect() call #%" PRIu64 ", reporting DS state:",
   7745                     g_drawCount[DRAW_INDEXED_INDIRECT]++);
   7746         skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
   7747         if (VK_FALSE == skipCall) {
   7748             updateResourceTrackingOnDraw(pCB);
   7749         }
   7750         skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexedIndirect");
   7751     }
   7752     loader_platform_thread_unlock_mutex(&globalLock);
   7753     if (VK_FALSE == skipCall)
   7754         dev_data->device_dispatch_table->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
   7755 }
   7756 
   7757 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
   7758     VkBool32 skipCall = VK_FALSE;
   7759     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7760     loader_platform_thread_lock_mutex(&globalLock);
   7761 #if MTMERGESOURCE
   7762     skipCall = markStoreImagesAndBuffersAsWritten(commandBuffer);
   7763 #endif
   7764     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7765     if (pCB) {
   7766         skipCall |= addCmd(dev_data, pCB, CMD_DISPATCH, "vkCmdDispatch()");
   7767         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatch");
   7768     }
   7769     loader_platform_thread_unlock_mutex(&globalLock);
   7770     if (VK_FALSE == skipCall)
   7771         dev_data->device_dispatch_table->CmdDispatch(commandBuffer, x, y, z);
   7772 }
   7773 
   7774 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7775 vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
   7776     VkBool32 skipCall = VK_FALSE;
   7777     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7778     loader_platform_thread_lock_mutex(&globalLock);
   7779 #if MTMERGESOURCE
   7780     VkDeviceMemory mem;
   7781     skipCall =
   7782         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   7783     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDispatchIndirect");
   7784     skipCall |= markStoreImagesAndBuffersAsWritten(commandBuffer);
   7785 #endif
   7786     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7787     if (pCB) {
   7788         skipCall |= addCmd(dev_data, pCB, CMD_DISPATCHINDIRECT, "vkCmdDispatchIndirect()");
   7789         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatchIndirect");
   7790     }
   7791     loader_platform_thread_unlock_mutex(&globalLock);
   7792     if (VK_FALSE == skipCall)
   7793         dev_data->device_dispatch_table->CmdDispatchIndirect(commandBuffer, buffer, offset);
   7794 }
   7795 
   7796 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
   7797                                                            uint32_t regionCount, const VkBufferCopy *pRegions) {
   7798     VkBool32 skipCall = VK_FALSE;
   7799     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7800     loader_platform_thread_lock_mutex(&globalLock);
   7801 #if MTMERGESOURCE
   7802     VkDeviceMemory mem;
   7803     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   7804     loader_platform_thread_lock_mutex(&globalLock);
   7805     skipCall =
   7806         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   7807     if (cb_data != dev_data->commandBufferMap.end()) {
   7808         std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyBuffer()"); };
   7809         cb_data->second->validate_functions.push_back(function);
   7810     }
   7811     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBuffer");
   7812     skipCall |=
   7813         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   7814     if (cb_data != dev_data->commandBufferMap.end()) {
   7815         std::function<VkBool32()> function = [=]() {
   7816             set_memory_valid(dev_data, mem, true);
   7817             return VK_FALSE;
   7818         };
   7819         cb_data->second->validate_functions.push_back(function);
   7820     }
   7821     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBuffer");
   7822     // Validate that SRC & DST buffers have correct usage flags set
   7823     skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
   7824                                             "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
   7825     skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
   7826                                             "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
   7827 #endif
   7828     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7829     if (pCB) {
   7830         skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFER, "vkCmdCopyBuffer()");
   7831         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBuffer");
   7832     }
   7833     loader_platform_thread_unlock_mutex(&globalLock);
   7834     if (VK_FALSE == skipCall)
   7835         dev_data->device_dispatch_table->CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
   7836 }
   7837 
   7838 VkBool32 VerifySourceImageLayout(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageSubresourceLayers subLayers,
   7839                                  VkImageLayout srcImageLayout) {
   7840     VkBool32 skip_call = VK_FALSE;
   7841 
   7842     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
   7843     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
   7844     for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
   7845         uint32_t layer = i + subLayers.baseArrayLayer;
   7846         VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
   7847         IMAGE_CMD_BUF_LAYOUT_NODE node;
   7848         if (!FindLayout(pCB, srcImage, sub, node)) {
   7849             SetLayout(pCB, srcImage, sub, {srcImageLayout, srcImageLayout});
   7850             continue;
   7851         }
   7852         if (node.layout != srcImageLayout) {
   7853             // TODO: Improve log message in the next pass
   7854             skip_call |=
   7855                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   7856                         __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose source layout is %s "
   7857                                                                         "and doesn't match the current layout %s.",
   7858                         string_VkImageLayout(srcImageLayout), string_VkImageLayout(node.layout));
   7859         }
   7860     }
   7861     if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
   7862         if (srcImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
   7863             // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
   7864             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
   7865                                  0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   7866                                  "Layout for input image should be TRANSFER_SRC_OPTIMAL instead of GENERAL.");
   7867         } else {
   7868             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   7869                                  DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for input image is %s but can only be "
   7870                                                                        "TRANSFER_SRC_OPTIMAL or GENERAL.",
   7871                                  string_VkImageLayout(srcImageLayout));
   7872         }
   7873     }
   7874     return skip_call;
   7875 }
   7876 
   7877 VkBool32 VerifyDestImageLayout(VkCommandBuffer cmdBuffer, VkImage destImage, VkImageSubresourceLayers subLayers,
   7878                                VkImageLayout destImageLayout) {
   7879     VkBool32 skip_call = VK_FALSE;
   7880 
   7881     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
   7882     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
   7883     for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
   7884         uint32_t layer = i + subLayers.baseArrayLayer;
   7885         VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
   7886         IMAGE_CMD_BUF_LAYOUT_NODE node;
   7887         if (!FindLayout(pCB, destImage, sub, node)) {
   7888             SetLayout(pCB, destImage, sub, {destImageLayout, destImageLayout});
   7889             continue;
   7890         }
   7891         if (node.layout != destImageLayout) {
   7892             skip_call |=
   7893                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   7894                         __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose dest layout is %s and "
   7895                                                                         "doesn't match the current layout %s.",
   7896                         string_VkImageLayout(destImageLayout), string_VkImageLayout(node.layout));
   7897         }
   7898     }
   7899     if (destImageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
   7900         if (destImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
   7901             // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
   7902             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
   7903                                  0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   7904                                  "Layout for output image should be TRANSFER_DST_OPTIMAL instead of GENERAL.");
   7905         } else {
   7906             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   7907                                  DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for output image is %s but can only be "
   7908                                                                        "TRANSFER_DST_OPTIMAL or GENERAL.",
   7909                                  string_VkImageLayout(destImageLayout));
   7910         }
   7911     }
   7912     return skip_call;
   7913 }
   7914 
   7915 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7916 vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
   7917                VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) {
   7918     VkBool32 skipCall = VK_FALSE;
   7919     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7920     loader_platform_thread_lock_mutex(&globalLock);
   7921 #if MTMERGESOURCE
   7922     VkDeviceMemory mem;
   7923     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   7924     // Validate that src & dst images have correct usage flags set
   7925     skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   7926     if (cb_data != dev_data->commandBufferMap.end()) {
   7927         std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyImage()", srcImage); };
   7928         cb_data->second->validate_functions.push_back(function);
   7929     }
   7930     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImage");
   7931     skipCall |=
   7932         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   7933     if (cb_data != dev_data->commandBufferMap.end()) {
   7934         std::function<VkBool32()> function = [=]() {
   7935             set_memory_valid(dev_data, mem, true, dstImage);
   7936             return VK_FALSE;
   7937         };
   7938         cb_data->second->validate_functions.push_back(function);
   7939     }
   7940     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImage");
   7941     skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
   7942                                            "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
   7943     skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
   7944                                            "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
   7945 #endif
   7946     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7947     if (pCB) {
   7948         skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGE, "vkCmdCopyImage()");
   7949         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImage");
   7950         for (uint32_t i = 0; i < regionCount; ++i) {
   7951             skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].srcSubresource, srcImageLayout);
   7952             skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].dstSubresource, dstImageLayout);
   7953         }
   7954     }
   7955     loader_platform_thread_unlock_mutex(&globalLock);
   7956     if (VK_FALSE == skipCall)
   7957         dev_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
   7958                                                       regionCount, pRegions);
   7959 }
   7960 
   7961 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   7962 vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
   7963                VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) {
   7964     VkBool32 skipCall = VK_FALSE;
   7965     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   7966     loader_platform_thread_lock_mutex(&globalLock);
   7967 #if MTMERGESOURCE
   7968     VkDeviceMemory mem;
   7969     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   7970     // Validate that src & dst images have correct usage flags set
   7971     skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   7972     if (cb_data != dev_data->commandBufferMap.end()) {
   7973         std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBlitImage()", srcImage); };
   7974         cb_data->second->validate_functions.push_back(function);
   7975     }
   7976     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdBlitImage");
   7977     skipCall |=
   7978         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   7979     if (cb_data != dev_data->commandBufferMap.end()) {
   7980         std::function<VkBool32()> function = [=]() {
   7981             set_memory_valid(dev_data, mem, true, dstImage);
   7982             return VK_FALSE;
   7983         };
   7984         cb_data->second->validate_functions.push_back(function);
   7985     }
   7986     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdBlitImage");
   7987     skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
   7988                                            "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
   7989     skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
   7990                                            "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
   7991 #endif
   7992     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   7993     if (pCB) {
   7994         skipCall |= addCmd(dev_data, pCB, CMD_BLITIMAGE, "vkCmdBlitImage()");
   7995         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBlitImage");
   7996     }
   7997     loader_platform_thread_unlock_mutex(&globalLock);
   7998     if (VK_FALSE == skipCall)
   7999         dev_data->device_dispatch_table->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
   8000                                                       regionCount, pRegions, filter);
   8001 }
   8002 
   8003 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer,
   8004                                                                   VkImage dstImage, VkImageLayout dstImageLayout,
   8005                                                                   uint32_t regionCount, const VkBufferImageCopy *pRegions) {
   8006     VkBool32 skipCall = VK_FALSE;
   8007     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8008     loader_platform_thread_lock_mutex(&globalLock);
   8009 #if MTMERGESOURCE
   8010     VkDeviceMemory mem;
   8011     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   8012     skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   8013     if (cb_data != dev_data->commandBufferMap.end()) {
   8014         std::function<VkBool32()> function = [=]() {
   8015             set_memory_valid(dev_data, mem, true, dstImage);
   8016             return VK_FALSE;
   8017         };
   8018         cb_data->second->validate_functions.push_back(function);
   8019     }
   8020     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBufferToImage");
   8021     skipCall |=
   8022         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   8023     if (cb_data != dev_data->commandBufferMap.end()) {
   8024         std::function<VkBool32()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyBufferToImage()"); };
   8025         cb_data->second->validate_functions.push_back(function);
   8026     }
   8027     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBufferToImage");
   8028     // Validate that src buff & dst image have correct usage flags set
   8029     skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
   8030                                             "vkCmdCopyBufferToImage()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
   8031     skipCall |= validate_image_usage_flags(dev_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
   8032                                            "vkCmdCopyBufferToImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
   8033 #endif
   8034     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8035     if (pCB) {
   8036         skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()");
   8037         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBufferToImage");
   8038         for (uint32_t i = 0; i < regionCount; ++i) {
   8039             skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].imageSubresource, dstImageLayout);
   8040         }
   8041     }
   8042     loader_platform_thread_unlock_mutex(&globalLock);
   8043     if (VK_FALSE == skipCall)
   8044         dev_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount,
   8045                                                               pRegions);
   8046 }
   8047 
   8048 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
   8049                                                                   VkImageLayout srcImageLayout, VkBuffer dstBuffer,
   8050                                                                   uint32_t regionCount, const VkBufferImageCopy *pRegions) {
   8051     VkBool32 skipCall = VK_FALSE;
   8052     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8053     loader_platform_thread_lock_mutex(&globalLock);
   8054 #if MTMERGESOURCE
   8055     VkDeviceMemory mem;
   8056     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   8057     skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   8058     if (cb_data != dev_data->commandBufferMap.end()) {
   8059         std::function<VkBool32()> function =
   8060             [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyImageToBuffer()", srcImage); };
   8061         cb_data->second->validate_functions.push_back(function);
   8062     }
   8063     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImageToBuffer");
   8064     skipCall |=
   8065         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   8066     if (cb_data != dev_data->commandBufferMap.end()) {
   8067         std::function<VkBool32()> function = [=]() {
   8068             set_memory_valid(dev_data, mem, true);
   8069             return VK_FALSE;
   8070         };
   8071         cb_data->second->validate_functions.push_back(function);
   8072     }
   8073     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImageToBuffer");
   8074     // Validate that dst buff & src image have correct usage flags set
   8075     skipCall |= validate_image_usage_flags(dev_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
   8076                                            "vkCmdCopyImageToBuffer()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
   8077     skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
   8078                                             "vkCmdCopyImageToBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
   8079 #endif
   8080     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8081     if (pCB) {
   8082         skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()");
   8083         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImageToBuffer");
   8084         for (uint32_t i = 0; i < regionCount; ++i) {
   8085             skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].imageSubresource, srcImageLayout);
   8086         }
   8087     }
   8088     loader_platform_thread_unlock_mutex(&globalLock);
   8089     if (VK_FALSE == skipCall)
   8090         dev_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount,
   8091                                                               pRegions);
   8092 }
   8093 
   8094 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer,
   8095                                                              VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t *pData) {
   8096     VkBool32 skipCall = VK_FALSE;
   8097     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8098     loader_platform_thread_lock_mutex(&globalLock);
   8099 #if MTMERGESOURCE
   8100     VkDeviceMemory mem;
   8101     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   8102     skipCall =
   8103         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   8104     if (cb_data != dev_data->commandBufferMap.end()) {
   8105         std::function<VkBool32()> function = [=]() {
   8106             set_memory_valid(dev_data, mem, true);
   8107             return VK_FALSE;
   8108         };
   8109         cb_data->second->validate_functions.push_back(function);
   8110     }
   8111     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdUpdateBuffer");
   8112     // Validate that dst buff has correct usage flags set
   8113     skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
   8114                                             "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
   8115 #endif
   8116     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8117     if (pCB) {
   8118         skipCall |= addCmd(dev_data, pCB, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
   8119         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyUpdateBuffer");
   8120     }
   8121     loader_platform_thread_unlock_mutex(&globalLock);
   8122     if (VK_FALSE == skipCall)
   8123         dev_data->device_dispatch_table->CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
   8124 }
   8125 
   8126 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8127 vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) {
   8128     VkBool32 skipCall = VK_FALSE;
   8129     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8130     loader_platform_thread_lock_mutex(&globalLock);
   8131 #if MTMERGESOURCE
   8132     VkDeviceMemory mem;
   8133     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   8134     skipCall =
   8135         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   8136     if (cb_data != dev_data->commandBufferMap.end()) {
   8137         std::function<VkBool32()> function = [=]() {
   8138             set_memory_valid(dev_data, mem, true);
   8139             return VK_FALSE;
   8140         };
   8141         cb_data->second->validate_functions.push_back(function);
   8142     }
   8143     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdFillBuffer");
   8144     // Validate that dst buff has correct usage flags set
   8145     skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
   8146                                             "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
   8147 #endif
   8148     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8149     if (pCB) {
   8150         skipCall |= addCmd(dev_data, pCB, CMD_FILLBUFFER, "vkCmdFillBuffer()");
   8151         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyFillBuffer");
   8152     }
   8153     loader_platform_thread_unlock_mutex(&globalLock);
   8154     if (VK_FALSE == skipCall)
   8155         dev_data->device_dispatch_table->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
   8156 }
   8157 
   8158 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
   8159                                                                  const VkClearAttachment *pAttachments, uint32_t rectCount,
   8160                                                                  const VkClearRect *pRects) {
   8161     VkBool32 skipCall = VK_FALSE;
   8162     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8163     loader_platform_thread_lock_mutex(&globalLock);
   8164     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8165     if (pCB) {
   8166         skipCall |= addCmd(dev_data, pCB, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()");
   8167         // Warn if this is issued prior to Draw Cmd and clearing the entire attachment
   8168         if (!hasDrawCmd(pCB) && (pCB->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) &&
   8169             (pCB->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) {
   8170             // TODO : commandBuffer should be srcObj
   8171             // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass)
   8172             // Can we make this warning more specific? I'd like to avoid triggering this test if we can tell it's a use that must
   8173             // call CmdClearAttachments
   8174             // Otherwise this seems more like a performance warning.
   8175             skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   8176                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 0, DRAWSTATE_CLEAR_CMD_BEFORE_DRAW, "DS",
   8177                                 "vkCmdClearAttachments() issued on CB object 0x%" PRIxLEAST64 " prior to any Draw Cmds."
   8178                                 " It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.",
   8179                                 (uint64_t)(commandBuffer));
   8180         }
   8181         skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdClearAttachments");
   8182     }
   8183 
   8184     // Validate that attachment is in reference list of active subpass
   8185     if (pCB->activeRenderPass) {
   8186         const VkRenderPassCreateInfo *pRPCI = dev_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo;
   8187         const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass];
   8188 
   8189         for (uint32_t attachment_idx = 0; attachment_idx < attachmentCount; attachment_idx++) {
   8190             const VkClearAttachment *attachment = &pAttachments[attachment_idx];
   8191             if (attachment->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
   8192                 VkBool32 found = VK_FALSE;
   8193                 for (uint32_t i = 0; i < pSD->colorAttachmentCount; i++) {
   8194                     if (attachment->colorAttachment == pSD->pColorAttachments[i].attachment) {
   8195                         found = VK_TRUE;
   8196                         break;
   8197                     }
   8198                 }
   8199                 if (VK_FALSE == found) {
   8200                     skipCall |= log_msg(
   8201                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   8202                         (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS",
   8203                         "vkCmdClearAttachments() attachment index %d not found in attachment reference array of active subpass %d",
   8204                         attachment->colorAttachment, pCB->activeSubpass);
   8205                 }
   8206             } else if (attachment->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
   8207                 if (!pSD->pDepthStencilAttachment || // Says no DS will be used in active subpass
   8208                     (pSD->pDepthStencilAttachment->attachment ==
   8209                      VK_ATTACHMENT_UNUSED)) { // Says no DS will be used in active subpass
   8210 
   8211                     skipCall |= log_msg(
   8212                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   8213                         (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS",
   8214                         "vkCmdClearAttachments() attachment index %d does not match depthStencilAttachment.attachment (%d) found "
   8215                         "in active subpass %d",
   8216                         attachment->colorAttachment,
   8217                         (pSD->pDepthStencilAttachment) ? pSD->pDepthStencilAttachment->attachment : VK_ATTACHMENT_UNUSED,
   8218                         pCB->activeSubpass);
   8219                 }
   8220             }
   8221         }
   8222     }
   8223     loader_platform_thread_unlock_mutex(&globalLock);
   8224     if (VK_FALSE == skipCall)
   8225         dev_data->device_dispatch_table->CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
   8226 }
   8227 
   8228 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image,
   8229                                                                 VkImageLayout imageLayout, const VkClearColorValue *pColor,
   8230                                                                 uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
   8231     VkBool32 skipCall = VK_FALSE;
   8232     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8233     loader_platform_thread_lock_mutex(&globalLock);
   8234 #if MTMERGESOURCE
   8235     // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
   8236     VkDeviceMemory mem;
   8237     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   8238     skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   8239     if (cb_data != dev_data->commandBufferMap.end()) {
   8240         std::function<VkBool32()> function = [=]() {
   8241             set_memory_valid(dev_data, mem, true, image);
   8242             return VK_FALSE;
   8243         };
   8244         cb_data->second->validate_functions.push_back(function);
   8245     }
   8246     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearColorImage");
   8247 #endif
   8248     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8249     if (pCB) {
   8250         skipCall |= addCmd(dev_data, pCB, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
   8251         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearColorImage");
   8252     }
   8253     loader_platform_thread_unlock_mutex(&globalLock);
   8254     if (VK_FALSE == skipCall)
   8255         dev_data->device_dispatch_table->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
   8256 }
   8257 
   8258 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8259 vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
   8260                             const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
   8261                             const VkImageSubresourceRange *pRanges) {
   8262     VkBool32 skipCall = VK_FALSE;
   8263     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8264     loader_platform_thread_lock_mutex(&globalLock);
   8265 #if MTMERGESOURCE
   8266     // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
   8267     VkDeviceMemory mem;
   8268     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   8269     skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   8270     if (cb_data != dev_data->commandBufferMap.end()) {
   8271         std::function<VkBool32()> function = [=]() {
   8272             set_memory_valid(dev_data, mem, true, image);
   8273             return VK_FALSE;
   8274         };
   8275         cb_data->second->validate_functions.push_back(function);
   8276     }
   8277     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearDepthStencilImage");
   8278 #endif
   8279     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8280     if (pCB) {
   8281         skipCall |= addCmd(dev_data, pCB, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
   8282         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearDepthStencilImage");
   8283     }
   8284     loader_platform_thread_unlock_mutex(&globalLock);
   8285     if (VK_FALSE == skipCall)
   8286         dev_data->device_dispatch_table->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount,
   8287                                                                    pRanges);
   8288 }
   8289 
   8290 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8291 vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
   8292                   VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) {
   8293     VkBool32 skipCall = VK_FALSE;
   8294     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8295     loader_platform_thread_lock_mutex(&globalLock);
   8296 #if MTMERGESOURCE
   8297     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   8298     VkDeviceMemory mem;
   8299     skipCall = get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   8300     if (cb_data != dev_data->commandBufferMap.end()) {
   8301         std::function<VkBool32()> function =
   8302             [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdResolveImage()", srcImage); };
   8303         cb_data->second->validate_functions.push_back(function);
   8304     }
   8305     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdResolveImage");
   8306     skipCall |=
   8307         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   8308     if (cb_data != dev_data->commandBufferMap.end()) {
   8309         std::function<VkBool32()> function = [=]() {
   8310             set_memory_valid(dev_data, mem, true, dstImage);
   8311             return VK_FALSE;
   8312         };
   8313         cb_data->second->validate_functions.push_back(function);
   8314     }
   8315     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdResolveImage");
   8316 #endif
   8317     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8318     if (pCB) {
   8319         skipCall |= addCmd(dev_data, pCB, CMD_RESOLVEIMAGE, "vkCmdResolveImage()");
   8320         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResolveImage");
   8321     }
   8322     loader_platform_thread_unlock_mutex(&globalLock);
   8323     if (VK_FALSE == skipCall)
   8324         dev_data->device_dispatch_table->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
   8325                                                          regionCount, pRegions);
   8326 }
   8327 
   8328 bool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
   8329     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8330     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8331     if (pCB) {
   8332         pCB->eventToStageMap[event] = stageMask;
   8333     }
   8334     auto queue_data = dev_data->queueMap.find(queue);
   8335     if (queue_data != dev_data->queueMap.end()) {
   8336         queue_data->second.eventToStageMap[event] = stageMask;
   8337     }
   8338     return false;
   8339 }
   8340 
   8341 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8342 vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
   8343     VkBool32 skipCall = VK_FALSE;
   8344     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8345     loader_platform_thread_lock_mutex(&globalLock);
   8346     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8347     if (pCB) {
   8348         skipCall |= addCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
   8349         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent");
   8350         pCB->events.push_back(event);
   8351         std::function<bool(VkQueue)> eventUpdate =
   8352             std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
   8353         pCB->eventUpdates.push_back(eventUpdate);
   8354     }
   8355     loader_platform_thread_unlock_mutex(&globalLock);
   8356     if (VK_FALSE == skipCall)
   8357         dev_data->device_dispatch_table->CmdSetEvent(commandBuffer, event, stageMask);
   8358 }
   8359 
   8360 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8361 vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
   8362     VkBool32 skipCall = VK_FALSE;
   8363     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8364     loader_platform_thread_lock_mutex(&globalLock);
   8365     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8366     if (pCB) {
   8367         skipCall |= addCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
   8368         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent");
   8369         pCB->events.push_back(event);
   8370         std::function<bool(VkQueue)> eventUpdate =
   8371             std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
   8372         pCB->eventUpdates.push_back(eventUpdate);
   8373     }
   8374     loader_platform_thread_unlock_mutex(&globalLock);
   8375     if (VK_FALSE == skipCall)
   8376         dev_data->device_dispatch_table->CmdResetEvent(commandBuffer, event, stageMask);
   8377 }
   8378 
   8379 VkBool32 TransitionImageLayouts(VkCommandBuffer cmdBuffer, uint32_t memBarrierCount, const VkImageMemoryBarrier *pImgMemBarriers) {
   8380     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
   8381     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
   8382     VkBool32 skip = VK_FALSE;
   8383     uint32_t levelCount = 0;
   8384     uint32_t layerCount = 0;
   8385 
   8386     for (uint32_t i = 0; i < memBarrierCount; ++i) {
   8387         auto mem_barrier = &pImgMemBarriers[i];
   8388         if (!mem_barrier)
   8389             continue;
   8390         // TODO: Do not iterate over every possibility - consolidate where
   8391         // possible
   8392         ResolveRemainingLevelsLayers(dev_data, &levelCount, &layerCount, mem_barrier->subresourceRange, mem_barrier->image);
   8393 
   8394         for (uint32_t j = 0; j < levelCount; j++) {
   8395             uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j;
   8396             for (uint32_t k = 0; k < layerCount; k++) {
   8397                 uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k;
   8398                 VkImageSubresource sub = {mem_barrier->subresourceRange.aspectMask, level, layer};
   8399                 IMAGE_CMD_BUF_LAYOUT_NODE node;
   8400                 if (!FindLayout(pCB, mem_barrier->image, sub, node)) {
   8401                     SetLayout(pCB, mem_barrier->image, sub, {mem_barrier->oldLayout, mem_barrier->newLayout});
   8402                     continue;
   8403                 }
   8404                 if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
   8405                     // TODO: Set memory invalid which is in mem_tracker currently
   8406                 } else if (node.layout != mem_barrier->oldLayout) {
   8407                     skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   8408                                     __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "You cannot transition the layout from %s "
   8409                                                                                     "when current layout is %s.",
   8410                                     string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout));
   8411                 }
   8412                 SetLayout(pCB, mem_barrier->image, sub, mem_barrier->newLayout);
   8413             }
   8414         }
   8415     }
   8416     return skip;
   8417 }
   8418 
   8419 // Print readable FlagBits in FlagMask
   8420 std::string string_VkAccessFlags(VkAccessFlags accessMask) {
   8421     std::string result;
   8422     std::string separator;
   8423 
   8424     if (accessMask == 0) {
   8425         result = "[None]";
   8426     } else {
   8427         result = "[";
   8428         for (auto i = 0; i < 32; i++) {
   8429             if (accessMask & (1 << i)) {
   8430                 result = result + separator + string_VkAccessFlagBits((VkAccessFlagBits)(1 << i));
   8431                 separator = " | ";
   8432             }
   8433         }
   8434         result = result + "]";
   8435     }
   8436     return result;
   8437 }
   8438 
   8439 // AccessFlags MUST have 'required_bit' set, and may have one or more of 'optional_bits' set.
   8440 // If required_bit is zero, accessMask must have at least one of 'optional_bits' set
   8441 // TODO: Add tracking to ensure that at least one barrier has been set for these layout transitions
   8442 VkBool32 ValidateMaskBits(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
   8443                           const VkImageLayout &layout, VkAccessFlags required_bit, VkAccessFlags optional_bits, const char *type) {
   8444     VkBool32 skip_call = VK_FALSE;
   8445 
   8446     if ((accessMask & required_bit) || (!required_bit && (accessMask & optional_bits))) {
   8447         if (accessMask & !(required_bit | optional_bits)) {
   8448             // TODO: Verify against Valid Use
   8449             skip_call |=
   8450                 log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8451                         DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.",
   8452                         type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
   8453         }
   8454     } else {
   8455         if (!required_bit) {
   8456             skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8457                                  DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must contain at least one of access bits %d "
   8458                                                                   "%s when layout is %s, unless the app has previously added a "
   8459                                                                   "barrier for this transition.",
   8460                                  type, accessMask, string_VkAccessFlags(accessMask).c_str(), optional_bits,
   8461                                  string_VkAccessFlags(optional_bits).c_str(), string_VkImageLayout(layout));
   8462         } else {
   8463             std::string opt_bits;
   8464             if (optional_bits != 0) {
   8465                 std::stringstream ss;
   8466                 ss << optional_bits;
   8467                 opt_bits = "and may have optional bits " + ss.str() + ' ' + string_VkAccessFlags(optional_bits);
   8468             }
   8469             skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8470                                  DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must have required access bit %d %s %s when "
   8471                                                                   "layout is %s, unless the app has previously added a barrier for "
   8472                                                                   "this transition.",
   8473                                  type, accessMask, string_VkAccessFlags(accessMask).c_str(), required_bit,
   8474                                  string_VkAccessFlags(required_bit).c_str(), opt_bits.c_str(), string_VkImageLayout(layout));
   8475         }
   8476     }
   8477     return skip_call;
   8478 }
   8479 
   8480 VkBool32 ValidateMaskBitsFromLayouts(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
   8481                                      const VkImageLayout &layout, const char *type) {
   8482     VkBool32 skip_call = VK_FALSE;
   8483     switch (layout) {
   8484     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: {
   8485         skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
   8486                                       VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, type);
   8487         break;
   8488     }
   8489     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: {
   8490         skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
   8491                                       VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, type);
   8492         break;
   8493     }
   8494     case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: {
   8495         skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_WRITE_BIT, 0, type);
   8496         break;
   8497     }
   8498     case VK_IMAGE_LAYOUT_PREINITIALIZED: {
   8499         skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_HOST_WRITE_BIT, 0, type);
   8500         break;
   8501     }
   8502     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: {
   8503         skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0,
   8504                                       VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type);
   8505         break;
   8506     }
   8507     case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: {
   8508         skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0,
   8509                                       VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type);
   8510         break;
   8511     }
   8512     case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: {
   8513         skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_READ_BIT, 0, type);
   8514         break;
   8515     }
   8516     case VK_IMAGE_LAYOUT_UNDEFINED: {
   8517         if (accessMask != 0) {
   8518             // TODO: Verify against Valid Use section spec
   8519             skip_call |=
   8520                 log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8521                         DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.",
   8522                         type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
   8523         }
   8524         break;
   8525     }
   8526     case VK_IMAGE_LAYOUT_GENERAL:
   8527     default: { break; }
   8528     }
   8529     return skip_call;
   8530 }
   8531 
   8532 VkBool32 ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
   8533                           const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
   8534                           const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
   8535                           const VkImageMemoryBarrier *pImageMemBarriers) {
   8536     VkBool32 skip_call = VK_FALSE;
   8537     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
   8538     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
   8539     if (pCB->activeRenderPass && memBarrierCount) {
   8540         if (!dev_data->renderPassMap[pCB->activeRenderPass]->hasSelfDependency[pCB->activeSubpass]) {
   8541             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8542                                  DRAWSTATE_INVALID_BARRIER, "DS", "%s: Barriers cannot be set during subpass %d "
   8543                                                                   "with no self dependency specified.",
   8544                                  funcName, pCB->activeSubpass);
   8545         }
   8546     }
   8547     for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
   8548         auto mem_barrier = &pImageMemBarriers[i];
   8549         auto image_data = dev_data->imageMap.find(mem_barrier->image);
   8550         if (image_data != dev_data->imageMap.end()) {
   8551             uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
   8552             uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
   8553             if (image_data->second.createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
   8554                 // srcQueueFamilyIndex and dstQueueFamilyIndex must both
   8555                 // be VK_QUEUE_FAMILY_IGNORED
   8556                 if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
   8557                     skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   8558                                          __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
   8559                                          "%s: Image Barrier for image 0x%" PRIx64 " was created with sharingMode of "
   8560                                          "VK_SHARING_MODE_CONCURRENT.  Src and dst "
   8561                                          " queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
   8562                                          funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
   8563                 }
   8564             } else {
   8565                 // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
   8566                 // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
   8567                 // or both be a valid queue family
   8568                 if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
   8569                     (src_q_f_index != dst_q_f_index)) {
   8570                     skip_call |=
   8571                         log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8572                                 DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64 " was created with sharingMode "
   8573                                                                      "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
   8574                                                                      "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
   8575                                                                      "must be.",
   8576                                 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
   8577                 } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
   8578                            ((src_q_f_index >= dev_data->physDevProperties.queue_family_properties.size()) ||
   8579                             (dst_q_f_index >= dev_data->physDevProperties.queue_family_properties.size()))) {
   8580                     skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   8581                                          __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
   8582                                          "%s: Image 0x%" PRIx64 " was created with sharingMode "
   8583                                          "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
   8584                                          " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
   8585                                          "queueFamilies crated for this device.",
   8586                                          funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index,
   8587                                          dst_q_f_index, dev_data->physDevProperties.queue_family_properties.size());
   8588                 }
   8589             }
   8590         }
   8591 
   8592         if (mem_barrier) {
   8593             skip_call |=
   8594                 ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
   8595             skip_call |=
   8596                 ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
   8597             if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
   8598                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8599                         DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image Layout cannot be transitioned to UNDEFINED or "
   8600                                                          "PREINITIALIZED.",
   8601                         funcName);
   8602             }
   8603             auto image_data = dev_data->imageMap.find(mem_barrier->image);
   8604             VkFormat format;
   8605             uint32_t arrayLayers, mipLevels;
   8606             bool imageFound = false;
   8607             if (image_data != dev_data->imageMap.end()) {
   8608                 format = image_data->second.createInfo.format;
   8609                 arrayLayers = image_data->second.createInfo.arrayLayers;
   8610                 mipLevels = image_data->second.createInfo.mipLevels;
   8611                 imageFound = true;
   8612             } else if (dev_data->device_extensions.wsi_enabled) {
   8613                 auto imageswap_data = dev_data->device_extensions.imageToSwapchainMap.find(mem_barrier->image);
   8614                 if (imageswap_data != dev_data->device_extensions.imageToSwapchainMap.end()) {
   8615                     auto swapchain_data = dev_data->device_extensions.swapchainMap.find(imageswap_data->second);
   8616                     if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) {
   8617                         format = swapchain_data->second->createInfo.imageFormat;
   8618                         arrayLayers = swapchain_data->second->createInfo.imageArrayLayers;
   8619                         mipLevels = 1;
   8620                         imageFound = true;
   8621                     }
   8622                 }
   8623             }
   8624             if (imageFound) {
   8625                 if (vk_format_is_depth_and_stencil(format) &&
   8626                     (!(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
   8627                      !(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT))) {
   8628                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8629                             DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image is a depth and stencil format and thus must "
   8630                                                              "have both VK_IMAGE_ASPECT_DEPTH_BIT and "
   8631                                                              "VK_IMAGE_ASPECT_STENCIL_BIT set.",
   8632                             funcName);
   8633                 }
   8634                 int layerCount = (mem_barrier->subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS)
   8635                                      ? 1
   8636                                      : mem_barrier->subresourceRange.layerCount;
   8637                 if ((mem_barrier->subresourceRange.baseArrayLayer + layerCount) > arrayLayers) {
   8638                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8639                             DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the "
   8640                                                              "baseArrayLayer (%d) and layerCount (%d) be less "
   8641                                                              "than or equal to the total number of layers (%d).",
   8642                             funcName, mem_barrier->subresourceRange.baseArrayLayer, mem_barrier->subresourceRange.layerCount,
   8643                             arrayLayers);
   8644                 }
   8645                 int levelCount = (mem_barrier->subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS)
   8646                                      ? 1
   8647                                      : mem_barrier->subresourceRange.levelCount;
   8648                 if ((mem_barrier->subresourceRange.baseMipLevel + levelCount) > mipLevels) {
   8649                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8650                             DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the baseMipLevel "
   8651                                                              "(%d) and levelCount (%d) be less than or equal to "
   8652                                                              "the total number of levels (%d).",
   8653                             funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount,
   8654                             mipLevels);
   8655                 }
   8656             }
   8657         }
   8658     }
   8659     for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
   8660         auto mem_barrier = &pBufferMemBarriers[i];
   8661         if (pCB->activeRenderPass) {
   8662             skip_call |=
   8663                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8664                         DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName);
   8665         }
   8666         if (!mem_barrier)
   8667             continue;
   8668 
   8669         // Validate buffer barrier queue family indices
   8670         if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
   8671              mem_barrier->srcQueueFamilyIndex >= dev_data->physDevProperties.queue_family_properties.size()) ||
   8672             (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
   8673              mem_barrier->dstQueueFamilyIndex >= dev_data->physDevProperties.queue_family_properties.size())) {
   8674             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8675                                  DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
   8676                                  "%s: Buffer Barrier 0x%" PRIx64 " has QueueFamilyIndex greater "
   8677                                  "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
   8678                                  funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
   8679                                  dev_data->physDevProperties.queue_family_properties.size());
   8680         }
   8681 
   8682         auto buffer_data = dev_data->bufferMap.find(mem_barrier->buffer);
   8683         uint64_t buffer_size =
   8684             buffer_data->second.create_info ? reinterpret_cast<uint64_t &>(buffer_data->second.create_info->size) : 0;
   8685         if (buffer_data != dev_data->bufferMap.end()) {
   8686             if (mem_barrier->offset >= buffer_size) {
   8687                 skip_call |=
   8688                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8689                             DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64
   8690                                                              " whose sum is not less than total size %" PRIu64 ".",
   8691                             funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
   8692                             reinterpret_cast<const uint64_t &>(mem_barrier->offset), buffer_size);
   8693             } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
   8694                 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   8695                                      __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
   8696                                      "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 " and size %" PRIu64
   8697                                      " whose sum is greater than total size %" PRIu64 ".",
   8698                                      funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
   8699                                      reinterpret_cast<const uint64_t &>(mem_barrier->offset),
   8700                                      reinterpret_cast<const uint64_t &>(mem_barrier->size), buffer_size);
   8701             }
   8702         }
   8703     }
   8704     return skip_call;
   8705 }
   8706 
   8707 bool validateEventStageMask(VkQueue queue, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags sourceStageMask) {
   8708     bool skip_call = false;
   8709     VkPipelineStageFlags stageMask = 0;
   8710     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
   8711     for (uint32_t i = 0; i < eventCount; ++i) {
   8712         auto queue_data = dev_data->queueMap.find(queue);
   8713         if (queue_data == dev_data->queueMap.end())
   8714             return false;
   8715         auto event_data = queue_data->second.eventToStageMap.find(pEvents[i]);
   8716         if (event_data != queue_data->second.eventToStageMap.end()) {
   8717             stageMask |= event_data->second;
   8718         } else {
   8719             auto global_event_data = dev_data->eventMap.find(pEvents[i]);
   8720             if (global_event_data == dev_data->eventMap.end()) {
   8721                 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
   8722                                      reinterpret_cast<const uint64_t &>(pEvents[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
   8723                                      "Fence 0x%" PRIx64 " cannot be waited on if it has never been set.",
   8724                                      reinterpret_cast<const uint64_t &>(pEvents[i]));
   8725             } else {
   8726                 stageMask |= global_event_data->second.stageMask;
   8727             }
   8728         }
   8729     }
   8730     if (sourceStageMask != stageMask) {
   8731         skip_call |=
   8732             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8733                     DRAWSTATE_INVALID_FENCE, "DS",
   8734                     "Submitting cmdbuffer with call to VkCmdWaitEvents using srcStageMask 0x%x which must be the bitwise OR of the "
   8735                     "stageMask parameters used in calls to vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if used with vkSetEvent.",
   8736                     sourceStageMask);
   8737     }
   8738     return skip_call;
   8739 }
   8740 
   8741 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8742 vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags sourceStageMask,
   8743                 VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
   8744                 uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
   8745                 uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
   8746     VkBool32 skipCall = VK_FALSE;
   8747     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8748     loader_platform_thread_lock_mutex(&globalLock);
   8749     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8750     if (pCB) {
   8751         for (uint32_t i = 0; i < eventCount; ++i) {
   8752             pCB->waitedEvents.push_back(pEvents[i]);
   8753             pCB->events.push_back(pEvents[i]);
   8754         }
   8755         std::function<bool(VkQueue)> eventUpdate =
   8756             std::bind(validateEventStageMask, std::placeholders::_1, eventCount, pEvents, sourceStageMask);
   8757         pCB->eventUpdates.push_back(eventUpdate);
   8758         if (pCB->state == CB_RECORDING) {
   8759             skipCall |= addCmd(dev_data, pCB, CMD_WAITEVENTS, "vkCmdWaitEvents()");
   8760         } else {
   8761             skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWaitEvents()");
   8762         }
   8763         skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
   8764         skipCall |=
   8765             ValidateBarriers("vkCmdWaitEvents", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
   8766                              pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
   8767     }
   8768     loader_platform_thread_unlock_mutex(&globalLock);
   8769     if (VK_FALSE == skipCall)
   8770         dev_data->device_dispatch_table->CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
   8771                                                        memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
   8772                                                        pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
   8773 }
   8774 
   8775 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8776 vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
   8777                      VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
   8778                      uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
   8779                      uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
   8780     VkBool32 skipCall = VK_FALSE;
   8781     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8782     loader_platform_thread_lock_mutex(&globalLock);
   8783     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8784     if (pCB) {
   8785         skipCall |= addCmd(dev_data, pCB, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
   8786         skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
   8787         skipCall |=
   8788             ValidateBarriers("vkCmdPipelineBarrier", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
   8789                              pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
   8790     }
   8791     loader_platform_thread_unlock_mutex(&globalLock);
   8792     if (VK_FALSE == skipCall)
   8793         dev_data->device_dispatch_table->CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags,
   8794                                                             memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
   8795                                                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
   8796 }
   8797 
   8798 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8799 vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
   8800     VkBool32 skipCall = VK_FALSE;
   8801     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8802     loader_platform_thread_lock_mutex(&globalLock);
   8803     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8804     if (pCB) {
   8805         QueryObject query = {queryPool, slot};
   8806         pCB->activeQueries.insert(query);
   8807         if (!pCB->startedQueries.count(query)) {
   8808             pCB->startedQueries.insert(query);
   8809         }
   8810         skipCall |= addCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
   8811     }
   8812     loader_platform_thread_unlock_mutex(&globalLock);
   8813     if (VK_FALSE == skipCall)
   8814         dev_data->device_dispatch_table->CmdBeginQuery(commandBuffer, queryPool, slot, flags);
   8815 }
   8816 
   8817 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
   8818     VkBool32 skipCall = VK_FALSE;
   8819     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8820     loader_platform_thread_lock_mutex(&globalLock);
   8821     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8822     if (pCB) {
   8823         QueryObject query = {queryPool, slot};
   8824         if (!pCB->activeQueries.count(query)) {
   8825             skipCall |=
   8826                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   8827                         DRAWSTATE_INVALID_QUERY, "DS", "Ending a query before it was started: queryPool %" PRIu64 ", index %d",
   8828                         (uint64_t)(queryPool), slot);
   8829         } else {
   8830             pCB->activeQueries.erase(query);
   8831         }
   8832         pCB->queryToStateMap[query] = 1;
   8833         if (pCB->state == CB_RECORDING) {
   8834             skipCall |= addCmd(dev_data, pCB, CMD_ENDQUERY, "VkCmdEndQuery()");
   8835         } else {
   8836             skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdEndQuery()");
   8837         }
   8838     }
   8839     loader_platform_thread_unlock_mutex(&globalLock);
   8840     if (VK_FALSE == skipCall)
   8841         dev_data->device_dispatch_table->CmdEndQuery(commandBuffer, queryPool, slot);
   8842 }
   8843 
   8844 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8845 vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
   8846     VkBool32 skipCall = VK_FALSE;
   8847     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8848     loader_platform_thread_lock_mutex(&globalLock);
   8849     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8850     if (pCB) {
   8851         for (uint32_t i = 0; i < queryCount; i++) {
   8852             QueryObject query = {queryPool, firstQuery + i};
   8853             pCB->waitedEventsBeforeQueryReset[query] = pCB->waitedEvents;
   8854             pCB->queryToStateMap[query] = 0;
   8855         }
   8856         if (pCB->state == CB_RECORDING) {
   8857             skipCall |= addCmd(dev_data, pCB, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
   8858         } else {
   8859             skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdResetQueryPool()");
   8860         }
   8861         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdQueryPool");
   8862     }
   8863     loader_platform_thread_unlock_mutex(&globalLock);
   8864     if (VK_FALSE == skipCall)
   8865         dev_data->device_dispatch_table->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
   8866 }
   8867 
   8868 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8869 vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
   8870                           VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) {
   8871     VkBool32 skipCall = VK_FALSE;
   8872     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8873     loader_platform_thread_lock_mutex(&globalLock);
   8874     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8875 #if MTMERGESOURCE
   8876     VkDeviceMemory mem;
   8877     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   8878     skipCall |=
   8879         get_mem_binding_from_object(dev_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
   8880     if (cb_data != dev_data->commandBufferMap.end()) {
   8881         std::function<VkBool32()> function = [=]() {
   8882             set_memory_valid(dev_data, mem, true);
   8883             return VK_FALSE;
   8884         };
   8885         cb_data->second->validate_functions.push_back(function);
   8886     }
   8887     skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyQueryPoolResults");
   8888     // Validate that DST buffer has correct usage flags set
   8889     skipCall |= validate_buffer_usage_flags(dev_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
   8890                                             "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
   8891 #endif
   8892     if (pCB) {
   8893         for (uint32_t i = 0; i < queryCount; i++) {
   8894             QueryObject query = {queryPool, firstQuery + i};
   8895             if (!pCB->queryToStateMap[query]) {
   8896                 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   8897                                     __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
   8898                                     "Requesting a copy from query to buffer with invalid query: queryPool %" PRIu64 ", index %d",
   8899                                     (uint64_t)(queryPool), firstQuery + i);
   8900             }
   8901         }
   8902         if (pCB->state == CB_RECORDING) {
   8903             skipCall |= addCmd(dev_data, pCB, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
   8904         } else {
   8905             skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdCopyQueryPoolResults()");
   8906         }
   8907         skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyQueryPoolResults");
   8908     }
   8909     loader_platform_thread_unlock_mutex(&globalLock);
   8910     if (VK_FALSE == skipCall)
   8911         dev_data->device_dispatch_table->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer,
   8912                                                                  dstOffset, stride, flags);
   8913 }
   8914 
   8915 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout,
   8916                                                               VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size,
   8917                                                               const void *pValues) {
   8918     bool skipCall = false;
   8919     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8920     loader_platform_thread_lock_mutex(&globalLock);
   8921     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8922     if (pCB) {
   8923         if (pCB->state == CB_RECORDING) {
   8924             skipCall |= addCmd(dev_data, pCB, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
   8925         } else {
   8926             skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdPushConstants()");
   8927         }
   8928     }
   8929     if ((offset + size) > dev_data->physDevProperties.properties.limits.maxPushConstantsSize) {
   8930         skipCall |= validatePushConstantSize(dev_data, offset, size, "vkCmdPushConstants()");
   8931     }
   8932     // TODO : Add warning if push constant update doesn't align with range
   8933     loader_platform_thread_unlock_mutex(&globalLock);
   8934     if (!skipCall)
   8935         dev_data->device_dispatch_table->CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
   8936 }
   8937 
   8938 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   8939 vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t slot) {
   8940     VkBool32 skipCall = VK_FALSE;
   8941     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   8942     loader_platform_thread_lock_mutex(&globalLock);
   8943     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   8944     if (pCB) {
   8945         QueryObject query = {queryPool, slot};
   8946         pCB->queryToStateMap[query] = 1;
   8947         if (pCB->state == CB_RECORDING) {
   8948             skipCall |= addCmd(dev_data, pCB, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
   8949         } else {
   8950             skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWriteTimestamp()");
   8951         }
   8952     }
   8953     loader_platform_thread_unlock_mutex(&globalLock);
   8954     if (VK_FALSE == skipCall)
   8955         dev_data->device_dispatch_table->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
   8956 }
   8957 
   8958 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
   8959                                                                    const VkAllocationCallbacks *pAllocator,
   8960                                                                    VkFramebuffer *pFramebuffer) {
   8961     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   8962     VkResult result = dev_data->device_dispatch_table->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
   8963     if (VK_SUCCESS == result) {
   8964         // Shadow create info and store in map
   8965         VkFramebufferCreateInfo *localFBCI = new VkFramebufferCreateInfo(*pCreateInfo);
   8966         if (pCreateInfo->pAttachments) {
   8967             localFBCI->pAttachments = new VkImageView[localFBCI->attachmentCount];
   8968             memcpy((void *)localFBCI->pAttachments, pCreateInfo->pAttachments, localFBCI->attachmentCount * sizeof(VkImageView));
   8969         }
   8970         FRAMEBUFFER_NODE fbNode = {};
   8971         fbNode.createInfo = *localFBCI;
   8972         std::pair<VkFramebuffer, FRAMEBUFFER_NODE> fbPair(*pFramebuffer, fbNode);
   8973         loader_platform_thread_lock_mutex(&globalLock);
   8974         for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
   8975             VkImageView view = pCreateInfo->pAttachments[i];
   8976             auto view_data = dev_data->imageViewMap.find(view);
   8977             if (view_data == dev_data->imageViewMap.end()) {
   8978                 continue;
   8979             }
   8980             MT_FB_ATTACHMENT_INFO fb_info;
   8981             get_mem_binding_from_object(dev_data, device, (uint64_t)(view_data->second.image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   8982                                         &fb_info.mem);
   8983             fb_info.image = view_data->second.image;
   8984             fbPair.second.attachments.push_back(fb_info);
   8985         }
   8986         dev_data->frameBufferMap.insert(fbPair);
   8987         loader_platform_thread_unlock_mutex(&globalLock);
   8988     }
   8989     return result;
   8990 }
   8991 
   8992 VkBool32 FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node,
   8993                         std::unordered_set<uint32_t> &processed_nodes) {
   8994     // If we have already checked this node we have not found a dependency path so return false.
   8995     if (processed_nodes.count(index))
   8996         return VK_FALSE;
   8997     processed_nodes.insert(index);
   8998     const DAGNode &node = subpass_to_node[index];
   8999     // Look for a dependency path. If one exists return true else recurse on the previous nodes.
   9000     if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
   9001         for (auto elem : node.prev) {
   9002             if (FindDependency(elem, dependent, subpass_to_node, processed_nodes))
   9003                 return VK_TRUE;
   9004         }
   9005     } else {
   9006         return VK_TRUE;
   9007     }
   9008     return VK_FALSE;
   9009 }
   9010 
   9011 VkBool32 CheckDependencyExists(const layer_data *my_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses,
   9012                                const std::vector<DAGNode> &subpass_to_node, VkBool32 &skip_call) {
   9013     VkBool32 result = VK_TRUE;
   9014     // Loop through all subpasses that share the same attachment and make sure a dependency exists
   9015     for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
   9016         if (subpass == dependent_subpasses[k])
   9017             continue;
   9018         const DAGNode &node = subpass_to_node[subpass];
   9019         // Check for a specified dependency between the two nodes. If one exists we are done.
   9020         auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
   9021         auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
   9022         if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
   9023             // If no dependency exits an implicit dependency still might. If so, warn and if not throw an error.
   9024             std::unordered_set<uint32_t> processed_nodes;
   9025             if (FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
   9026                 FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes)) {
   9027                 // TODO: Verify against Valid Use section of spec
   9028                 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   9029                                      __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
   9030                                      "A dependency between subpasses %d and %d must exist but only an implicit one is specified.",
   9031                                      subpass, dependent_subpasses[k]);
   9032             } else {
   9033                 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   9034                                      __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
   9035                                      "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
   9036                                      dependent_subpasses[k]);
   9037                 result = VK_FALSE;
   9038             }
   9039         }
   9040     }
   9041     return result;
   9042 }
   9043 
   9044 VkBool32 CheckPreserved(const layer_data *my_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
   9045                         const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, VkBool32 &skip_call) {
   9046     const DAGNode &node = subpass_to_node[index];
   9047     // If this node writes to the attachment return true as next nodes need to preserve the attachment.
   9048     const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
   9049     for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
   9050         if (attachment == subpass.pColorAttachments[j].attachment)
   9051             return VK_TRUE;
   9052     }
   9053     if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
   9054         if (attachment == subpass.pDepthStencilAttachment->attachment)
   9055             return VK_TRUE;
   9056     }
   9057     VkBool32 result = VK_FALSE;
   9058     // Loop through previous nodes and see if any of them write to the attachment.
   9059     for (auto elem : node.prev) {
   9060         result |= CheckPreserved(my_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call);
   9061     }
   9062     // If the attachment was written to by a previous node than this node needs to preserve it.
   9063     if (result && depth > 0) {
   9064         const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
   9065         VkBool32 has_preserved = VK_FALSE;
   9066         for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
   9067             if (subpass.pPreserveAttachments[j] == attachment) {
   9068                 has_preserved = VK_TRUE;
   9069                 break;
   9070             }
   9071         }
   9072         if (has_preserved == VK_FALSE) {
   9073             skip_call |=
   9074                 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9075                         DRAWSTATE_INVALID_RENDERPASS, "DS",
   9076                         "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
   9077         }
   9078     }
   9079     return result;
   9080 }
   9081 
   9082 template <class T> bool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
   9083     return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
   9084            ((offset1 > offset2) && (offset1 < (offset2 + size2)));
   9085 }
   9086 
   9087 bool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
   9088     return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
   9089             isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
   9090 }
   9091 
   9092 VkBool32 ValidateDependencies(const layer_data *my_data, const VkRenderPassBeginInfo *pRenderPassBegin,
   9093                               const std::vector<DAGNode> &subpass_to_node) {
   9094     VkBool32 skip_call = VK_FALSE;
   9095     const VkFramebufferCreateInfo *pFramebufferInfo = &my_data->frameBufferMap.at(pRenderPassBegin->framebuffer).createInfo;
   9096     const VkRenderPassCreateInfo *pCreateInfo = my_data->renderPassMap.at(pRenderPassBegin->renderPass)->pCreateInfo;
   9097     std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
   9098     std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
   9099     std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
   9100     // Find overlapping attachments
   9101     for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
   9102         for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
   9103             VkImageView viewi = pFramebufferInfo->pAttachments[i];
   9104             VkImageView viewj = pFramebufferInfo->pAttachments[j];
   9105             if (viewi == viewj) {
   9106                 overlapping_attachments[i].push_back(j);
   9107                 overlapping_attachments[j].push_back(i);
   9108                 continue;
   9109             }
   9110             auto view_data_i = my_data->imageViewMap.find(viewi);
   9111             auto view_data_j = my_data->imageViewMap.find(viewj);
   9112             if (view_data_i == my_data->imageViewMap.end() || view_data_j == my_data->imageViewMap.end()) {
   9113                 continue;
   9114             }
   9115             if (view_data_i->second.image == view_data_j->second.image &&
   9116                 isRegionOverlapping(view_data_i->second.subresourceRange, view_data_j->second.subresourceRange)) {
   9117                 overlapping_attachments[i].push_back(j);
   9118                 overlapping_attachments[j].push_back(i);
   9119                 continue;
   9120             }
   9121             auto image_data_i = my_data->imageMap.find(view_data_i->second.image);
   9122             auto image_data_j = my_data->imageMap.find(view_data_j->second.image);
   9123             if (image_data_i == my_data->imageMap.end() || image_data_j == my_data->imageMap.end()) {
   9124                 continue;
   9125             }
   9126             if (image_data_i->second.mem == image_data_j->second.mem &&
   9127                 isRangeOverlapping(image_data_i->second.memOffset, image_data_i->second.memSize, image_data_j->second.memOffset,
   9128                                    image_data_j->second.memSize)) {
   9129                 overlapping_attachments[i].push_back(j);
   9130                 overlapping_attachments[j].push_back(i);
   9131             }
   9132         }
   9133     }
   9134     for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
   9135         uint32_t attachment = i;
   9136         for (auto other_attachment : overlapping_attachments[i]) {
   9137             if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
   9138                 skip_call |=
   9139                     log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9140                             DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't "
   9141                                                                 "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.",
   9142                             attachment, other_attachment);
   9143             }
   9144             if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
   9145                 skip_call |=
   9146                     log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9147                             DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't "
   9148                                                                 "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.",
   9149                             other_attachment, attachment);
   9150             }
   9151         }
   9152     }
   9153     // Find for each attachment the subpasses that use them.
   9154     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
   9155         const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
   9156         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
   9157             uint32_t attachment = subpass.pInputAttachments[j].attachment;
   9158             input_attachment_to_subpass[attachment].push_back(i);
   9159             for (auto overlapping_attachment : overlapping_attachments[attachment]) {
   9160                 input_attachment_to_subpass[overlapping_attachment].push_back(i);
   9161             }
   9162         }
   9163         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
   9164             uint32_t attachment = subpass.pColorAttachments[j].attachment;
   9165             output_attachment_to_subpass[attachment].push_back(i);
   9166             for (auto overlapping_attachment : overlapping_attachments[attachment]) {
   9167                 output_attachment_to_subpass[overlapping_attachment].push_back(i);
   9168             }
   9169         }
   9170         if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
   9171             uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
   9172             output_attachment_to_subpass[attachment].push_back(i);
   9173             for (auto overlapping_attachment : overlapping_attachments[attachment]) {
   9174                 output_attachment_to_subpass[overlapping_attachment].push_back(i);
   9175             }
   9176         }
   9177     }
   9178     // If there is a dependency needed make sure one exists
   9179     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
   9180         const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
   9181         // If the attachment is an input then all subpasses that output must have a dependency relationship
   9182         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
   9183             const uint32_t &attachment = subpass.pInputAttachments[j].attachment;
   9184             CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
   9185         }
   9186         // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
   9187         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
   9188             const uint32_t &attachment = subpass.pColorAttachments[j].attachment;
   9189             CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
   9190             CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
   9191         }
   9192         if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
   9193             const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
   9194             CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
   9195             CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
   9196         }
   9197     }
   9198     // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
   9199     // written.
   9200     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
   9201         const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
   9202         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
   9203             CheckPreserved(my_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call);
   9204         }
   9205     }
   9206     return skip_call;
   9207 }
   9208 
   9209 VkBool32 ValidateLayouts(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo) {
   9210     VkBool32 skip = VK_FALSE;
   9211 
   9212     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
   9213         const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
   9214         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
   9215             if (subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL &&
   9216                 subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
   9217                 if (subpass.pInputAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) {
   9218                     // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
   9219                     skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   9220                                     (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   9221                                     "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL.");
   9222                 } else {
   9223                     skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9224                                     DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   9225                                     "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.",
   9226                                     string_VkImageLayout(subpass.pInputAttachments[j].layout));
   9227                 }
   9228             }
   9229         }
   9230         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
   9231             if (subpass.pColorAttachments[j].layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
   9232                 if (subpass.pColorAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) {
   9233                     // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
   9234                     skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   9235                                     (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   9236                                     "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL.");
   9237                 } else {
   9238                     skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9239                                     DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   9240                                     "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
   9241                                     string_VkImageLayout(subpass.pColorAttachments[j].layout));
   9242                 }
   9243             }
   9244         }
   9245         if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
   9246             if (subpass.pDepthStencilAttachment->layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
   9247                 if (subpass.pDepthStencilAttachment->layout == VK_IMAGE_LAYOUT_GENERAL) {
   9248                     // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
   9249                     skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   9250                                     (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   9251                                     "Layout for depth attachment is GENERAL but should be DEPTH_STENCIL_ATTACHMENT_OPTIMAL.");
   9252                 } else {
   9253                     skip |=
   9254                         log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9255                                 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   9256                                 "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL or GENERAL.",
   9257                                 string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
   9258                 }
   9259             }
   9260         }
   9261     }
   9262     return skip;
   9263 }
   9264 
   9265 VkBool32 CreatePassDAG(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
   9266                        std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
   9267     VkBool32 skip_call = VK_FALSE;
   9268     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
   9269         DAGNode &subpass_node = subpass_to_node[i];
   9270         subpass_node.pass = i;
   9271     }
   9272     for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
   9273         const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
   9274         if (dependency.srcSubpass > dependency.dstSubpass && dependency.srcSubpass != VK_SUBPASS_EXTERNAL &&
   9275             dependency.dstSubpass != VK_SUBPASS_EXTERNAL) {
   9276             skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9277                                  DRAWSTATE_INVALID_RENDERPASS, "DS",
   9278                                  "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
   9279         } else if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL && dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
   9280             skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9281                                  DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
   9282         } else if (dependency.srcSubpass == dependency.dstSubpass) {
   9283             has_self_dependency[dependency.srcSubpass] = true;
   9284         }
   9285         if (dependency.dstSubpass != VK_SUBPASS_EXTERNAL) {
   9286             subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
   9287         }
   9288         if (dependency.srcSubpass != VK_SUBPASS_EXTERNAL) {
   9289             subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
   9290         }
   9291     }
   9292     return skip_call;
   9293 }
   9294 
   9295 
   9296 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
   9297                                                                     const VkAllocationCallbacks *pAllocator,
   9298                                                                     VkShaderModule *pShaderModule) {
   9299     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   9300     VkBool32 skip_call = VK_FALSE;
   9301     if (!shader_is_spirv(pCreateInfo)) {
   9302         skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   9303                              /* dev */ 0, __LINE__, SHADER_CHECKER_NON_SPIRV_SHADER, "SC", "Shader is not SPIR-V");
   9304     }
   9305 
   9306     if (VK_FALSE != skip_call)
   9307         return VK_ERROR_VALIDATION_FAILED_EXT;
   9308 
   9309     VkResult res = my_data->device_dispatch_table->CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
   9310 
   9311     if (res == VK_SUCCESS) {
   9312         loader_platform_thread_lock_mutex(&globalLock);
   9313         my_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new shader_module(pCreateInfo));
   9314         loader_platform_thread_unlock_mutex(&globalLock);
   9315     }
   9316     return res;
   9317 }
   9318 
   9319 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
   9320                                                                   const VkAllocationCallbacks *pAllocator,
   9321                                                                   VkRenderPass *pRenderPass) {
   9322     VkBool32 skip_call = VK_FALSE;
   9323     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   9324     loader_platform_thread_lock_mutex(&globalLock);
   9325     // Create DAG
   9326     std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
   9327     std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
   9328     skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency);
   9329     // Validate
   9330     skip_call |= ValidateLayouts(dev_data, device, pCreateInfo);
   9331     if (VK_FALSE != skip_call) {
   9332         return VK_ERROR_VALIDATION_FAILED_EXT;
   9333     }
   9334     loader_platform_thread_unlock_mutex(&globalLock);
   9335     VkResult result = dev_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
   9336     if (VK_SUCCESS == result) {
   9337         loader_platform_thread_lock_mutex(&globalLock);
   9338         // TODOSC : Merge in tracking of renderpass from shader_checker
   9339         // Shadow create info and store in map
   9340         VkRenderPassCreateInfo *localRPCI = new VkRenderPassCreateInfo(*pCreateInfo);
   9341         if (pCreateInfo->pAttachments) {
   9342             localRPCI->pAttachments = new VkAttachmentDescription[localRPCI->attachmentCount];
   9343             memcpy((void *)localRPCI->pAttachments, pCreateInfo->pAttachments,
   9344                    localRPCI->attachmentCount * sizeof(VkAttachmentDescription));
   9345         }
   9346         if (pCreateInfo->pSubpasses) {
   9347             localRPCI->pSubpasses = new VkSubpassDescription[localRPCI->subpassCount];
   9348             memcpy((void *)localRPCI->pSubpasses, pCreateInfo->pSubpasses, localRPCI->subpassCount * sizeof(VkSubpassDescription));
   9349 
   9350             for (uint32_t i = 0; i < localRPCI->subpassCount; i++) {
   9351                 VkSubpassDescription *subpass = (VkSubpassDescription *)&localRPCI->pSubpasses[i];
   9352                 const uint32_t attachmentCount = subpass->inputAttachmentCount +
   9353                                                  subpass->colorAttachmentCount * (1 + (subpass->pResolveAttachments ? 1 : 0)) +
   9354                                                  ((subpass->pDepthStencilAttachment) ? 1 : 0) + subpass->preserveAttachmentCount;
   9355                 VkAttachmentReference *attachments = new VkAttachmentReference[attachmentCount];
   9356 
   9357                 memcpy(attachments, subpass->pInputAttachments, sizeof(attachments[0]) * subpass->inputAttachmentCount);
   9358                 subpass->pInputAttachments = attachments;
   9359                 attachments += subpass->inputAttachmentCount;
   9360 
   9361                 memcpy(attachments, subpass->pColorAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount);
   9362                 subpass->pColorAttachments = attachments;
   9363                 attachments += subpass->colorAttachmentCount;
   9364 
   9365                 if (subpass->pResolveAttachments) {
   9366                     memcpy(attachments, subpass->pResolveAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount);
   9367                     subpass->pResolveAttachments = attachments;
   9368                     attachments += subpass->colorAttachmentCount;
   9369                 }
   9370 
   9371                 if (subpass->pDepthStencilAttachment) {
   9372                     memcpy(attachments, subpass->pDepthStencilAttachment, sizeof(attachments[0]) * 1);
   9373                     subpass->pDepthStencilAttachment = attachments;
   9374                     attachments += 1;
   9375                 }
   9376 
   9377                 memcpy(attachments, subpass->pPreserveAttachments, sizeof(attachments[0]) * subpass->preserveAttachmentCount);
   9378                 subpass->pPreserveAttachments = &attachments->attachment;
   9379             }
   9380         }
   9381         if (pCreateInfo->pDependencies) {
   9382             localRPCI->pDependencies = new VkSubpassDependency[localRPCI->dependencyCount];
   9383             memcpy((void *)localRPCI->pDependencies, pCreateInfo->pDependencies,
   9384                    localRPCI->dependencyCount * sizeof(VkSubpassDependency));
   9385         }
   9386         dev_data->renderPassMap[*pRenderPass] = new RENDER_PASS_NODE(localRPCI);
   9387         dev_data->renderPassMap[*pRenderPass]->hasSelfDependency = has_self_dependency;
   9388         dev_data->renderPassMap[*pRenderPass]->subpassToNode = subpass_to_node;
   9389 #if MTMERGESOURCE
   9390         // MTMTODO : Merge with code from above to eliminate duplication
   9391         for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
   9392             VkAttachmentDescription desc = pCreateInfo->pAttachments[i];
   9393             MT_PASS_ATTACHMENT_INFO pass_info;
   9394             pass_info.load_op = desc.loadOp;
   9395             pass_info.store_op = desc.storeOp;
   9396             pass_info.attachment = i;
   9397             dev_data->renderPassMap[*pRenderPass]->attachments.push_back(pass_info);
   9398         }
   9399         // TODO: Maybe fill list and then copy instead of locking
   9400         std::unordered_map<uint32_t, bool> &attachment_first_read = dev_data->renderPassMap[*pRenderPass]->attachment_first_read;
   9401         std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout =
   9402             dev_data->renderPassMap[*pRenderPass]->attachment_first_layout;
   9403         for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
   9404             const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
   9405             for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
   9406                 uint32_t attachment = subpass.pInputAttachments[j].attachment;
   9407                 if (attachment_first_read.count(attachment))
   9408                     continue;
   9409                 attachment_first_read.insert(std::make_pair(attachment, true));
   9410                 attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout));
   9411             }
   9412             for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
   9413                 uint32_t attachment = subpass.pColorAttachments[j].attachment;
   9414                 if (attachment_first_read.count(attachment))
   9415                     continue;
   9416                 attachment_first_read.insert(std::make_pair(attachment, false));
   9417                 attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout));
   9418             }
   9419             if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
   9420                 uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
   9421                 if (attachment_first_read.count(attachment))
   9422                     continue;
   9423                 attachment_first_read.insert(std::make_pair(attachment, false));
   9424                 attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout));
   9425             }
   9426         }
   9427 #endif
   9428         loader_platform_thread_unlock_mutex(&globalLock);
   9429     }
   9430     return result;
   9431 }
   9432 // Free the renderpass shadow
   9433 static void deleteRenderPasses(layer_data *my_data) {
   9434     if (my_data->renderPassMap.size() <= 0)
   9435         return;
   9436     for (auto ii = my_data->renderPassMap.begin(); ii != my_data->renderPassMap.end(); ++ii) {
   9437         const VkRenderPassCreateInfo *pRenderPassInfo = (*ii).second->pCreateInfo;
   9438         delete[] pRenderPassInfo->pAttachments;
   9439         if (pRenderPassInfo->pSubpasses) {
   9440             for (uint32_t i = 0; i < pRenderPassInfo->subpassCount; ++i) {
   9441                 // Attachements are all allocated in a block, so just need to
   9442                 //  find the first non-null one to delete
   9443                 if (pRenderPassInfo->pSubpasses[i].pInputAttachments) {
   9444                     delete[] pRenderPassInfo->pSubpasses[i].pInputAttachments;
   9445                 } else if (pRenderPassInfo->pSubpasses[i].pColorAttachments) {
   9446                     delete[] pRenderPassInfo->pSubpasses[i].pColorAttachments;
   9447                 } else if (pRenderPassInfo->pSubpasses[i].pResolveAttachments) {
   9448                     delete[] pRenderPassInfo->pSubpasses[i].pResolveAttachments;
   9449                 } else if (pRenderPassInfo->pSubpasses[i].pPreserveAttachments) {
   9450                     delete[] pRenderPassInfo->pSubpasses[i].pPreserveAttachments;
   9451                 }
   9452             }
   9453             delete[] pRenderPassInfo->pSubpasses;
   9454         }
   9455         delete[] pRenderPassInfo->pDependencies;
   9456         delete pRenderPassInfo;
   9457         delete (*ii).second;
   9458     }
   9459     my_data->renderPassMap.clear();
   9460 }
   9461 
   9462 VkBool32 VerifyFramebufferAndRenderPassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) {
   9463     VkBool32 skip_call = VK_FALSE;
   9464     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
   9465     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
   9466     const VkRenderPassCreateInfo *pRenderPassInfo = dev_data->renderPassMap[pRenderPassBegin->renderPass]->pCreateInfo;
   9467     const VkFramebufferCreateInfo framebufferInfo = dev_data->frameBufferMap[pRenderPassBegin->framebuffer].createInfo;
   9468     if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) {
   9469         skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9470                              DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using a framebuffer "
   9471                                                                  "with a different number of attachments.");
   9472     }
   9473     for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
   9474         const VkImageView &image_view = framebufferInfo.pAttachments[i];
   9475         auto image_data = dev_data->imageViewMap.find(image_view);
   9476         assert(image_data != dev_data->imageViewMap.end());
   9477         const VkImage &image = image_data->second.image;
   9478         const VkImageSubresourceRange &subRange = image_data->second.subresourceRange;
   9479         IMAGE_CMD_BUF_LAYOUT_NODE newNode = {pRenderPassInfo->pAttachments[i].initialLayout,
   9480                                              pRenderPassInfo->pAttachments[i].initialLayout};
   9481         // TODO: Do not iterate over every possibility - consolidate where possible
   9482         for (uint32_t j = 0; j < subRange.levelCount; j++) {
   9483             uint32_t level = subRange.baseMipLevel + j;
   9484             for (uint32_t k = 0; k < subRange.layerCount; k++) {
   9485                 uint32_t layer = subRange.baseArrayLayer + k;
   9486                 VkImageSubresource sub = {subRange.aspectMask, level, layer};
   9487                 IMAGE_CMD_BUF_LAYOUT_NODE node;
   9488                 if (!FindLayout(pCB, image, sub, node)) {
   9489                     SetLayout(pCB, image, sub, newNode);
   9490                     continue;
   9491                 }
   9492                 if (newNode.layout != node.layout) {
   9493                     skip_call |=
   9494                         log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9495                                 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using attachment %i "
   9496                                                                     "where the "
   9497                                                                     "intial layout differs from the starting layout.",
   9498                                 i);
   9499                 }
   9500             }
   9501         }
   9502     }
   9503     return skip_call;
   9504 }
   9505 
   9506 void TransitionSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, const int subpass_index) {
   9507     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
   9508     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
   9509     auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass);
   9510     if (render_pass_data == dev_data->renderPassMap.end()) {
   9511         return;
   9512     }
   9513     const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo;
   9514     auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer);
   9515     if (framebuffer_data == dev_data->frameBufferMap.end()) {
   9516         return;
   9517     }
   9518     const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo;
   9519     const VkSubpassDescription &subpass = pRenderPassInfo->pSubpasses[subpass_index];
   9520     for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
   9521         const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pInputAttachments[j].attachment];
   9522         SetLayout(dev_data, pCB, image_view, subpass.pInputAttachments[j].layout);
   9523     }
   9524     for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
   9525         const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pColorAttachments[j].attachment];
   9526         SetLayout(dev_data, pCB, image_view, subpass.pColorAttachments[j].layout);
   9527     }
   9528     if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
   9529         const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pDepthStencilAttachment->attachment];
   9530         SetLayout(dev_data, pCB, image_view, subpass.pDepthStencilAttachment->layout);
   9531     }
   9532 }
   9533 
   9534 VkBool32 validatePrimaryCommandBuffer(const layer_data *my_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name) {
   9535     VkBool32 skip_call = VK_FALSE;
   9536     if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
   9537         skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9538                              DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", "Cannot execute command %s on a secondary command buffer.",
   9539                              cmd_name.c_str());
   9540     }
   9541     return skip_call;
   9542 }
   9543 
   9544 void TransitionFinalSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) {
   9545     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
   9546     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
   9547     auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass);
   9548     if (render_pass_data == dev_data->renderPassMap.end()) {
   9549         return;
   9550     }
   9551     const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo;
   9552     auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer);
   9553     if (framebuffer_data == dev_data->frameBufferMap.end()) {
   9554         return;
   9555     }
   9556     const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo;
   9557     for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
   9558         const VkImageView &image_view = framebufferInfo.pAttachments[i];
   9559         SetLayout(dev_data, pCB, image_view, pRenderPassInfo->pAttachments[i].finalLayout);
   9560     }
   9561 }
   9562 
   9563 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   9564 vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) {
   9565     VkBool32 skipCall = VK_FALSE;
   9566     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   9567     loader_platform_thread_lock_mutex(&globalLock);
   9568     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   9569     if (pCB) {
   9570         if (pRenderPassBegin && pRenderPassBegin->renderPass) {
   9571 #if MTMERGE
   9572             auto pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass);
   9573             if (pass_data != dev_data->renderPassMap.end()) {
   9574                 RENDER_PASS_NODE* pRPNode = pass_data->second;
   9575                 pRPNode->fb = pRenderPassBegin->framebuffer;
   9576                 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   9577                 for (size_t i = 0; i < pRPNode->attachments.size(); ++i) {
   9578                     MT_FB_ATTACHMENT_INFO &fb_info = dev_data->frameBufferMap[pRPNode->fb].attachments[i];
   9579                     if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) {
   9580                         if (cb_data != dev_data->commandBufferMap.end()) {
   9581                             std::function<VkBool32()> function = [=]() {
   9582                                 set_memory_valid(dev_data, fb_info.mem, true, fb_info.image);
   9583                                 return VK_FALSE;
   9584                             };
   9585                             cb_data->second->validate_functions.push_back(function);
   9586                         }
   9587                         VkImageLayout &attachment_layout = pRPNode->attachment_first_layout[pRPNode->attachments[i].attachment];
   9588                         if (attachment_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ||
   9589                             attachment_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
   9590                             skipCall |=
   9591                                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   9592                                         VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, (uint64_t)(pRenderPassBegin->renderPass), __LINE__,
   9593                                         MEMTRACK_INVALID_LAYOUT, "MEM", "Cannot clear attachment %d with invalid first layout %d.",
   9594                                         pRPNode->attachments[i].attachment, attachment_layout);
   9595                         }
   9596                     } else if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) {
   9597                         if (cb_data != dev_data->commandBufferMap.end()) {
   9598                             std::function<VkBool32()> function = [=]() {
   9599                                 set_memory_valid(dev_data, fb_info.mem, false, fb_info.image);
   9600                                 return VK_FALSE;
   9601                             };
   9602                             cb_data->second->validate_functions.push_back(function);
   9603                         }
   9604                     } else if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_LOAD) {
   9605                         if (cb_data != dev_data->commandBufferMap.end()) {
   9606                             std::function<VkBool32()> function = [=]() {
   9607                                 return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image);
   9608                             };
   9609                             cb_data->second->validate_functions.push_back(function);
   9610                         }
   9611                     }
   9612                     if (pRPNode->attachment_first_read[pRPNode->attachments[i].attachment]) {
   9613                         if (cb_data != dev_data->commandBufferMap.end()) {
   9614                             std::function<VkBool32()> function = [=]() {
   9615                                 return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image);
   9616                             };
   9617                             cb_data->second->validate_functions.push_back(function);
   9618                         }
   9619                     }
   9620                 }
   9621             }
   9622 #endif
   9623             skipCall |= VerifyFramebufferAndRenderPassLayouts(commandBuffer, pRenderPassBegin);
   9624             auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass);
   9625             if (render_pass_data != dev_data->renderPassMap.end()) {
   9626                 skipCall |= ValidateDependencies(dev_data, pRenderPassBegin, render_pass_data->second->subpassToNode);
   9627             }
   9628             skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBeginRenderPass");
   9629             skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdBeginRenderPass");
   9630             skipCall |= addCmd(dev_data, pCB, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
   9631             pCB->activeRenderPass = pRenderPassBegin->renderPass;
   9632             // This is a shallow copy as that is all that is needed for now
   9633             pCB->activeRenderPassBeginInfo = *pRenderPassBegin;
   9634             pCB->activeSubpass = 0;
   9635             pCB->activeSubpassContents = contents;
   9636             pCB->framebuffer = pRenderPassBegin->framebuffer;
   9637             // Connect this framebuffer to this cmdBuffer
   9638             dev_data->frameBufferMap[pCB->framebuffer].referencingCmdBuffers.insert(pCB->commandBuffer);
   9639         } else {
   9640             skipCall |=
   9641                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9642                         DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot use a NULL RenderPass object in vkCmdBeginRenderPass()");
   9643         }
   9644     }
   9645     loader_platform_thread_unlock_mutex(&globalLock);
   9646     if (VK_FALSE == skipCall) {
   9647         dev_data->device_dispatch_table->CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
   9648         loader_platform_thread_lock_mutex(&globalLock);
   9649         // This is a shallow copy as that is all that is needed for now
   9650         dev_data->renderPassBeginInfo = *pRenderPassBegin;
   9651         dev_data->currentSubpass = 0;
   9652         loader_platform_thread_unlock_mutex(&globalLock);
   9653     }
   9654 }
   9655 
   9656 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
   9657     VkBool32 skipCall = VK_FALSE;
   9658     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   9659     loader_platform_thread_lock_mutex(&globalLock);
   9660     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   9661     TransitionSubpassLayouts(commandBuffer, &dev_data->renderPassBeginInfo, ++dev_data->currentSubpass);
   9662     if (pCB) {
   9663         skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass");
   9664         skipCall |= addCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
   9665         pCB->activeSubpass++;
   9666         pCB->activeSubpassContents = contents;
   9667         TransitionSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass);
   9668         if (pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline) {
   9669             skipCall |= validatePipelineState(dev_data, pCB, VK_PIPELINE_BIND_POINT_GRAPHICS,
   9670                                               pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
   9671         }
   9672         skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass");
   9673     }
   9674     loader_platform_thread_unlock_mutex(&globalLock);
   9675     if (VK_FALSE == skipCall)
   9676         dev_data->device_dispatch_table->CmdNextSubpass(commandBuffer, contents);
   9677 }
   9678 
   9679 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(VkCommandBuffer commandBuffer) {
   9680     VkBool32 skipCall = VK_FALSE;
   9681     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   9682     loader_platform_thread_lock_mutex(&globalLock);
   9683 #if MTMERGESOURCE
   9684     auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
   9685     if (cb_data != dev_data->commandBufferMap.end()) {
   9686         auto pass_data = dev_data->renderPassMap.find(cb_data->second->activeRenderPass);
   9687         if (pass_data != dev_data->renderPassMap.end()) {
   9688             RENDER_PASS_NODE* pRPNode = pass_data->second;
   9689             for (size_t i = 0; i < pRPNode->attachments.size(); ++i) {
   9690                 MT_FB_ATTACHMENT_INFO &fb_info = dev_data->frameBufferMap[pRPNode->fb].attachments[i];
   9691                 if (pRPNode->attachments[i].store_op == VK_ATTACHMENT_STORE_OP_STORE) {
   9692                     if (cb_data != dev_data->commandBufferMap.end()) {
   9693                         std::function<VkBool32()> function = [=]() {
   9694                             set_memory_valid(dev_data, fb_info.mem, true, fb_info.image);
   9695                             return VK_FALSE;
   9696                         };
   9697                         cb_data->second->validate_functions.push_back(function);
   9698                     }
   9699                 } else if (pRPNode->attachments[i].store_op == VK_ATTACHMENT_STORE_OP_DONT_CARE) {
   9700                     if (cb_data != dev_data->commandBufferMap.end()) {
   9701                         std::function<VkBool32()> function = [=]() {
   9702                             set_memory_valid(dev_data, fb_info.mem, false, fb_info.image);
   9703                             return VK_FALSE;
   9704                         };
   9705                         cb_data->second->validate_functions.push_back(function);
   9706                     }
   9707                 }
   9708             }
   9709         }
   9710     }
   9711 #endif
   9712     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   9713     TransitionFinalSubpassLayouts(commandBuffer, &dev_data->renderPassBeginInfo);
   9714     if (pCB) {
   9715         skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass");
   9716         skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass");
   9717         skipCall |= addCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
   9718         TransitionFinalSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo);
   9719         pCB->activeRenderPass = 0;
   9720         pCB->activeSubpass = 0;
   9721     }
   9722     loader_platform_thread_unlock_mutex(&globalLock);
   9723     if (VK_FALSE == skipCall)
   9724         dev_data->device_dispatch_table->CmdEndRenderPass(commandBuffer);
   9725 }
   9726 
   9727 bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass,
   9728                                  VkRenderPass primaryPass, uint32_t primaryAttach, uint32_t secondaryAttach, const char *msg) {
   9729     return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9730                    DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9731                    "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64
   9732                    " that is not compatible with the current render pass %" PRIx64 "."
   9733                    "Attachment %" PRIu32 " is not compatable with %" PRIu32 ". %s",
   9734                    (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass), primaryAttach, secondaryAttach,
   9735                    msg);
   9736 }
   9737 
   9738 bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass,
   9739                                      uint32_t primaryAttach, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass,
   9740                                      uint32_t secondaryAttach, bool is_multi) {
   9741     bool skip_call = false;
   9742     auto primary_data = dev_data->renderPassMap.find(primaryPass);
   9743     auto secondary_data = dev_data->renderPassMap.find(secondaryPass);
   9744     if (primary_data->second->pCreateInfo->attachmentCount <= primaryAttach) {
   9745         primaryAttach = VK_ATTACHMENT_UNUSED;
   9746     }
   9747     if (secondary_data->second->pCreateInfo->attachmentCount <= secondaryAttach) {
   9748         secondaryAttach = VK_ATTACHMENT_UNUSED;
   9749     }
   9750     if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
   9751         return skip_call;
   9752     }
   9753     if (primaryAttach == VK_ATTACHMENT_UNUSED) {
   9754         skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
   9755                                                  secondaryAttach, "The first is unused while the second is not.");
   9756         return skip_call;
   9757     }
   9758     if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
   9759         skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
   9760                                                  secondaryAttach, "The second is unused while the first is not.");
   9761         return skip_call;
   9762     }
   9763     if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].format !=
   9764         secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].format) {
   9765         skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
   9766                                                  secondaryAttach, "They have different formats.");
   9767     }
   9768     if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].samples !=
   9769         secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].samples) {
   9770         skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
   9771                                                  secondaryAttach, "They have different samples.");
   9772     }
   9773     if (is_multi &&
   9774         primary_data->second->pCreateInfo->pAttachments[primaryAttach].flags !=
   9775             secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].flags) {
   9776         skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
   9777                                                  secondaryAttach, "They have different flags.");
   9778     }
   9779     return skip_call;
   9780 }
   9781 
   9782 bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass,
   9783                                   VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, const int subpass, bool is_multi) {
   9784     bool skip_call = false;
   9785     auto primary_data = dev_data->renderPassMap.find(primaryPass);
   9786     auto secondary_data = dev_data->renderPassMap.find(secondaryPass);
   9787     const VkSubpassDescription &primary_desc = primary_data->second->pCreateInfo->pSubpasses[subpass];
   9788     const VkSubpassDescription &secondary_desc = secondary_data->second->pCreateInfo->pSubpasses[subpass];
   9789     uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
   9790     for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
   9791         uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
   9792         if (i < primary_desc.inputAttachmentCount) {
   9793             primary_input_attach = primary_desc.pInputAttachments[i].attachment;
   9794         }
   9795         if (i < secondary_desc.inputAttachmentCount) {
   9796             secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
   9797         }
   9798         skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_input_attach, secondaryBuffer,
   9799                                                      secondaryPass, secondary_input_attach, is_multi);
   9800     }
   9801     uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
   9802     for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
   9803         uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
   9804         if (i < primary_desc.colorAttachmentCount) {
   9805             primary_color_attach = primary_desc.pColorAttachments[i].attachment;
   9806         }
   9807         if (i < secondary_desc.colorAttachmentCount) {
   9808             secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
   9809         }
   9810         skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_color_attach, secondaryBuffer,
   9811                                                      secondaryPass, secondary_color_attach, is_multi);
   9812         uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
   9813         if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
   9814             primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
   9815         }
   9816         if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
   9817             secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
   9818         }
   9819         skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_resolve_attach, secondaryBuffer,
   9820                                                      secondaryPass, secondary_resolve_attach, is_multi);
   9821     }
   9822     uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
   9823     if (primary_desc.pDepthStencilAttachment) {
   9824         primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
   9825     }
   9826     if (secondary_desc.pDepthStencilAttachment) {
   9827         secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
   9828     }
   9829     skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_depthstencil_attach, secondaryBuffer,
   9830                                                  secondaryPass, secondary_depthstencil_attach, is_multi);
   9831     return skip_call;
   9832 }
   9833 
   9834 bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass,
   9835                                      VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass) {
   9836     bool skip_call = false;
   9837     // Early exit if renderPass objects are identical (and therefore compatible)
   9838     if (primaryPass == secondaryPass)
   9839         return skip_call;
   9840     auto primary_data = dev_data->renderPassMap.find(primaryPass);
   9841     auto secondary_data = dev_data->renderPassMap.find(secondaryPass);
   9842     if (primary_data == dev_data->renderPassMap.end() || primary_data->second == nullptr) {
   9843         skip_call |=
   9844             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9845                     DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9846                     "vkCmdExecuteCommands() called w/ invalid current Cmd Buffer %p which has invalid render pass %" PRIx64 ".",
   9847                     (void *)primaryBuffer, (uint64_t)(primaryPass));
   9848         return skip_call;
   9849     }
   9850     if (secondary_data == dev_data->renderPassMap.end() || secondary_data->second == nullptr) {
   9851         skip_call |=
   9852             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9853                     DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9854                     "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer %p which has invalid render pass %" PRIx64 ".",
   9855                     (void *)secondaryBuffer, (uint64_t)(secondaryPass));
   9856         return skip_call;
   9857     }
   9858     if (primary_data->second->pCreateInfo->subpassCount != secondary_data->second->pCreateInfo->subpassCount) {
   9859         skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9860                              DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9861                              "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64
   9862                              " that is not compatible with the current render pass %" PRIx64 "."
   9863                              "They have a different number of subpasses.",
   9864                              (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass));
   9865         return skip_call;
   9866     }
   9867     bool is_multi = primary_data->second->pCreateInfo->subpassCount > 1;
   9868     for (uint32_t i = 0; i < primary_data->second->pCreateInfo->subpassCount; ++i) {
   9869         skip_call |=
   9870             validateSubpassCompatibility(dev_data, primaryBuffer, primaryPass, secondaryBuffer, secondaryPass, i, is_multi);
   9871     }
   9872     return skip_call;
   9873 }
   9874 
   9875 bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
   9876                          VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
   9877     bool skip_call = false;
   9878     if (!pSubCB->beginInfo.pInheritanceInfo) {
   9879         return skip_call;
   9880     }
   9881     VkFramebuffer primary_fb = pCB->framebuffer;
   9882     VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
   9883     if (secondary_fb != VK_NULL_HANDLE) {
   9884         if (primary_fb != secondary_fb) {
   9885             skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9886                                  DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9887                                  "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a framebuffer %" PRIx64
   9888                                  " that is not compatible with the current framebuffer %" PRIx64 ".",
   9889                                  (void *)secondaryBuffer, (uint64_t)(secondary_fb), (uint64_t)(primary_fb));
   9890         }
   9891         auto fb_data = dev_data->frameBufferMap.find(secondary_fb);
   9892         if (fb_data == dev_data->frameBufferMap.end()) {
   9893             skip_call |=
   9894                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9895                         DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p "
   9896                                                                           "which has invalid framebuffer %" PRIx64 ".",
   9897                         (void *)secondaryBuffer, (uint64_t)(secondary_fb));
   9898             return skip_call;
   9899         }
   9900         skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb_data->second.createInfo.renderPass,
   9901                                                      secondaryBuffer, pSubCB->beginInfo.pInheritanceInfo->renderPass);
   9902     }
   9903     return skip_call;
   9904 }
   9905 
   9906 bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
   9907     bool skipCall = false;
   9908     unordered_set<int> activeTypes;
   9909     for (auto queryObject : pCB->activeQueries) {
   9910         auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
   9911         if (queryPoolData != dev_data->queryPoolMap.end()) {
   9912             if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
   9913                 pSubCB->beginInfo.pInheritanceInfo) {
   9914                 VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
   9915                 if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
   9916                     skipCall |= log_msg(
   9917                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9918                         DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9919                         "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p "
   9920                         "which has invalid active query pool %" PRIx64 ". Pipeline statistics is being queried so the command "
   9921                         "buffer must have all bits set on the queryPool.",
   9922                         reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first));
   9923                 }
   9924             }
   9925             activeTypes.insert(queryPoolData->second.createInfo.queryType);
   9926         }
   9927     }
   9928     for (auto queryObject : pSubCB->startedQueries) {
   9929         auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
   9930         if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
   9931             skipCall |=
   9932                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9933                         DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9934                         "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p "
   9935                         "which has invalid active query pool %" PRIx64 "of type %d but a query of that type has been started on "
   9936                         "secondary Cmd Buffer %p.",
   9937                         reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first),
   9938                         queryPoolData->second.createInfo.queryType, reinterpret_cast<void *>(pSubCB->commandBuffer));
   9939         }
   9940     }
   9941     return skipCall;
   9942 }
   9943 
   9944 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   9945 vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount, const VkCommandBuffer *pCommandBuffers) {
   9946     VkBool32 skipCall = VK_FALSE;
   9947     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   9948     loader_platform_thread_lock_mutex(&globalLock);
   9949     GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
   9950     if (pCB) {
   9951         GLOBAL_CB_NODE *pSubCB = NULL;
   9952         for (uint32_t i = 0; i < commandBuffersCount; i++) {
   9953             pSubCB = getCBNode(dev_data, pCommandBuffers[i]);
   9954             if (!pSubCB) {
   9955                 skipCall |=
   9956                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
   9957                             DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9958                             "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p in element %u of pCommandBuffers array.",
   9959                             (void *)pCommandBuffers[i], i);
   9960             } else if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
   9961                 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   9962                                     __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
   9963                                     "vkCmdExecuteCommands() called w/ Primary Cmd Buffer %p in element %u of pCommandBuffers "
   9964                                     "array. All cmd buffers in pCommandBuffers array must be secondary.",
   9965                                     (void *)pCommandBuffers[i], i);
   9966             } else if (pCB->activeRenderPass) { // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
   9967                 if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
   9968                     skipCall |= log_msg(
   9969                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   9970                         (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
   9971                         "vkCmdExecuteCommands(): Secondary Command Buffer (%p) executed within render pass (%#" PRIxLEAST64
   9972                         ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set.",
   9973                         (void *)pCommandBuffers[i], (uint64_t)pCB->activeRenderPass);
   9974                 } else {
   9975                     // Make sure render pass is compatible with parent command buffer pass if has continue
   9976                     skipCall |= validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass, pCommandBuffers[i],
   9977                                                                 pSubCB->beginInfo.pInheritanceInfo->renderPass);
   9978                     skipCall |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
   9979                 }
   9980                 string errorString = "";
   9981                 if (!verify_renderpass_compatibility(dev_data, pCB->activeRenderPass,
   9982                                                      pSubCB->beginInfo.pInheritanceInfo->renderPass, errorString)) {
   9983                     skipCall |= log_msg(
   9984                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   9985                         (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
   9986                         "vkCmdExecuteCommands(): Secondary Command Buffer (%p) w/ render pass (%#" PRIxLEAST64
   9987                         ") is incompatible w/ primary command buffer (%p) w/ render pass (%#" PRIxLEAST64 ") due to: %s",
   9988                         (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, (void *)commandBuffer,
   9989                         (uint64_t)pCB->activeRenderPass, errorString.c_str());
   9990                 }
   9991                 //  If framebuffer for secondary CB is not NULL, then it must match FB from vkCmdBeginRenderPass()
   9992                 //   that this CB will be executed in AND framebuffer must have been created w/ RP compatible w/ renderpass
   9993                 if (pSubCB->beginInfo.pInheritanceInfo->framebuffer) {
   9994                     if (pSubCB->beginInfo.pInheritanceInfo->framebuffer != pCB->activeRenderPassBeginInfo.framebuffer) {
   9995                         skipCall |= log_msg(
   9996                             dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   9997                             (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE, "DS",
   9998                             "vkCmdExecuteCommands(): Secondary Command Buffer (%p) references framebuffer (%#" PRIxLEAST64
   9999                             ") that does not match framebuffer (%#" PRIxLEAST64 ") in active renderpass (%#" PRIxLEAST64 ").",
   10000                             (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->framebuffer,
   10001                             (uint64_t)pCB->activeRenderPassBeginInfo.framebuffer, (uint64_t)pCB->activeRenderPass);
   10002                     }
   10003                 }
   10004             }
   10005             // TODO(mlentine): Move more logic into this method
   10006             skipCall |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
   10007             skipCall |= validateCommandBufferState(dev_data, pSubCB);
   10008             // Secondary cmdBuffers are considered pending execution starting w/
   10009             // being recorded
   10010             if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
   10011                 if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) {
   10012                     skipCall |= log_msg(
   10013                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   10014                         (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
   10015                         "Attempt to simultaneously execute CB %#" PRIxLEAST64 " w/o VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
   10016                         "set!",
   10017                         (uint64_t)(pCB->commandBuffer));
   10018                 }
   10019                 if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
   10020                     // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
   10021                     skipCall |= log_msg(
   10022                         dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   10023                         (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
   10024                         "vkCmdExecuteCommands(): Secondary Command Buffer (%#" PRIxLEAST64
   10025                         ") does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
   10026                         "(%#" PRIxLEAST64 ") to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
   10027                                           "set, even though it does.",
   10028                         (uint64_t)(pCommandBuffers[i]), (uint64_t)(pCB->commandBuffer));
   10029                     pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
   10030                 }
   10031             }
   10032             if (!pCB->activeQueries.empty() && !dev_data->physDevProperties.features.inheritedQueries) {
   10033                 skipCall |=
   10034                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   10035                             reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
   10036                             "vkCmdExecuteCommands(): Secondary Command Buffer "
   10037                             "(%#" PRIxLEAST64 ") cannot be submitted with a query in "
   10038                             "flight and inherited queries not "
   10039                             "supported on this device.",
   10040                             reinterpret_cast<uint64_t>(pCommandBuffers[i]));
   10041             }
   10042             pSubCB->primaryCommandBuffer = pCB->commandBuffer;
   10043             pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
   10044             dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer);
   10045         }
   10046         skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands");
   10047         skipCall |= addCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()");
   10048     }
   10049     loader_platform_thread_unlock_mutex(&globalLock);
   10050     if (VK_FALSE == skipCall)
   10051         dev_data->device_dispatch_table->CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
   10052 }
   10053 
   10054 VkBool32 ValidateMapImageLayouts(VkDevice device, VkDeviceMemory mem) {
   10055     VkBool32 skip_call = VK_FALSE;
   10056     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10057     auto mem_data = dev_data->memObjMap.find(mem);
   10058     if ((mem_data != dev_data->memObjMap.end()) && (mem_data->second.image != VK_NULL_HANDLE)) {
   10059         std::vector<VkImageLayout> layouts;
   10060         if (FindLayouts(dev_data, mem_data->second.image, layouts)) {
   10061             for (auto layout : layouts) {
   10062                 if (layout != VK_IMAGE_LAYOUT_PREINITIALIZED && layout != VK_IMAGE_LAYOUT_GENERAL) {
   10063                     skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   10064                                          __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot map an image with layout %s. Only "
   10065                                                                                          "GENERAL or PREINITIALIZED are supported.",
   10066                                          string_VkImageLayout(layout));
   10067                 }
   10068             }
   10069         }
   10070     }
   10071     return skip_call;
   10072 }
   10073 
   10074 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   10075 vkMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags, void **ppData) {
   10076     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10077 
   10078     VkBool32 skip_call = VK_FALSE;
   10079     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   10080     loader_platform_thread_lock_mutex(&globalLock);
   10081 #if MTMERGESOURCE
   10082     DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
   10083     if (pMemObj) {
   10084         pMemObj->valid = true;
   10085         if ((memProps.memoryTypes[pMemObj->allocInfo.memoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
   10086             skip_call =
   10087                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
   10088                         (uint64_t)mem, __LINE__, MEMTRACK_INVALID_STATE, "MEM",
   10089                         "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj %#" PRIxLEAST64, (uint64_t)mem);
   10090         }
   10091     }
   10092     skip_call |= validateMemRange(dev_data, mem, offset, size);
   10093     storeMemRanges(dev_data, mem, offset, size);
   10094 #endif
   10095     skip_call |= ValidateMapImageLayouts(device, mem);
   10096     loader_platform_thread_unlock_mutex(&globalLock);
   10097 
   10098     if (VK_FALSE == skip_call) {
   10099         result = dev_data->device_dispatch_table->MapMemory(device, mem, offset, size, flags, ppData);
   10100 #if MTMERGESOURCE
   10101         initializeAndTrackMemory(dev_data, mem, size, ppData);
   10102 #endif
   10103     }
   10104     return result;
   10105 }
   10106 
   10107 #if MTMERGESOURCE
   10108 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory mem) {
   10109     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10110     VkBool32 skipCall = VK_FALSE;
   10111 
   10112     loader_platform_thread_lock_mutex(&globalLock);
   10113     skipCall |= deleteMemRanges(my_data, mem);
   10114     loader_platform_thread_unlock_mutex(&globalLock);
   10115     if (VK_FALSE == skipCall) {
   10116         my_data->device_dispatch_table->UnmapMemory(device, mem);
   10117     }
   10118 }
   10119 
   10120 VkBool32 validateMemoryIsMapped(layer_data *my_data, const char *funcName, uint32_t memRangeCount,
   10121                                 const VkMappedMemoryRange *pMemRanges) {
   10122     VkBool32 skipCall = VK_FALSE;
   10123     for (uint32_t i = 0; i < memRangeCount; ++i) {
   10124         auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory);
   10125         if (mem_element != my_data->memObjMap.end()) {
   10126             if (mem_element->second.memRange.offset > pMemRanges[i].offset) {
   10127                 skipCall |= log_msg(
   10128                     my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
   10129                     (uint64_t)pMemRanges[i].memory, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
   10130                     "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER ") is less than Memory Object's offset "
   10131                     "(" PRINTF_SIZE_T_SPECIFIER ").",
   10132                     funcName, static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(mem_element->second.memRange.offset));
   10133             }
   10134             if ((mem_element->second.memRange.size != VK_WHOLE_SIZE) &&
   10135                 ((mem_element->second.memRange.offset + mem_element->second.memRange.size) <
   10136                  (pMemRanges[i].offset + pMemRanges[i].size))) {
   10137                 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   10138                                     VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
   10139                                     MEMTRACK_INVALID_MAP, "MEM", "%s: Flush/Invalidate upper-bound (" PRINTF_SIZE_T_SPECIFIER
   10140                                                                  ") exceeds the Memory Object's upper-bound "
   10141                                                                  "(" PRINTF_SIZE_T_SPECIFIER ").",
   10142                                     funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
   10143                                     static_cast<size_t>(mem_element->second.memRange.offset + mem_element->second.memRange.size));
   10144             }
   10145         }
   10146     }
   10147     return skipCall;
   10148 }
   10149 
   10150 VkBool32 validateAndCopyNoncoherentMemoryToDriver(layer_data *my_data, uint32_t memRangeCount,
   10151                                                   const VkMappedMemoryRange *pMemRanges) {
   10152     VkBool32 skipCall = VK_FALSE;
   10153     for (uint32_t i = 0; i < memRangeCount; ++i) {
   10154         auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory);
   10155         if (mem_element != my_data->memObjMap.end()) {
   10156             if (mem_element->second.pData) {
   10157                 VkDeviceSize size = mem_element->second.memRange.size;
   10158                 VkDeviceSize half_size = (size / 2);
   10159                 char *data = static_cast<char *>(mem_element->second.pData);
   10160                 for (auto j = 0; j < half_size; ++j) {
   10161                     if (data[j] != NoncoherentMemoryFillValue) {
   10162                         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   10163                                             VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
   10164                                             MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64,
   10165                                             (uint64_t)pMemRanges[i].memory);
   10166                     }
   10167                 }
   10168                 for (auto j = size + half_size; j < 2 * size; ++j) {
   10169                     if (data[j] != NoncoherentMemoryFillValue) {
   10170                         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   10171                                             VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
   10172                                             MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64,
   10173                                             (uint64_t)pMemRanges[i].memory);
   10174                     }
   10175                 }
   10176                 memcpy(mem_element->second.pDriverData, static_cast<void *>(data + (size_t)(half_size)), (size_t)(size));
   10177             }
   10178         }
   10179     }
   10180     return skipCall;
   10181 }
   10182 
   10183 VK_LAYER_EXPORT VkResult VKAPI_CALL
   10184 vkFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) {
   10185     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   10186     VkBool32 skipCall = VK_FALSE;
   10187     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10188 
   10189     loader_platform_thread_lock_mutex(&globalLock);
   10190     skipCall |= validateAndCopyNoncoherentMemoryToDriver(my_data, memRangeCount, pMemRanges);
   10191     skipCall |= validateMemoryIsMapped(my_data, "vkFlushMappedMemoryRanges", memRangeCount, pMemRanges);
   10192     loader_platform_thread_unlock_mutex(&globalLock);
   10193     if (VK_FALSE == skipCall) {
   10194         result = my_data->device_dispatch_table->FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
   10195     }
   10196     return result;
   10197 }
   10198 
   10199 VK_LAYER_EXPORT VkResult VKAPI_CALL
   10200 vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) {
   10201     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   10202     VkBool32 skipCall = VK_FALSE;
   10203     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10204 
   10205     loader_platform_thread_lock_mutex(&globalLock);
   10206     skipCall |= validateMemoryIsMapped(my_data, "vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges);
   10207     loader_platform_thread_unlock_mutex(&globalLock);
   10208     if (VK_FALSE == skipCall) {
   10209         result = my_data->device_dispatch_table->InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
   10210     }
   10211     return result;
   10212 }
   10213 #endif
   10214 
   10215 VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
   10216     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10217     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   10218     VkBool32 skipCall = VK_FALSE;
   10219 #if MTMERGESOURCE
   10220     loader_platform_thread_lock_mutex(&globalLock);
   10221     // Track objects tied to memory
   10222     uint64_t image_handle = (uint64_t)(image);
   10223     skipCall =
   10224         set_mem_binding(dev_data, device, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory");
   10225     add_object_binding_info(dev_data, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, mem);
   10226     {
   10227         VkMemoryRequirements memRequirements;
   10228         vkGetImageMemoryRequirements(device, image, &memRequirements);
   10229         skipCall |= validate_buffer_image_aliasing(dev_data, image_handle, mem, memoryOffset, memRequirements,
   10230                                                    dev_data->memObjMap[mem].imageRanges, dev_data->memObjMap[mem].bufferRanges,
   10231                                                    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
   10232     }
   10233     print_mem_list(dev_data, device);
   10234     loader_platform_thread_unlock_mutex(&globalLock);
   10235 #endif
   10236     if (VK_FALSE == skipCall) {
   10237         result = dev_data->device_dispatch_table->BindImageMemory(device, image, mem, memoryOffset);
   10238         VkMemoryRequirements memRequirements;
   10239         dev_data->device_dispatch_table->GetImageMemoryRequirements(device, image, &memRequirements);
   10240         loader_platform_thread_lock_mutex(&globalLock);
   10241         dev_data->memObjMap[mem].image = image;
   10242         dev_data->imageMap[image].mem = mem;
   10243         dev_data->imageMap[image].memOffset = memoryOffset;
   10244         dev_data->imageMap[image].memSize = memRequirements.size;
   10245         loader_platform_thread_unlock_mutex(&globalLock);
   10246     }
   10247     return result;
   10248 }
   10249 
   10250 VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(VkDevice device, VkEvent event) {
   10251     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10252     loader_platform_thread_lock_mutex(&globalLock);
   10253     dev_data->eventMap[event].needsSignaled = false;
   10254     dev_data->eventMap[event].stageMask = VK_PIPELINE_STAGE_HOST_BIT;
   10255     loader_platform_thread_unlock_mutex(&globalLock);
   10256     VkResult result = dev_data->device_dispatch_table->SetEvent(device, event);
   10257     return result;
   10258 }
   10259 
   10260 VKAPI_ATTR VkResult VKAPI_CALL
   10261 vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) {
   10262     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
   10263     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   10264     VkBool32 skip_call = VK_FALSE;
   10265 #if MTMERGESOURCE
   10266     //MTMTODO : Merge this code with the checks below
   10267     loader_platform_thread_lock_mutex(&globalLock);
   10268 
   10269     for (uint32_t i = 0; i < bindInfoCount; i++) {
   10270         const VkBindSparseInfo *bindInfo = &pBindInfo[i];
   10271         // Track objects tied to memory
   10272         for (uint32_t j = 0; j < bindInfo->bufferBindCount; j++) {
   10273             for (uint32_t k = 0; k < bindInfo->pBufferBinds[j].bindCount; k++) {
   10274                 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pBufferBinds[j].pBinds[k].memory,
   10275                                            (uint64_t)bindInfo->pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   10276                                            "vkQueueBindSparse"))
   10277                     skip_call = VK_TRUE;
   10278             }
   10279         }
   10280         for (uint32_t j = 0; j < bindInfo->imageOpaqueBindCount; j++) {
   10281             for (uint32_t k = 0; k < bindInfo->pImageOpaqueBinds[j].bindCount; k++) {
   10282                 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pImageOpaqueBinds[j].pBinds[k].memory,
   10283                                            (uint64_t)bindInfo->pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   10284                                            "vkQueueBindSparse"))
   10285                     skip_call = VK_TRUE;
   10286             }
   10287         }
   10288         for (uint32_t j = 0; j < bindInfo->imageBindCount; j++) {
   10289             for (uint32_t k = 0; k < bindInfo->pImageBinds[j].bindCount; k++) {
   10290                 if (set_sparse_mem_binding(dev_data, queue, bindInfo->pImageBinds[j].pBinds[k].memory,
   10291                                            (uint64_t)bindInfo->pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   10292                                            "vkQueueBindSparse"))
   10293                     skip_call = VK_TRUE;
   10294             }
   10295         }
   10296         // Validate semaphore state
   10297         for (uint32_t i = 0; i < bindInfo->waitSemaphoreCount; i++) {
   10298             VkSemaphore sem = bindInfo->pWaitSemaphores[i];
   10299 
   10300             if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) {
   10301                 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_SIGNALLED) {
   10302                     skip_call =
   10303                         log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
   10304                                 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE",
   10305                                 "vkQueueBindSparse: Semaphore must be in signaled state before passing to pWaitSemaphores");
   10306                 }
   10307                 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_WAIT;
   10308             }
   10309         }
   10310         for (uint32_t i = 0; i < bindInfo->signalSemaphoreCount; i++) {
   10311             VkSemaphore sem = bindInfo->pSignalSemaphores[i];
   10312 
   10313             if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) {
   10314                 if (dev_data->semaphoreMap[sem].state != MEMTRACK_SEMAPHORE_STATE_UNSET) {
   10315                     skip_call =
   10316                         log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
   10317                                 (uint64_t)sem, __LINE__, MEMTRACK_NONE, "SEMAPHORE",
   10318                                 "vkQueueBindSparse: Semaphore must not be currently signaled or in a wait state");
   10319                 }
   10320                 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED;
   10321             }
   10322         }
   10323     }
   10324 
   10325     print_mem_list(dev_data, queue);
   10326     loader_platform_thread_unlock_mutex(&globalLock);
   10327 #endif
   10328     loader_platform_thread_lock_mutex(&globalLock);
   10329     for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
   10330         const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
   10331         for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
   10332             if (dev_data->semaphoreMap[bindInfo.pWaitSemaphores[i]].signaled) {
   10333                 dev_data->semaphoreMap[bindInfo.pWaitSemaphores[i]].signaled = 0;
   10334             } else {
   10335                 skip_call |=
   10336                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   10337                             __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
   10338                             "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.",
   10339                             (uint64_t)(queue), (uint64_t)(bindInfo.pWaitSemaphores[i]));
   10340             }
   10341         }
   10342         for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
   10343             dev_data->semaphoreMap[bindInfo.pSignalSemaphores[i]].signaled = 1;
   10344         }
   10345     }
   10346     loader_platform_thread_unlock_mutex(&globalLock);
   10347 
   10348     if (VK_FALSE == skip_call)
   10349         return dev_data->device_dispatch_table->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
   10350 #if MTMERGESOURCE
   10351     // Update semaphore state
   10352     loader_platform_thread_lock_mutex(&globalLock);
   10353     for (uint32_t bind_info_idx = 0; bind_info_idx < bindInfoCount; bind_info_idx++) {
   10354         const VkBindSparseInfo *bindInfo = &pBindInfo[bind_info_idx];
   10355         for (uint32_t i = 0; i < bindInfo->waitSemaphoreCount; i++) {
   10356             VkSemaphore sem = bindInfo->pWaitSemaphores[i];
   10357 
   10358             if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) {
   10359                 dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET;
   10360             }
   10361         }
   10362     }
   10363     loader_platform_thread_unlock_mutex(&globalLock);
   10364 #endif
   10365 
   10366     return result;
   10367 }
   10368 
   10369 VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
   10370                                                  const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
   10371     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10372     VkResult result = dev_data->device_dispatch_table->CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
   10373     if (result == VK_SUCCESS) {
   10374         loader_platform_thread_lock_mutex(&globalLock);
   10375         SEMAPHORE_NODE* sNode = &dev_data->semaphoreMap[*pSemaphore];
   10376         sNode->signaled = 0;
   10377         sNode->queue = VK_NULL_HANDLE;
   10378         sNode->in_use.store(0);
   10379         sNode->state = MEMTRACK_SEMAPHORE_STATE_UNSET;
   10380         loader_platform_thread_unlock_mutex(&globalLock);
   10381     }
   10382     return result;
   10383 }
   10384 
   10385 VKAPI_ATTR VkResult VKAPI_CALL
   10386 vkCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
   10387     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10388     VkResult result = dev_data->device_dispatch_table->CreateEvent(device, pCreateInfo, pAllocator, pEvent);
   10389     if (result == VK_SUCCESS) {
   10390         loader_platform_thread_lock_mutex(&globalLock);
   10391         dev_data->eventMap[*pEvent].needsSignaled = false;
   10392         dev_data->eventMap[*pEvent].in_use.store(0);
   10393         dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
   10394         loader_platform_thread_unlock_mutex(&globalLock);
   10395     }
   10396     return result;
   10397 }
   10398 
   10399 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
   10400                                                                     const VkAllocationCallbacks *pAllocator,
   10401                                                                     VkSwapchainKHR *pSwapchain) {
   10402     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10403     VkResult result = dev_data->device_dispatch_table->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
   10404 
   10405     if (VK_SUCCESS == result) {
   10406         SWAPCHAIN_NODE *psc_node = new SWAPCHAIN_NODE(pCreateInfo);
   10407         loader_platform_thread_lock_mutex(&globalLock);
   10408         dev_data->device_extensions.swapchainMap[*pSwapchain] = psc_node;
   10409         loader_platform_thread_unlock_mutex(&globalLock);
   10410     }
   10411 
   10412     return result;
   10413 }
   10414 
   10415 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   10416 vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
   10417     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10418     bool skipCall = false;
   10419 
   10420     loader_platform_thread_lock_mutex(&globalLock);
   10421     auto swapchain_data = dev_data->device_extensions.swapchainMap.find(swapchain);
   10422     if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) {
   10423         if (swapchain_data->second->images.size() > 0) {
   10424             for (auto swapchain_image : swapchain_data->second->images) {
   10425                 auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
   10426                 if (image_sub != dev_data->imageSubresourceMap.end()) {
   10427                     for (auto imgsubpair : image_sub->second) {
   10428                         auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
   10429                         if (image_item != dev_data->imageLayoutMap.end()) {
   10430                             dev_data->imageLayoutMap.erase(image_item);
   10431                         }
   10432                     }
   10433                     dev_data->imageSubresourceMap.erase(image_sub);
   10434                 }
   10435 #if MTMERGESOURCE
   10436                 skipCall = clear_object_binding(dev_data, device, (uint64_t)swapchain_image,
   10437                                                 VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT);
   10438                 dev_data->imageBindingMap.erase((uint64_t)swapchain_image);
   10439 #endif
   10440             }
   10441         }
   10442         delete swapchain_data->second;
   10443         dev_data->device_extensions.swapchainMap.erase(swapchain);
   10444     }
   10445     loader_platform_thread_unlock_mutex(&globalLock);
   10446     if (!skipCall)
   10447         dev_data->device_dispatch_table->DestroySwapchainKHR(device, swapchain, pAllocator);
   10448 }
   10449 
   10450 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   10451 vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount, VkImage *pSwapchainImages) {
   10452     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10453     VkResult result = dev_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
   10454 
   10455     if (result == VK_SUCCESS && pSwapchainImages != NULL) {
   10456         // This should never happen and is checked by param checker.
   10457         if (!pCount)
   10458             return result;
   10459         loader_platform_thread_lock_mutex(&globalLock);
   10460         const size_t count = *pCount;
   10461         auto swapchain_node = dev_data->device_extensions.swapchainMap[swapchain];
   10462         if (!swapchain_node->images.empty()) {
   10463             // TODO : Not sure I like the memcmp here, but it works
   10464             const bool mismatch = (swapchain_node->images.size() != count ||
   10465                                    memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count));
   10466             if (mismatch) {
   10467                 // TODO: Verify against Valid Usage section of extension
   10468                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
   10469                         (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN",
   10470                         "vkGetSwapchainInfoKHR(%" PRIu64
   10471                         ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data",
   10472                         (uint64_t)(swapchain));
   10473             }
   10474         }
   10475         for (uint32_t i = 0; i < *pCount; ++i) {
   10476             IMAGE_LAYOUT_NODE image_layout_node;
   10477             image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
   10478             image_layout_node.format = swapchain_node->createInfo.imageFormat;
   10479             dev_data->imageMap[pSwapchainImages[i]].createInfo.mipLevels = 1;
   10480             dev_data->imageMap[pSwapchainImages[i]].createInfo.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
   10481             swapchain_node->images.push_back(pSwapchainImages[i]);
   10482             ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
   10483             dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
   10484             dev_data->imageLayoutMap[subpair] = image_layout_node;
   10485             dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain;
   10486         }
   10487         if (!swapchain_node->images.empty()) {
   10488             for (auto image : swapchain_node->images) {
   10489                 // Add image object binding, then insert the new Mem Object and then bind it to created image
   10490 #if MTMERGESOURCE
   10491                 add_object_create_info(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
   10492                                        &swapchain_node->createInfo);
   10493 #endif
   10494             }
   10495         }
   10496         loader_platform_thread_unlock_mutex(&globalLock);
   10497     }
   10498     return result;
   10499 }
   10500 
   10501 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
   10502     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
   10503     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   10504     bool skip_call = false;
   10505 
   10506     if (pPresentInfo) {
   10507         loader_platform_thread_lock_mutex(&globalLock);
   10508         for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
   10509             if (dev_data->semaphoreMap[pPresentInfo->pWaitSemaphores[i]].signaled) {
   10510                 dev_data->semaphoreMap[pPresentInfo->pWaitSemaphores[i]].signaled = 0;
   10511             } else {
   10512                 skip_call |=
   10513                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   10514                             __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
   10515                             "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.",
   10516                             (uint64_t)(queue), (uint64_t)(pPresentInfo->pWaitSemaphores[i]));
   10517             }
   10518         }
   10519         VkDeviceMemory mem;
   10520         for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
   10521             auto swapchain_data = dev_data->device_extensions.swapchainMap.find(pPresentInfo->pSwapchains[i]);
   10522             if (swapchain_data != dev_data->device_extensions.swapchainMap.end() &&
   10523                 pPresentInfo->pImageIndices[i] < swapchain_data->second->images.size()) {
   10524                 VkImage image = swapchain_data->second->images[pPresentInfo->pImageIndices[i]];
   10525 #if MTMERGESOURCE
   10526                 skip_call |=
   10527                     get_mem_binding_from_object(dev_data, queue, (uint64_t)(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
   10528                 skip_call |= validate_memory_is_valid(dev_data, mem, "vkQueuePresentKHR()", image);
   10529 #endif
   10530                 vector<VkImageLayout> layouts;
   10531                 if (FindLayouts(dev_data, image, layouts)) {
   10532                     for (auto layout : layouts) {
   10533                         if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
   10534                             skip_call |=
   10535                                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
   10536                                         reinterpret_cast<uint64_t &>(queue), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
   10537                                         "Images passed to present must be in layout "
   10538                                         "PRESENT_SOURCE_KHR but is in %s",
   10539                                         string_VkImageLayout(layout));
   10540                         }
   10541                     }
   10542                 }
   10543             }
   10544         }
   10545         loader_platform_thread_unlock_mutex(&globalLock);
   10546     }
   10547 
   10548     if (!skip_call)
   10549         result = dev_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo);
   10550 #if MTMERGESOURCE
   10551     loader_platform_thread_lock_mutex(&globalLock);
   10552     for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; i++) {
   10553         VkSemaphore sem = pPresentInfo->pWaitSemaphores[i];
   10554         if (dev_data->semaphoreMap.find(sem) != dev_data->semaphoreMap.end()) {
   10555             dev_data->semaphoreMap[sem].state = MEMTRACK_SEMAPHORE_STATE_UNSET;
   10556         }
   10557     }
   10558     loader_platform_thread_unlock_mutex(&globalLock);
   10559 #endif
   10560     return result;
   10561 }
   10562 
   10563 VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
   10564                                                      VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
   10565     layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   10566     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
   10567     bool skipCall = false;
   10568 #if MTMERGESOURCE
   10569     loader_platform_thread_lock_mutex(&globalLock);
   10570     if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
   10571         if (dev_data->semaphoreMap[semaphore].state != MEMTRACK_SEMAPHORE_STATE_UNSET) {
   10572             skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
   10573                                (uint64_t)semaphore, __LINE__, MEMTRACK_NONE, "SEMAPHORE",
   10574                                "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state");
   10575         }
   10576         dev_data->semaphoreMap[semaphore].state = MEMTRACK_SEMAPHORE_STATE_SIGNALLED;
   10577     }
   10578     auto fence_data = dev_data->fenceMap.find(fence);
   10579     if (fence_data != dev_data->fenceMap.end()) {
   10580         fence_data->second.swapchain = swapchain;
   10581     }
   10582     loader_platform_thread_unlock_mutex(&globalLock);
   10583 #endif
   10584     if (!skipCall) {
   10585         result =
   10586             dev_data->device_dispatch_table->AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
   10587     }
   10588     loader_platform_thread_lock_mutex(&globalLock);
   10589     // FIXME/TODO: Need to add some thing code the "fence" parameter
   10590     dev_data->semaphoreMap[semaphore].signaled = 1;
   10591     loader_platform_thread_unlock_mutex(&globalLock);
   10592     return result;
   10593 }
   10594 
   10595 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   10596 vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
   10597                                const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
   10598     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   10599     VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
   10600     VkResult res = pTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
   10601     if (VK_SUCCESS == res) {
   10602         loader_platform_thread_lock_mutex(&globalLock);
   10603         res = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback);
   10604         loader_platform_thread_unlock_mutex(&globalLock);
   10605     }
   10606     return res;
   10607 }
   10608 
   10609 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance,
   10610                                                                            VkDebugReportCallbackEXT msgCallback,
   10611                                                                            const VkAllocationCallbacks *pAllocator) {
   10612     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   10613     VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
   10614     pTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
   10615     loader_platform_thread_lock_mutex(&globalLock);
   10616     layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator);
   10617     loader_platform_thread_unlock_mutex(&globalLock);
   10618 }
   10619 
   10620 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
   10621 vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
   10622                         size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
   10623     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   10624     my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix,
   10625                                                             pMsg);
   10626 }
   10627 
   10628 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
   10629     if (!strcmp(funcName, "vkGetDeviceProcAddr"))
   10630         return (PFN_vkVoidFunction)vkGetDeviceProcAddr;
   10631     if (!strcmp(funcName, "vkDestroyDevice"))
   10632         return (PFN_vkVoidFunction)vkDestroyDevice;
   10633     if (!strcmp(funcName, "vkQueueSubmit"))
   10634         return (PFN_vkVoidFunction)vkQueueSubmit;
   10635     if (!strcmp(funcName, "vkWaitForFences"))
   10636         return (PFN_vkVoidFunction)vkWaitForFences;
   10637     if (!strcmp(funcName, "vkGetFenceStatus"))
   10638         return (PFN_vkVoidFunction)vkGetFenceStatus;
   10639     if (!strcmp(funcName, "vkQueueWaitIdle"))
   10640         return (PFN_vkVoidFunction)vkQueueWaitIdle;
   10641     if (!strcmp(funcName, "vkDeviceWaitIdle"))
   10642         return (PFN_vkVoidFunction)vkDeviceWaitIdle;
   10643     if (!strcmp(funcName, "vkGetDeviceQueue"))
   10644         return (PFN_vkVoidFunction)vkGetDeviceQueue;
   10645     if (!strcmp(funcName, "vkDestroyInstance"))
   10646         return (PFN_vkVoidFunction)vkDestroyInstance;
   10647     if (!strcmp(funcName, "vkDestroyDevice"))
   10648         return (PFN_vkVoidFunction)vkDestroyDevice;
   10649     if (!strcmp(funcName, "vkDestroyFence"))
   10650         return (PFN_vkVoidFunction)vkDestroyFence;
   10651     if (!strcmp(funcName, "vkResetFences"))
   10652         return (PFN_vkVoidFunction)vkResetFences;
   10653     if (!strcmp(funcName, "vkDestroySemaphore"))
   10654         return (PFN_vkVoidFunction)vkDestroySemaphore;
   10655     if (!strcmp(funcName, "vkDestroyEvent"))
   10656         return (PFN_vkVoidFunction)vkDestroyEvent;
   10657     if (!strcmp(funcName, "vkDestroyQueryPool"))
   10658         return (PFN_vkVoidFunction)vkDestroyQueryPool;
   10659     if (!strcmp(funcName, "vkDestroyBuffer"))
   10660         return (PFN_vkVoidFunction)vkDestroyBuffer;
   10661     if (!strcmp(funcName, "vkDestroyBufferView"))
   10662         return (PFN_vkVoidFunction)vkDestroyBufferView;
   10663     if (!strcmp(funcName, "vkDestroyImage"))
   10664         return (PFN_vkVoidFunction)vkDestroyImage;
   10665     if (!strcmp(funcName, "vkDestroyImageView"))
   10666         return (PFN_vkVoidFunction)vkDestroyImageView;
   10667     if (!strcmp(funcName, "vkDestroyShaderModule"))
   10668         return (PFN_vkVoidFunction)vkDestroyShaderModule;
   10669     if (!strcmp(funcName, "vkDestroyPipeline"))
   10670         return (PFN_vkVoidFunction)vkDestroyPipeline;
   10671     if (!strcmp(funcName, "vkDestroyPipelineLayout"))
   10672         return (PFN_vkVoidFunction)vkDestroyPipelineLayout;
   10673     if (!strcmp(funcName, "vkDestroySampler"))
   10674         return (PFN_vkVoidFunction)vkDestroySampler;
   10675     if (!strcmp(funcName, "vkDestroyDescriptorSetLayout"))
   10676         return (PFN_vkVoidFunction)vkDestroyDescriptorSetLayout;
   10677     if (!strcmp(funcName, "vkDestroyDescriptorPool"))
   10678         return (PFN_vkVoidFunction)vkDestroyDescriptorPool;
   10679     if (!strcmp(funcName, "vkDestroyFramebuffer"))
   10680         return (PFN_vkVoidFunction)vkDestroyFramebuffer;
   10681     if (!strcmp(funcName, "vkDestroyRenderPass"))
   10682         return (PFN_vkVoidFunction)vkDestroyRenderPass;
   10683     if (!strcmp(funcName, "vkCreateBuffer"))
   10684         return (PFN_vkVoidFunction)vkCreateBuffer;
   10685     if (!strcmp(funcName, "vkCreateBufferView"))
   10686         return (PFN_vkVoidFunction)vkCreateBufferView;
   10687     if (!strcmp(funcName, "vkCreateImage"))
   10688         return (PFN_vkVoidFunction)vkCreateImage;
   10689     if (!strcmp(funcName, "vkCreateImageView"))
   10690         return (PFN_vkVoidFunction)vkCreateImageView;
   10691     if (!strcmp(funcName, "vkCreateFence"))
   10692         return (PFN_vkVoidFunction)vkCreateFence;
   10693     if (!strcmp(funcName, "CreatePipelineCache"))
   10694         return (PFN_vkVoidFunction)vkCreatePipelineCache;
   10695     if (!strcmp(funcName, "DestroyPipelineCache"))
   10696         return (PFN_vkVoidFunction)vkDestroyPipelineCache;
   10697     if (!strcmp(funcName, "GetPipelineCacheData"))
   10698         return (PFN_vkVoidFunction)vkGetPipelineCacheData;
   10699     if (!strcmp(funcName, "MergePipelineCaches"))
   10700         return (PFN_vkVoidFunction)vkMergePipelineCaches;
   10701     if (!strcmp(funcName, "vkCreateGraphicsPipelines"))
   10702         return (PFN_vkVoidFunction)vkCreateGraphicsPipelines;
   10703     if (!strcmp(funcName, "vkCreateComputePipelines"))
   10704         return (PFN_vkVoidFunction)vkCreateComputePipelines;
   10705     if (!strcmp(funcName, "vkCreateSampler"))
   10706         return (PFN_vkVoidFunction)vkCreateSampler;
   10707     if (!strcmp(funcName, "vkCreateDescriptorSetLayout"))
   10708         return (PFN_vkVoidFunction)vkCreateDescriptorSetLayout;
   10709     if (!strcmp(funcName, "vkCreatePipelineLayout"))
   10710         return (PFN_vkVoidFunction)vkCreatePipelineLayout;
   10711     if (!strcmp(funcName, "vkCreateDescriptorPool"))
   10712         return (PFN_vkVoidFunction)vkCreateDescriptorPool;
   10713     if (!strcmp(funcName, "vkResetDescriptorPool"))
   10714         return (PFN_vkVoidFunction)vkResetDescriptorPool;
   10715     if (!strcmp(funcName, "vkAllocateDescriptorSets"))
   10716         return (PFN_vkVoidFunction)vkAllocateDescriptorSets;
   10717     if (!strcmp(funcName, "vkFreeDescriptorSets"))
   10718         return (PFN_vkVoidFunction)vkFreeDescriptorSets;
   10719     if (!strcmp(funcName, "vkUpdateDescriptorSets"))
   10720         return (PFN_vkVoidFunction)vkUpdateDescriptorSets;
   10721     if (!strcmp(funcName, "vkCreateCommandPool"))
   10722         return (PFN_vkVoidFunction)vkCreateCommandPool;
   10723     if (!strcmp(funcName, "vkDestroyCommandPool"))
   10724         return (PFN_vkVoidFunction)vkDestroyCommandPool;
   10725     if (!strcmp(funcName, "vkResetCommandPool"))
   10726         return (PFN_vkVoidFunction)vkResetCommandPool;
   10727     if (!strcmp(funcName, "vkCreateQueryPool"))
   10728         return (PFN_vkVoidFunction)vkCreateQueryPool;
   10729     if (!strcmp(funcName, "vkAllocateCommandBuffers"))
   10730         return (PFN_vkVoidFunction)vkAllocateCommandBuffers;
   10731     if (!strcmp(funcName, "vkFreeCommandBuffers"))
   10732         return (PFN_vkVoidFunction)vkFreeCommandBuffers;
   10733     if (!strcmp(funcName, "vkBeginCommandBuffer"))
   10734         return (PFN_vkVoidFunction)vkBeginCommandBuffer;
   10735     if (!strcmp(funcName, "vkEndCommandBuffer"))
   10736         return (PFN_vkVoidFunction)vkEndCommandBuffer;
   10737     if (!strcmp(funcName, "vkResetCommandBuffer"))
   10738         return (PFN_vkVoidFunction)vkResetCommandBuffer;
   10739     if (!strcmp(funcName, "vkCmdBindPipeline"))
   10740         return (PFN_vkVoidFunction)vkCmdBindPipeline;
   10741     if (!strcmp(funcName, "vkCmdSetViewport"))
   10742         return (PFN_vkVoidFunction)vkCmdSetViewport;
   10743     if (!strcmp(funcName, "vkCmdSetScissor"))
   10744         return (PFN_vkVoidFunction)vkCmdSetScissor;
   10745     if (!strcmp(funcName, "vkCmdSetLineWidth"))
   10746         return (PFN_vkVoidFunction)vkCmdSetLineWidth;
   10747     if (!strcmp(funcName, "vkCmdSetDepthBias"))
   10748         return (PFN_vkVoidFunction)vkCmdSetDepthBias;
   10749     if (!strcmp(funcName, "vkCmdSetBlendConstants"))
   10750         return (PFN_vkVoidFunction)vkCmdSetBlendConstants;
   10751     if (!strcmp(funcName, "vkCmdSetDepthBounds"))
   10752         return (PFN_vkVoidFunction)vkCmdSetDepthBounds;
   10753     if (!strcmp(funcName, "vkCmdSetStencilCompareMask"))
   10754         return (PFN_vkVoidFunction)vkCmdSetStencilCompareMask;
   10755     if (!strcmp(funcName, "vkCmdSetStencilWriteMask"))
   10756         return (PFN_vkVoidFunction)vkCmdSetStencilWriteMask;
   10757     if (!strcmp(funcName, "vkCmdSetStencilReference"))
   10758         return (PFN_vkVoidFunction)vkCmdSetStencilReference;
   10759     if (!strcmp(funcName, "vkCmdBindDescriptorSets"))
   10760         return (PFN_vkVoidFunction)vkCmdBindDescriptorSets;
   10761     if (!strcmp(funcName, "vkCmdBindVertexBuffers"))
   10762         return (PFN_vkVoidFunction)vkCmdBindVertexBuffers;
   10763     if (!strcmp(funcName, "vkCmdBindIndexBuffer"))
   10764         return (PFN_vkVoidFunction)vkCmdBindIndexBuffer;
   10765     if (!strcmp(funcName, "vkCmdDraw"))
   10766         return (PFN_vkVoidFunction)vkCmdDraw;
   10767     if (!strcmp(funcName, "vkCmdDrawIndexed"))
   10768         return (PFN_vkVoidFunction)vkCmdDrawIndexed;
   10769     if (!strcmp(funcName, "vkCmdDrawIndirect"))
   10770         return (PFN_vkVoidFunction)vkCmdDrawIndirect;
   10771     if (!strcmp(funcName, "vkCmdDrawIndexedIndirect"))
   10772         return (PFN_vkVoidFunction)vkCmdDrawIndexedIndirect;
   10773     if (!strcmp(funcName, "vkCmdDispatch"))
   10774         return (PFN_vkVoidFunction)vkCmdDispatch;
   10775     if (!strcmp(funcName, "vkCmdDispatchIndirect"))
   10776         return (PFN_vkVoidFunction)vkCmdDispatchIndirect;
   10777     if (!strcmp(funcName, "vkCmdCopyBuffer"))
   10778         return (PFN_vkVoidFunction)vkCmdCopyBuffer;
   10779     if (!strcmp(funcName, "vkCmdCopyImage"))
   10780         return (PFN_vkVoidFunction)vkCmdCopyImage;
   10781     if (!strcmp(funcName, "vkCmdBlitImage"))
   10782         return (PFN_vkVoidFunction)vkCmdBlitImage;
   10783     if (!strcmp(funcName, "vkCmdCopyBufferToImage"))
   10784         return (PFN_vkVoidFunction)vkCmdCopyBufferToImage;
   10785     if (!strcmp(funcName, "vkCmdCopyImageToBuffer"))
   10786         return (PFN_vkVoidFunction)vkCmdCopyImageToBuffer;
   10787     if (!strcmp(funcName, "vkCmdUpdateBuffer"))
   10788         return (PFN_vkVoidFunction)vkCmdUpdateBuffer;
   10789     if (!strcmp(funcName, "vkCmdFillBuffer"))
   10790         return (PFN_vkVoidFunction)vkCmdFillBuffer;
   10791     if (!strcmp(funcName, "vkCmdClearColorImage"))
   10792         return (PFN_vkVoidFunction)vkCmdClearColorImage;
   10793     if (!strcmp(funcName, "vkCmdClearDepthStencilImage"))
   10794         return (PFN_vkVoidFunction)vkCmdClearDepthStencilImage;
   10795     if (!strcmp(funcName, "vkCmdClearAttachments"))
   10796         return (PFN_vkVoidFunction)vkCmdClearAttachments;
   10797     if (!strcmp(funcName, "vkCmdResolveImage"))
   10798         return (PFN_vkVoidFunction)vkCmdResolveImage;
   10799     if (!strcmp(funcName, "vkCmdSetEvent"))
   10800         return (PFN_vkVoidFunction)vkCmdSetEvent;
   10801     if (!strcmp(funcName, "vkCmdResetEvent"))
   10802         return (PFN_vkVoidFunction)vkCmdResetEvent;
   10803     if (!strcmp(funcName, "vkCmdWaitEvents"))
   10804         return (PFN_vkVoidFunction)vkCmdWaitEvents;
   10805     if (!strcmp(funcName, "vkCmdPipelineBarrier"))
   10806         return (PFN_vkVoidFunction)vkCmdPipelineBarrier;
   10807     if (!strcmp(funcName, "vkCmdBeginQuery"))
   10808         return (PFN_vkVoidFunction)vkCmdBeginQuery;
   10809     if (!strcmp(funcName, "vkCmdEndQuery"))
   10810         return (PFN_vkVoidFunction)vkCmdEndQuery;
   10811     if (!strcmp(funcName, "vkCmdResetQueryPool"))
   10812         return (PFN_vkVoidFunction)vkCmdResetQueryPool;
   10813     if (!strcmp(funcName, "vkCmdCopyQueryPoolResults"))
   10814         return (PFN_vkVoidFunction)vkCmdCopyQueryPoolResults;
   10815     if (!strcmp(funcName, "vkCmdPushConstants"))
   10816         return (PFN_vkVoidFunction)vkCmdPushConstants;
   10817     if (!strcmp(funcName, "vkCmdWriteTimestamp"))
   10818         return (PFN_vkVoidFunction)vkCmdWriteTimestamp;
   10819     if (!strcmp(funcName, "vkCreateFramebuffer"))
   10820         return (PFN_vkVoidFunction)vkCreateFramebuffer;
   10821     if (!strcmp(funcName, "vkCreateShaderModule"))
   10822         return (PFN_vkVoidFunction)vkCreateShaderModule;
   10823     if (!strcmp(funcName, "vkCreateRenderPass"))
   10824         return (PFN_vkVoidFunction)vkCreateRenderPass;
   10825     if (!strcmp(funcName, "vkCmdBeginRenderPass"))
   10826         return (PFN_vkVoidFunction)vkCmdBeginRenderPass;
   10827     if (!strcmp(funcName, "vkCmdNextSubpass"))
   10828         return (PFN_vkVoidFunction)vkCmdNextSubpass;
   10829     if (!strcmp(funcName, "vkCmdEndRenderPass"))
   10830         return (PFN_vkVoidFunction)vkCmdEndRenderPass;
   10831     if (!strcmp(funcName, "vkCmdExecuteCommands"))
   10832         return (PFN_vkVoidFunction)vkCmdExecuteCommands;
   10833     if (!strcmp(funcName, "vkSetEvent"))
   10834         return (PFN_vkVoidFunction)vkSetEvent;
   10835     if (!strcmp(funcName, "vkMapMemory"))
   10836         return (PFN_vkVoidFunction)vkMapMemory;
   10837 #if MTMERGESOURCE
   10838     if (!strcmp(funcName, "vkUnmapMemory"))
   10839         return (PFN_vkVoidFunction)vkUnmapMemory;
   10840     if (!strcmp(funcName, "vkAllocateMemory"))
   10841         return (PFN_vkVoidFunction)vkAllocateMemory;
   10842     if (!strcmp(funcName, "vkFreeMemory"))
   10843         return (PFN_vkVoidFunction)vkFreeMemory;
   10844     if (!strcmp(funcName, "vkFlushMappedMemoryRanges"))
   10845         return (PFN_vkVoidFunction)vkFlushMappedMemoryRanges;
   10846     if (!strcmp(funcName, "vkInvalidateMappedMemoryRanges"))
   10847         return (PFN_vkVoidFunction)vkInvalidateMappedMemoryRanges;
   10848     if (!strcmp(funcName, "vkBindBufferMemory"))
   10849         return (PFN_vkVoidFunction)vkBindBufferMemory;
   10850     if (!strcmp(funcName, "vkGetBufferMemoryRequirements"))
   10851         return (PFN_vkVoidFunction)vkGetBufferMemoryRequirements;
   10852     if (!strcmp(funcName, "vkGetImageMemoryRequirements"))
   10853         return (PFN_vkVoidFunction)vkGetImageMemoryRequirements;
   10854 #endif
   10855     if (!strcmp(funcName, "vkGetQueryPoolResults"))
   10856         return (PFN_vkVoidFunction)vkGetQueryPoolResults;
   10857     if (!strcmp(funcName, "vkBindImageMemory"))
   10858         return (PFN_vkVoidFunction)vkBindImageMemory;
   10859     if (!strcmp(funcName, "vkQueueBindSparse"))
   10860         return (PFN_vkVoidFunction)vkQueueBindSparse;
   10861     if (!strcmp(funcName, "vkCreateSemaphore"))
   10862         return (PFN_vkVoidFunction)vkCreateSemaphore;
   10863     if (!strcmp(funcName, "vkCreateEvent"))
   10864         return (PFN_vkVoidFunction)vkCreateEvent;
   10865 
   10866     if (dev == NULL)
   10867         return NULL;
   10868 
   10869     layer_data *dev_data;
   10870     dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map);
   10871 
   10872     if (dev_data->device_extensions.wsi_enabled) {
   10873         if (!strcmp(funcName, "vkCreateSwapchainKHR"))
   10874             return (PFN_vkVoidFunction)vkCreateSwapchainKHR;
   10875         if (!strcmp(funcName, "vkDestroySwapchainKHR"))
   10876             return (PFN_vkVoidFunction)vkDestroySwapchainKHR;
   10877         if (!strcmp(funcName, "vkGetSwapchainImagesKHR"))
   10878             return (PFN_vkVoidFunction)vkGetSwapchainImagesKHR;
   10879         if (!strcmp(funcName, "vkAcquireNextImageKHR"))
   10880             return (PFN_vkVoidFunction)vkAcquireNextImageKHR;
   10881         if (!strcmp(funcName, "vkQueuePresentKHR"))
   10882             return (PFN_vkVoidFunction)vkQueuePresentKHR;
   10883     }
   10884 
   10885     VkLayerDispatchTable *pTable = dev_data->device_dispatch_table;
   10886     {
   10887         if (pTable->GetDeviceProcAddr == NULL)
   10888             return NULL;
   10889         return pTable->GetDeviceProcAddr(dev, funcName);
   10890     }
   10891 }
   10892 
   10893 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
   10894     if (!strcmp(funcName, "vkGetInstanceProcAddr"))
   10895         return (PFN_vkVoidFunction)vkGetInstanceProcAddr;
   10896     if (!strcmp(funcName, "vkGetDeviceProcAddr"))
   10897         return (PFN_vkVoidFunction)vkGetDeviceProcAddr;
   10898     if (!strcmp(funcName, "vkCreateInstance"))
   10899         return (PFN_vkVoidFunction)vkCreateInstance;
   10900     if (!strcmp(funcName, "vkCreateDevice"))
   10901         return (PFN_vkVoidFunction)vkCreateDevice;
   10902     if (!strcmp(funcName, "vkDestroyInstance"))
   10903         return (PFN_vkVoidFunction)vkDestroyInstance;
   10904 #if MTMERGESOURCE
   10905     if (!strcmp(funcName, "vkGetPhysicalDeviceMemoryProperties"))
   10906         return (PFN_vkVoidFunction)vkGetPhysicalDeviceMemoryProperties;
   10907 #endif
   10908     if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties"))
   10909         return (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties;
   10910     if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties"))
   10911         return (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties;
   10912     if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties"))
   10913         return (PFN_vkVoidFunction)vkEnumerateDeviceLayerProperties;
   10914     if (!strcmp(funcName, "vkEnumerateDeviceExtensionProperties"))
   10915         return (PFN_vkVoidFunction)vkEnumerateDeviceExtensionProperties;
   10916 
   10917     if (instance == NULL)
   10918         return NULL;
   10919 
   10920     PFN_vkVoidFunction fptr;
   10921 
   10922     layer_data *my_data;
   10923     my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   10924     fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
   10925     if (fptr)
   10926         return fptr;
   10927 
   10928     VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
   10929     if (pTable->GetInstanceProcAddr == NULL)
   10930         return NULL;
   10931     return pTable->GetInstanceProcAddr(instance, funcName);
   10932 }
   10933