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  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Jon Ashburn <jon (at) lunarg.com>
     19  * Author: Mark Lobodzinski <mark (at) lunarg.com>
     20  * Author: Tobin Ehlis <tobin (at) lunarg.com>
     21  */
     22 
     23 #include <mutex>
     24 
     25 #include "vulkan/vk_layer.h"
     26 #include "vk_layer_extension_utils.h"
     27 #include "vk_enum_string_helper.h"
     28 #include "vk_layer_table.h"
     29 #include "vk_layer_utils.h"
     30 
     31 namespace object_tracker {
     32 
     33 // Object Tracker ERROR codes
     34 enum OBJECT_TRACK_ERROR {
     35     OBJTRACK_NONE,                     // Used for INFO & other non-error messages
     36     OBJTRACK_UNKNOWN_OBJECT,           // Updating uses of object that's not in global object list
     37     OBJTRACK_INTERNAL_ERROR,           // Bug with data tracking within the layer
     38     OBJTRACK_OBJECT_LEAK,              // OBJECT was not correctly freed/destroyed
     39     OBJTRACK_INVALID_OBJECT,           // Object used that has never been created
     40     OBJTRACK_DESCRIPTOR_POOL_MISMATCH, // Descriptor Pools specified incorrectly
     41     OBJTRACK_COMMAND_POOL_MISMATCH,    // Command Pools specified incorrectly
     42 };
     43 
     44 // Object Status -- used to track state of individual objects
     45 typedef VkFlags ObjectStatusFlags;
     46 enum ObjectStatusFlagBits {
     47     OBJSTATUS_NONE = 0x00000000,                     // No status is set
     48     OBJSTATUS_FENCE_IS_SUBMITTED = 0x00000001,       // Fence has been submitted
     49     OBJSTATUS_VIEWPORT_BOUND = 0x00000002,           // Viewport state object has been bound
     50     OBJSTATUS_RASTER_BOUND = 0x00000004,             // Viewport state object has been bound
     51     OBJSTATUS_COLOR_BLEND_BOUND = 0x00000008,        // Viewport state object has been bound
     52     OBJSTATUS_DEPTH_STENCIL_BOUND = 0x00000010,      // Viewport state object has been bound
     53     OBJSTATUS_GPU_MEM_MAPPED = 0x00000020,           // Memory object is currently mapped
     54     OBJSTATUS_COMMAND_BUFFER_SECONDARY = 0x00000040, // Command Buffer is of type SECONDARY
     55 };
     56 
     57 struct OBJTRACK_NODE {
     58     uint64_t vkObj;                     // Object handle
     59     VkDebugReportObjectTypeEXT objType; // Object type identifier
     60     ObjectStatusFlags status;           // Object state
     61     uint64_t parentObj;                 // Parent object
     62     uint64_t belongsTo;                 // Object Scope -- owning device/instance
     63 };
     64 
     65 // prototype for extension functions
     66 uint64_t objTrackGetObjectCount(VkDevice device);
     67 uint64_t objTrackGetObjectsOfTypeCount(VkDevice, VkDebugReportObjectTypeEXT type);
     68 
     69 // Func ptr typedefs
     70 typedef uint64_t (*OBJ_TRACK_GET_OBJECT_COUNT)(VkDevice);
     71 typedef uint64_t (*OBJ_TRACK_GET_OBJECTS_OF_TYPE_COUNT)(VkDevice, VkDebugReportObjectTypeEXT);
     72 
     73 struct layer_data {
     74     VkInstance instance;
     75 
     76     debug_report_data *report_data;
     77     // TODO: put instance data here
     78     std::vector<VkDebugReportCallbackEXT> logging_callback;
     79     bool wsi_enabled;
     80     bool objtrack_extensions_enabled;
     81     // The following are for keeping track of the temporary callbacks that can
     82     // be used in vkCreateInstance and vkDestroyInstance:
     83     uint32_t num_tmp_callbacks;
     84     VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
     85     VkDebugReportCallbackEXT *tmp_callbacks;
     86 
     87     layer_data()
     88         : report_data(nullptr), wsi_enabled(false), objtrack_extensions_enabled(false), num_tmp_callbacks(0),
     89           tmp_dbg_create_infos(nullptr), tmp_callbacks(nullptr){};
     90 };
     91 
     92 struct instExts {
     93     bool wsi_enabled;
     94 };
     95 
     96 static std::unordered_map<void *, struct instExts> instanceExtMap;
     97 static std::unordered_map<void *, layer_data *> layer_data_map;
     98 static device_table_map object_tracker_device_table_map;
     99 static instance_table_map object_tracker_instance_table_map;
    100 
    101 // We need additionally validate image usage using a separate map
    102 // of swapchain-created images
    103 static std::unordered_map<uint64_t, OBJTRACK_NODE *> swapchainImageMap;
    104 
    105 static long long unsigned int object_track_index = 0;
    106 static std::mutex global_lock;
    107 
    108 #define NUM_OBJECT_TYPES (VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT + 1)
    109 
    110 static uint64_t numObjs[NUM_OBJECT_TYPES] = {0};
    111 static uint64_t numTotalObjs = 0;
    112 std::vector<VkQueueFamilyProperties> queue_family_properties;
    113 
    114 //
    115 // Internal Object Tracker Functions
    116 //
    117 
    118 static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
    119     layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
    120     VkLayerDispatchTable *pDisp = get_dispatch_table(object_tracker_device_table_map, device);
    121     PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr;
    122     pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR");
    123     pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR");
    124     pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR");
    125     pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR");
    126     pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR");
    127     my_device_data->wsi_enabled = false;
    128     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
    129         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
    130             my_device_data->wsi_enabled = true;
    131 
    132         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], "OBJTRACK_EXTENSIONS") == 0)
    133             my_device_data->objtrack_extensions_enabled = true;
    134     }
    135 }
    136 
    137 static void createInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) {
    138     uint32_t i;
    139     VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(object_tracker_instance_table_map, instance);
    140     PFN_vkGetInstanceProcAddr gpa = pDisp->GetInstanceProcAddr;
    141 
    142     pDisp->DestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)gpa(instance, "vkDestroySurfaceKHR");
    143     pDisp->GetPhysicalDeviceSurfaceSupportKHR =
    144         (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceSupportKHR");
    145     pDisp->GetPhysicalDeviceSurfaceCapabilitiesKHR =
    146         (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
    147     pDisp->GetPhysicalDeviceSurfaceFormatsKHR =
    148         (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR");
    149     pDisp->GetPhysicalDeviceSurfacePresentModesKHR =
    150         (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)gpa(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR");
    151 
    152 #if VK_USE_PLATFORM_WIN32_KHR
    153     pDisp->CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)gpa(instance, "vkCreateWin32SurfaceKHR");
    154     pDisp->GetPhysicalDeviceWin32PresentationSupportKHR =
    155         (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
    156 #endif // VK_USE_PLATFORM_WIN32_KHR
    157 #ifdef VK_USE_PLATFORM_XCB_KHR
    158     pDisp->CreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)gpa(instance, "vkCreateXcbSurfaceKHR");
    159     pDisp->GetPhysicalDeviceXcbPresentationSupportKHR =
    160         (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR");
    161 #endif // VK_USE_PLATFORM_XCB_KHR
    162 #ifdef VK_USE_PLATFORM_XLIB_KHR
    163     pDisp->CreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)gpa(instance, "vkCreateXlibSurfaceKHR");
    164     pDisp->GetPhysicalDeviceXlibPresentationSupportKHR =
    165         (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR");
    166 #endif // VK_USE_PLATFORM_XLIB_KHR
    167 #ifdef VK_USE_PLATFORM_MIR_KHR
    168     pDisp->CreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR)gpa(instance, "vkCreateMirSurfaceKHR");
    169     pDisp->GetPhysicalDeviceMirPresentationSupportKHR =
    170         (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
    171 #endif // VK_USE_PLATFORM_MIR_KHR
    172 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
    173     pDisp->CreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)gpa(instance, "vkCreateWaylandSurfaceKHR");
    174     pDisp->GetPhysicalDeviceWaylandPresentationSupportKHR =
    175         (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
    176 #endif //  VK_USE_PLATFORM_WAYLAND_KHR
    177 #ifdef VK_USE_PLATFORM_ANDROID_KHR
    178     pDisp->CreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)gpa(instance, "vkCreateAndroidSurfaceKHR");
    179 #endif // VK_USE_PLATFORM_ANDROID_KHR
    180 
    181     instanceExtMap[pDisp].wsi_enabled = false;
    182     for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
    183         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME) == 0)
    184             instanceExtMap[pDisp].wsi_enabled = true;
    185     }
    186 }
    187 
    188 // Indicate device or instance dispatch table type
    189 enum DispTableType {
    190     DISP_TBL_TYPE_INSTANCE,
    191     DISP_TBL_TYPE_DEVICE,
    192 };
    193 
    194 debug_report_data *mdd(const void *object) {
    195     dispatch_key key = get_dispatch_key(object);
    196     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
    197     return my_data->report_data;
    198 }
    199 
    200 debug_report_data *mid(VkInstance object) {
    201     dispatch_key key = get_dispatch_key(object);
    202     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
    203     return my_data->report_data;
    204 }
    205 
    206 // For each Queue's doubly linked-list of mem refs
    207 struct OT_MEM_INFO {
    208     VkDeviceMemory mem;
    209     OT_MEM_INFO *pNextMI;
    210     OT_MEM_INFO *pPrevMI;
    211 };
    212 
    213 // Track Queue information
    214 struct OT_QUEUE_INFO {
    215     OT_MEM_INFO *pMemRefList;
    216     uint32_t queueNodeIndex;
    217     VkQueue queue;
    218     uint32_t refCount;
    219 };
    220 
    221 // Global map of structures, one per queue
    222 std::unordered_map<VkQueue, OT_QUEUE_INFO *> queue_info_map;
    223 
    224 #include "vk_dispatch_table_helper.h"
    225 
    226 static void init_object_tracker(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
    227 
    228     layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_object_tracker");
    229 }
    230 
    231 //
    232 // Forward declarations
    233 //
    234 
    235 static void create_physical_device(VkInstance dispatchable_object, VkPhysicalDevice vkObj, VkDebugReportObjectTypeEXT objType);
    236 static void create_instance(VkInstance dispatchable_object, VkInstance object, VkDebugReportObjectTypeEXT objType);
    237 static void create_device(VkDevice dispatchable_object, VkDevice object, VkDebugReportObjectTypeEXT objType);
    238 static void create_device(VkPhysicalDevice dispatchable_object, VkDevice object, VkDebugReportObjectTypeEXT objType);
    239 static void create_queue(VkDevice dispatchable_object, VkQueue vkObj, VkDebugReportObjectTypeEXT objType);
    240 static bool validate_image(VkQueue dispatchable_object, VkImage object, VkDebugReportObjectTypeEXT objType, bool null_allowed);
    241 static bool validate_instance(VkInstance dispatchable_object, VkInstance object, VkDebugReportObjectTypeEXT objType,
    242                                   bool null_allowed);
    243 static bool validate_device(VkDevice dispatchable_object, VkDevice object, VkDebugReportObjectTypeEXT objType,
    244                                 bool null_allowed);
    245 static bool validate_descriptor_pool(VkDevice dispatchable_object, VkDescriptorPool object, VkDebugReportObjectTypeEXT objType,
    246                                          bool null_allowed);
    247 static bool validate_descriptor_set_layout(VkDevice dispatchable_object, VkDescriptorSetLayout object,
    248                                                VkDebugReportObjectTypeEXT objType, bool null_allowed);
    249 static bool validate_command_pool(VkDevice dispatchable_object, VkCommandPool object, VkDebugReportObjectTypeEXT objType,
    250                                       bool null_allowed);
    251 static bool validate_buffer(VkQueue dispatchable_object, VkBuffer object, VkDebugReportObjectTypeEXT objType,
    252                                 bool null_allowed);
    253 static void create_pipeline(VkDevice dispatchable_object, VkPipeline vkObj, VkDebugReportObjectTypeEXT objType);
    254 static bool validate_pipeline_cache(VkDevice dispatchable_object, VkPipelineCache object, VkDebugReportObjectTypeEXT objType,
    255                                         bool null_allowed);
    256 static bool validate_render_pass(VkDevice dispatchable_object, VkRenderPass object, VkDebugReportObjectTypeEXT objType,
    257                                      bool null_allowed);
    258 static bool validate_shader_module(VkDevice dispatchable_object, VkShaderModule object, VkDebugReportObjectTypeEXT objType,
    259                                        bool null_allowed);
    260 static bool validate_pipeline_layout(VkDevice dispatchable_object, VkPipelineLayout object, VkDebugReportObjectTypeEXT objType,
    261                                          bool null_allowed);
    262 static bool validate_pipeline(VkDevice dispatchable_object, VkPipeline object, VkDebugReportObjectTypeEXT objType,
    263                                   bool null_allowed);
    264 static void destroy_command_pool(VkDevice dispatchable_object, VkCommandPool object);
    265 static void destroy_descriptor_pool(VkDevice dispatchable_object, VkDescriptorPool object);
    266 static void destroy_descriptor_set(VkDevice dispatchable_object, VkDescriptorSet object);
    267 static void destroy_device_memory(VkDevice dispatchable_object, VkDeviceMemory object);
    268 static void destroy_swapchain_khr(VkDevice dispatchable_object, VkSwapchainKHR object);
    269 static bool set_device_memory_status(VkDevice dispatchable_object, VkDeviceMemory object, VkDebugReportObjectTypeEXT objType,
    270                                          ObjectStatusFlags status_flag);
    271 static bool reset_device_memory_status(VkDevice dispatchable_object, VkDeviceMemory object, VkDebugReportObjectTypeEXT objType,
    272                                            ObjectStatusFlags status_flag);
    273 static void destroy_queue(VkQueue dispatchable_object, VkQueue object);
    274 
    275 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkPhysicalDeviceMap;
    276 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkDeviceMap;
    277 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkImageMap;
    278 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkQueueMap;
    279 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkDescriptorSetMap;
    280 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkBufferMap;
    281 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkFenceMap;
    282 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkSemaphoreMap;
    283 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkCommandPoolMap;
    284 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkCommandBufferMap;
    285 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkSwapchainKHRMap;
    286 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkSurfaceKHRMap;
    287 extern std::unordered_map<uint64_t, OBJTRACK_NODE *> VkQueueMap;
    288 
    289 // Convert an object type enum to an object type array index
    290 static uint32_t objTypeToIndex(uint32_t objType) {
    291     uint32_t index = objType;
    292     return index;
    293 }
    294 
    295 // Add new queue to head of global queue list
    296 static void addQueueInfo(uint32_t queueNodeIndex, VkQueue queue) {
    297     auto queueItem = queue_info_map.find(queue);
    298     if (queueItem == queue_info_map.end()) {
    299         OT_QUEUE_INFO *p_queue_info = new OT_QUEUE_INFO;
    300         if (p_queue_info != NULL) {
    301             memset(p_queue_info, 0, sizeof(OT_QUEUE_INFO));
    302             p_queue_info->queue = queue;
    303             p_queue_info->queueNodeIndex = queueNodeIndex;
    304             queue_info_map[queue] = p_queue_info;
    305         } else {
    306             log_msg(mdd(queue), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
    307                     reinterpret_cast<uint64_t>(queue), __LINE__, OBJTRACK_INTERNAL_ERROR, "OBJTRACK",
    308                     "ERROR:  VK_ERROR_OUT_OF_HOST_MEMORY -- could not allocate memory for Queue Information");
    309         }
    310     }
    311 }
    312 
    313 // Destroy memRef lists and free all memory
    314 static void destroyQueueMemRefLists() {
    315     for (auto queue_item : queue_info_map) {
    316         OT_MEM_INFO *p_mem_info = queue_item.second->pMemRefList;
    317         while (p_mem_info != NULL) {
    318             OT_MEM_INFO *p_del_mem_info = p_mem_info;
    319             p_mem_info = p_mem_info->pNextMI;
    320             delete p_del_mem_info;
    321         }
    322         delete queue_item.second;
    323     }
    324     queue_info_map.clear();
    325 
    326     // Destroy the items in the queue map
    327     auto queue = VkQueueMap.begin();
    328     while (queue != VkQueueMap.end()) {
    329         uint32_t obj_index = objTypeToIndex(queue->second->objType);
    330         assert(numTotalObjs > 0);
    331         numTotalObjs--;
    332         assert(numObjs[obj_index] > 0);
    333         numObjs[obj_index]--;
    334         log_msg(mdd(reinterpret_cast<VkQueue>(queue->second->vkObj)), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, queue->second->objType,
    335                 queue->second->vkObj, __LINE__, OBJTRACK_NONE, "OBJTRACK",
    336                 "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",
    337                 string_VkDebugReportObjectTypeEXT(queue->second->objType), queue->second->vkObj, numTotalObjs, numObjs[obj_index],
    338                 string_VkDebugReportObjectTypeEXT(queue->second->objType));
    339         delete queue->second;
    340         queue = VkQueueMap.erase(queue);
    341     }
    342 }
    343 
    344 // Check Queue type flags for selected queue operations
    345 static void validateQueueFlags(VkQueue queue, const char *function) {
    346 
    347     auto queue_item = queue_info_map.find(queue);
    348     if (queue_item != queue_info_map.end()) {
    349         OT_QUEUE_INFO *pQueueInfo = queue_item->second;
    350         if (pQueueInfo != NULL) {
    351             if ((queue_family_properties[pQueueInfo->queueNodeIndex].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) == 0) {
    352                 log_msg(mdd(queue), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
    353                         reinterpret_cast<uint64_t>(queue), __LINE__, OBJTRACK_UNKNOWN_OBJECT, "OBJTRACK",
    354                         "Attempting %s on a non-memory-management capable queue -- VK_QUEUE_SPARSE_BINDING_BIT not set", function);
    355             }
    356         }
    357     }
    358 }
    359 
    360 static void create_physical_device(VkInstance instance, VkPhysicalDevice vkObj, VkDebugReportObjectTypeEXT objType) {
    361     log_msg(mdd(instance), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objType, reinterpret_cast<uint64_t>(vkObj), __LINE__,
    362             OBJTRACK_NONE, "OBJTRACK", "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++,
    363             string_VkDebugReportObjectTypeEXT(objType), reinterpret_cast<uint64_t>(vkObj));
    364 
    365     uint64_t physical_device_handle = reinterpret_cast<uint64_t>(vkObj);
    366     auto pd_item = VkPhysicalDeviceMap.find(physical_device_handle);
    367     if (pd_item == VkPhysicalDeviceMap.end()) {
    368         OBJTRACK_NODE *p_new_obj_node = new OBJTRACK_NODE;
    369         p_new_obj_node->objType = objType;
    370         p_new_obj_node->belongsTo = reinterpret_cast<uint64_t>(instance);
    371         p_new_obj_node->status = OBJSTATUS_NONE;
    372         p_new_obj_node->vkObj = physical_device_handle;
    373         VkPhysicalDeviceMap[physical_device_handle] = p_new_obj_node;
    374         uint32_t objIndex = objTypeToIndex(objType);
    375         numObjs[objIndex]++;
    376         numTotalObjs++;
    377     }
    378 }
    379 
    380 static void create_surface_khr(VkInstance dispatchable_object, VkSurfaceKHR vkObj, VkDebugReportObjectTypeEXT objType) {
    381     // TODO: Add tracking of surface objects
    382     log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objType, (uint64_t)(vkObj), __LINE__, OBJTRACK_NONE,
    383             "OBJTRACK", "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++,
    384             string_VkDebugReportObjectTypeEXT(objType), (uint64_t)(vkObj));
    385 
    386     OBJTRACK_NODE *pNewObjNode = new OBJTRACK_NODE;
    387     pNewObjNode->objType = objType;
    388     pNewObjNode->belongsTo = (uint64_t)dispatchable_object;
    389     pNewObjNode->status = OBJSTATUS_NONE;
    390     pNewObjNode->vkObj = (uint64_t)(vkObj);
    391     VkSurfaceKHRMap[(uint64_t)vkObj] = pNewObjNode;
    392     uint32_t objIndex = objTypeToIndex(objType);
    393     numObjs[objIndex]++;
    394     numTotalObjs++;
    395 }
    396 
    397 static void destroy_surface_khr(VkInstance dispatchable_object, VkSurfaceKHR object) {
    398     uint64_t object_handle = (uint64_t)(object);
    399     if (VkSurfaceKHRMap.find(object_handle) != VkSurfaceKHRMap.end()) {
    400         OBJTRACK_NODE *pNode = VkSurfaceKHRMap[(uint64_t)object];
    401         uint32_t objIndex = objTypeToIndex(pNode->objType);
    402         assert(numTotalObjs > 0);
    403         numTotalObjs--;
    404         assert(numObjs[objIndex] > 0);
    405         numObjs[objIndex]--;
    406         log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, pNode->objType, object_handle, __LINE__,
    407                 OBJTRACK_NONE, "OBJTRACK",
    408                 "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (0x%" PRIx64 " total objs remain & 0x%" PRIx64 " %s objs).",
    409                 string_VkDebugReportObjectTypeEXT(pNode->objType), (uint64_t)(object), numTotalObjs, numObjs[objIndex],
    410                 string_VkDebugReportObjectTypeEXT(pNode->objType));
    411         delete pNode;
    412         VkSurfaceKHRMap.erase(object_handle);
    413     } else {
    414         log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, object_handle, __LINE__,
    415                 OBJTRACK_NONE, "OBJTRACK",
    416                 "Unable to remove obj 0x%" PRIxLEAST64 ". Was it created? Has it already been destroyed?", object_handle);
    417     }
    418 }
    419 
    420 static void alloc_command_buffer(VkDevice device, VkCommandPool commandPool, VkCommandBuffer vkObj,
    421                                  VkDebugReportObjectTypeEXT objType, VkCommandBufferLevel level) {
    422     log_msg(mdd(device), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objType, reinterpret_cast<uint64_t>(vkObj), __LINE__, OBJTRACK_NONE,
    423             "OBJTRACK", "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++,
    424             string_VkDebugReportObjectTypeEXT(objType), reinterpret_cast<uint64_t>(vkObj));
    425 
    426     OBJTRACK_NODE *pNewObjNode = new OBJTRACK_NODE;
    427     pNewObjNode->objType = objType;
    428     pNewObjNode->belongsTo = (uint64_t)device;
    429     pNewObjNode->vkObj = reinterpret_cast<uint64_t>(vkObj);
    430     pNewObjNode->parentObj = (uint64_t)commandPool;
    431     if (level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
    432         pNewObjNode->status = OBJSTATUS_COMMAND_BUFFER_SECONDARY;
    433     } else {
    434         pNewObjNode->status = OBJSTATUS_NONE;
    435     }
    436     VkCommandBufferMap[reinterpret_cast<uint64_t>(vkObj)] = pNewObjNode;
    437     uint32_t objIndex = objTypeToIndex(objType);
    438     numObjs[objIndex]++;
    439     numTotalObjs++;
    440 }
    441 
    442 static bool validate_command_buffer(VkDevice device, VkCommandPool commandPool, VkCommandBuffer commandBuffer) {
    443     bool skipCall = false;
    444     uint64_t object_handle = reinterpret_cast<uint64_t>(commandBuffer);
    445     if (VkCommandBufferMap.find(object_handle) != VkCommandBufferMap.end()) {
    446         OBJTRACK_NODE *pNode = VkCommandBufferMap[(uint64_t)commandBuffer];
    447 
    448         if (pNode->parentObj != (uint64_t)(commandPool)) {
    449             skipCall |= log_msg(
    450                 mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, pNode->objType, object_handle, __LINE__, OBJTRACK_COMMAND_POOL_MISMATCH,
    451                 "OBJTRACK", "FreeCommandBuffers is attempting to free Command Buffer 0x%" PRIxLEAST64
    452                             " belonging to Command Pool 0x%" PRIxLEAST64 " from pool 0x%" PRIxLEAST64 ").",
    453                 reinterpret_cast<uint64_t>(commandBuffer), pNode->parentObj, reinterpret_cast<uint64_t &>(commandPool));
    454         }
    455     } else {
    456         skipCall |= log_msg(
    457             mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, object_handle, __LINE__, OBJTRACK_NONE,
    458             "OBJTRACK", "Unable to remove obj 0x%" PRIxLEAST64 ". Was it created? Has it already been destroyed?", object_handle);
    459     }
    460     return skipCall;
    461 }
    462 
    463 static bool free_command_buffer(VkDevice device, VkCommandBuffer commandBuffer) {
    464     bool skipCall = false;
    465     auto cbItem = VkCommandBufferMap.find(reinterpret_cast<uint64_t>(commandBuffer));
    466     if (cbItem != VkCommandBufferMap.end()) {
    467         OBJTRACK_NODE *pNode = cbItem->second;
    468         uint32_t objIndex = objTypeToIndex(pNode->objType);
    469         assert(numTotalObjs > 0);
    470         numTotalObjs--;
    471         assert(numObjs[objIndex] > 0);
    472         numObjs[objIndex]--;
    473         skipCall |= log_msg(mdd(device), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, pNode->objType,
    474                             reinterpret_cast<uint64_t>(commandBuffer), __LINE__, OBJTRACK_NONE, "OBJTRACK",
    475                             "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",
    476                             string_VkDebugReportObjectTypeEXT(pNode->objType), reinterpret_cast<uint64_t>(commandBuffer),
    477                             numTotalObjs, numObjs[objIndex], string_VkDebugReportObjectTypeEXT(pNode->objType));
    478         delete pNode;
    479         VkCommandBufferMap.erase(cbItem);
    480     }
    481     return skipCall;
    482 }
    483 
    484 static void alloc_descriptor_set(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSet vkObj,
    485                                  VkDebugReportObjectTypeEXT objType) {
    486     log_msg(mdd(device), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objType, (uint64_t)(vkObj), __LINE__, OBJTRACK_NONE, "OBJTRACK",
    487             "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++, string_VkDebugReportObjectTypeEXT(objType),
    488             (uint64_t)(vkObj));
    489 
    490     OBJTRACK_NODE *pNewObjNode = new OBJTRACK_NODE;
    491     pNewObjNode->objType = objType;
    492     pNewObjNode->belongsTo = (uint64_t)device;
    493     pNewObjNode->status = OBJSTATUS_NONE;
    494     pNewObjNode->vkObj = (uint64_t)(vkObj);
    495     pNewObjNode->parentObj = (uint64_t)descriptorPool;
    496     VkDescriptorSetMap[(uint64_t)vkObj] = pNewObjNode;
    497     uint32_t objIndex = objTypeToIndex(objType);
    498     numObjs[objIndex]++;
    499     numTotalObjs++;
    500 }
    501 
    502 static bool validate_descriptor_set(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSet descriptorSet) {
    503     bool skipCall = false;
    504     uint64_t object_handle = reinterpret_cast<uint64_t &>(descriptorSet);
    505     auto dsItem = VkDescriptorSetMap.find(object_handle);
    506     if (dsItem != VkDescriptorSetMap.end()) {
    507         OBJTRACK_NODE *pNode = dsItem->second;
    508 
    509         if (pNode->parentObj != reinterpret_cast<uint64_t &>(descriptorPool)) {
    510             skipCall |= log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, pNode->objType, object_handle, __LINE__,
    511                                 OBJTRACK_DESCRIPTOR_POOL_MISMATCH, "OBJTRACK",
    512                                 "FreeDescriptorSets is attempting to free descriptorSet 0x%" PRIxLEAST64
    513                                 " belonging to Descriptor Pool 0x%" PRIxLEAST64 " from pool 0x%" PRIxLEAST64 ").",
    514                                 reinterpret_cast<uint64_t &>(descriptorSet), pNode->parentObj,
    515                                 reinterpret_cast<uint64_t &>(descriptorPool));
    516         }
    517     } else {
    518         skipCall |= log_msg(
    519             mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, object_handle, __LINE__, OBJTRACK_NONE,
    520             "OBJTRACK", "Unable to remove obj 0x%" PRIxLEAST64 ". Was it created? Has it already been destroyed?", object_handle);
    521     }
    522     return skipCall;
    523 }
    524 
    525 static bool free_descriptor_set(VkDevice device, VkDescriptorSet descriptorSet) {
    526     bool skipCall = false;
    527     auto dsItem = VkDescriptorSetMap.find(reinterpret_cast<uint64_t &>(descriptorSet));
    528     if (dsItem != VkDescriptorSetMap.end()) {
    529         OBJTRACK_NODE *pNode = dsItem->second;
    530         uint32_t objIndex = objTypeToIndex(pNode->objType);
    531         assert(numTotalObjs > 0);
    532         numTotalObjs--;
    533         assert(numObjs[objIndex] > 0);
    534         numObjs[objIndex]--;
    535         skipCall |= log_msg(mdd(device), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, pNode->objType,
    536                             reinterpret_cast<uint64_t &>(descriptorSet), __LINE__, OBJTRACK_NONE, "OBJTRACK",
    537                             "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",
    538                             string_VkDebugReportObjectTypeEXT(pNode->objType), reinterpret_cast<uint64_t &>(descriptorSet),
    539                             numTotalObjs, numObjs[objIndex], string_VkDebugReportObjectTypeEXT(pNode->objType));
    540         delete pNode;
    541         VkDescriptorSetMap.erase(dsItem);
    542     }
    543     return skipCall;
    544 }
    545 
    546 static void create_queue(VkDevice device, VkQueue vkObj, VkDebugReportObjectTypeEXT objType) {
    547 
    548     log_msg(mdd(device), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objType, reinterpret_cast<uint64_t>(vkObj), __LINE__,
    549             OBJTRACK_NONE, "OBJTRACK", "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++,
    550             string_VkDebugReportObjectTypeEXT(objType), reinterpret_cast<uint64_t>(vkObj));
    551 
    552     OBJTRACK_NODE *p_obj_node = NULL;
    553     auto queue_item = VkQueueMap.find(reinterpret_cast<uint64_t>(vkObj));
    554     if (queue_item == VkQueueMap.end()) {
    555         p_obj_node = new OBJTRACK_NODE;
    556         VkQueueMap[reinterpret_cast<uint64_t>(vkObj)] = p_obj_node;
    557         uint32_t objIndex = objTypeToIndex(objType);
    558         numObjs[objIndex]++;
    559         numTotalObjs++;
    560     } else {
    561         p_obj_node = queue_item->second;
    562     }
    563     p_obj_node->objType = objType;
    564     p_obj_node->belongsTo = reinterpret_cast<uint64_t>(device);
    565     p_obj_node->status = OBJSTATUS_NONE;
    566     p_obj_node->vkObj = reinterpret_cast<uint64_t>(vkObj);
    567 }
    568 
    569 static void create_swapchain_image_obj(VkDevice dispatchable_object, VkImage vkObj, VkSwapchainKHR swapchain) {
    570     log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, (uint64_t)vkObj,
    571             __LINE__, OBJTRACK_NONE, "OBJTRACK", "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++,
    572             "SwapchainImage", (uint64_t)(vkObj));
    573 
    574     OBJTRACK_NODE *pNewObjNode = new OBJTRACK_NODE;
    575     pNewObjNode->belongsTo = (uint64_t)dispatchable_object;
    576     pNewObjNode->objType = VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT;
    577     pNewObjNode->status = OBJSTATUS_NONE;
    578     pNewObjNode->vkObj = (uint64_t)vkObj;
    579     pNewObjNode->parentObj = (uint64_t)swapchain;
    580     swapchainImageMap[(uint64_t)(vkObj)] = pNewObjNode;
    581 }
    582 
    583 static void create_device(VkInstance dispatchable_object, VkDevice vkObj, VkDebugReportObjectTypeEXT objType) {
    584     log_msg(mid(dispatchable_object), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objType, (uint64_t)(vkObj), __LINE__, OBJTRACK_NONE,
    585             "OBJTRACK", "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++,
    586             string_VkDebugReportObjectTypeEXT(objType), (uint64_t)(vkObj));
    587 
    588     OBJTRACK_NODE *pNewObjNode = new OBJTRACK_NODE;
    589     pNewObjNode->belongsTo = (uint64_t)dispatchable_object;
    590     pNewObjNode->objType = objType;
    591     pNewObjNode->status = OBJSTATUS_NONE;
    592     pNewObjNode->vkObj = (uint64_t)(vkObj);
    593     VkDeviceMap[(uint64_t)vkObj] = pNewObjNode;
    594     uint32_t objIndex = objTypeToIndex(objType);
    595     numObjs[objIndex]++;
    596     numTotalObjs++;
    597 }
    598 
    599 //
    600 // Non-auto-generated API functions called by generated code
    601 //
    602 VkResult explicit_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
    603                                  VkInstance *pInstance) {
    604     VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
    605 
    606     assert(chain_info->u.pLayerInfo);
    607     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
    608     PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
    609     if (fpCreateInstance == NULL) {
    610         return VK_ERROR_INITIALIZATION_FAILED;
    611     }
    612 
    613     // Advance the link info for the next element on the chain
    614     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
    615 
    616     VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
    617     if (result != VK_SUCCESS) {
    618         return result;
    619     }
    620 
    621     layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
    622     my_data->instance = *pInstance;
    623     initInstanceTable(*pInstance, fpGetInstanceProcAddr, object_tracker_instance_table_map);
    624     VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(object_tracker_instance_table_map, *pInstance);
    625 
    626     // Look for one or more debug report create info structures, and copy the
    627     // callback(s) for each one found (for use by vkDestroyInstance)
    628     layer_copy_tmp_callbacks(pCreateInfo->pNext, &my_data->num_tmp_callbacks, &my_data->tmp_dbg_create_infos,
    629                              &my_data->tmp_callbacks);
    630 
    631     my_data->report_data = debug_report_create_instance(pInstanceTable, *pInstance, pCreateInfo->enabledExtensionCount,
    632                                                         pCreateInfo->ppEnabledExtensionNames);
    633 
    634     init_object_tracker(my_data, pAllocator);
    635     createInstanceRegisterExtensions(pCreateInfo, *pInstance);
    636 
    637     create_instance(*pInstance, *pInstance, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT);
    638 
    639     return result;
    640 }
    641 
    642 void explicit_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice gpu, uint32_t *pCount, VkQueueFamilyProperties *pProperties) {
    643     get_dispatch_table(object_tracker_instance_table_map, gpu)->GetPhysicalDeviceQueueFamilyProperties(gpu, pCount, pProperties);
    644 
    645     std::lock_guard<std::mutex> lock(global_lock);
    646     if (pProperties != NULL) {
    647         for (uint32_t i = 0; i < *pCount; i++) {
    648             queue_family_properties.emplace_back(pProperties[i]);
    649         }
    650     }
    651 }
    652 
    653 VkResult explicit_CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
    654                                VkDevice *pDevice) {
    655     std::lock_guard<std::mutex> lock(global_lock);
    656     layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map);
    657     VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
    658 
    659     assert(chain_info->u.pLayerInfo);
    660     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
    661     PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
    662     PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
    663     if (fpCreateDevice == NULL) {
    664         return VK_ERROR_INITIALIZATION_FAILED;
    665     }
    666 
    667     // Advance the link info for the next element on the chain
    668     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
    669 
    670     VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
    671     if (result != VK_SUCCESS) {
    672         return result;
    673     }
    674 
    675     layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
    676     my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
    677 
    678     initDeviceTable(*pDevice, fpGetDeviceProcAddr, object_tracker_device_table_map);
    679 
    680     createDeviceRegisterExtensions(pCreateInfo, *pDevice);
    681 
    682     if (VkPhysicalDeviceMap.find((uint64_t)gpu) != VkPhysicalDeviceMap.end()) {
    683         OBJTRACK_NODE *pNewObjNode = VkPhysicalDeviceMap[(uint64_t)gpu];
    684         create_device((VkInstance)pNewObjNode->belongsTo, *pDevice, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT);
    685     }
    686 
    687     return result;
    688 }
    689 
    690 VkResult explicit_EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
    691                                            VkPhysicalDevice *pPhysicalDevices) {
    692     bool skipCall = VK_FALSE;
    693     std::unique_lock<std::mutex> lock(global_lock);
    694     skipCall |= validate_instance(instance, instance, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, false);
    695     lock.unlock();
    696     if (skipCall)
    697         return VK_ERROR_VALIDATION_FAILED_EXT;
    698     VkResult result = get_dispatch_table(object_tracker_instance_table_map, instance)
    699                           ->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
    700     lock.lock();
    701     if (result == VK_SUCCESS) {
    702         if (pPhysicalDevices) {
    703             for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
    704                 create_physical_device(instance, pPhysicalDevices[i], VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT);
    705             }
    706         }
    707     }
    708     lock.unlock();
    709     return result;
    710 }
    711 
    712 void explicit_GetDeviceQueue(VkDevice device, uint32_t queueNodeIndex, uint32_t queueIndex, VkQueue *pQueue) {
    713     std::unique_lock<std::mutex> lock(global_lock);
    714     validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    715     lock.unlock();
    716 
    717     get_dispatch_table(object_tracker_device_table_map, device)->GetDeviceQueue(device, queueNodeIndex, queueIndex, pQueue);
    718 
    719     lock.lock();
    720 
    721     create_queue(device, *pQueue, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT);
    722     addQueueInfo(queueNodeIndex, *pQueue);
    723 }
    724 
    725 VkResult explicit_MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
    726                             void **ppData) {
    727     bool skipCall = VK_FALSE;
    728     std::unique_lock<std::mutex> lock(global_lock);
    729     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    730     lock.unlock();
    731     if (skipCall == VK_TRUE)
    732         return VK_ERROR_VALIDATION_FAILED_EXT;
    733 
    734     VkResult result =
    735         get_dispatch_table(object_tracker_device_table_map, device)->MapMemory(device, mem, offset, size, flags, ppData);
    736 
    737     return result;
    738 }
    739 
    740 void explicit_UnmapMemory(VkDevice device, VkDeviceMemory mem) {
    741     bool skipCall = VK_FALSE;
    742     std::unique_lock<std::mutex> lock(global_lock);
    743     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    744     lock.unlock();
    745     if (skipCall == VK_TRUE)
    746         return;
    747 
    748     get_dispatch_table(object_tracker_device_table_map, device)->UnmapMemory(device, mem);
    749 }
    750 
    751 VkResult explicit_QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) {
    752     std::unique_lock<std::mutex> lock(global_lock);
    753     validateQueueFlags(queue, "QueueBindSparse");
    754 
    755     for (uint32_t i = 0; i < bindInfoCount; i++) {
    756         for (uint32_t j = 0; j < pBindInfo[i].bufferBindCount; j++)
    757             validate_buffer(queue, pBindInfo[i].pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, false);
    758         for (uint32_t j = 0; j < pBindInfo[i].imageOpaqueBindCount; j++)
    759             validate_image(queue, pBindInfo[i].pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, false);
    760         for (uint32_t j = 0; j < pBindInfo[i].imageBindCount; j++)
    761             validate_image(queue, pBindInfo[i].pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, false);
    762     }
    763     lock.unlock();
    764 
    765     VkResult result =
    766         get_dispatch_table(object_tracker_device_table_map, queue)->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
    767     return result;
    768 }
    769 
    770 VkResult explicit_AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
    771                                          VkCommandBuffer *pCommandBuffers) {
    772     bool skipCall = VK_FALSE;
    773     std::unique_lock<std::mutex> lock(global_lock);
    774     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    775     skipCall |= validate_command_pool(device, pAllocateInfo->commandPool, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, false);
    776     lock.unlock();
    777 
    778     if (skipCall) {
    779         return VK_ERROR_VALIDATION_FAILED_EXT;
    780     }
    781 
    782     VkResult result =
    783         get_dispatch_table(object_tracker_device_table_map, device)->AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers);
    784 
    785     lock.lock();
    786     for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) {
    787         alloc_command_buffer(device, pAllocateInfo->commandPool, pCommandBuffers[i], VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    788                              pAllocateInfo->level);
    789     }
    790     lock.unlock();
    791 
    792     return result;
    793 }
    794 
    795 VkResult explicit_AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
    796                                          VkDescriptorSet *pDescriptorSets) {
    797     bool skipCall = VK_FALSE;
    798     std::unique_lock<std::mutex> lock(global_lock);
    799     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    800     skipCall |=
    801         validate_descriptor_pool(device, pAllocateInfo->descriptorPool, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, false);
    802     for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
    803         skipCall |= validate_descriptor_set_layout(device, pAllocateInfo->pSetLayouts[i],
    804                                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, false);
    805     }
    806     lock.unlock();
    807     if (skipCall) {
    808         return VK_ERROR_VALIDATION_FAILED_EXT;
    809     }
    810 
    811     VkResult result =
    812         get_dispatch_table(object_tracker_device_table_map, device)->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
    813 
    814     if (VK_SUCCESS == result) {
    815         lock.lock();
    816         for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
    817             alloc_descriptor_set(device, pAllocateInfo->descriptorPool, pDescriptorSets[i],
    818                                  VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT);
    819         }
    820         lock.unlock();
    821     }
    822 
    823     return result;
    824 }
    825 
    826 void explicit_FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
    827                                  const VkCommandBuffer *pCommandBuffers) {
    828     bool skipCall = false;
    829     std::unique_lock<std::mutex> lock(global_lock);
    830     validate_command_pool(device, commandPool, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, false);
    831     validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    832     for (uint32_t i = 0; i < commandBufferCount; i++) {
    833         skipCall |= validate_command_buffer(device, commandPool, pCommandBuffers[i]);
    834     }
    835 
    836     lock.unlock();
    837     if (!skipCall) {
    838         get_dispatch_table(object_tracker_device_table_map, device)
    839             ->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
    840     }
    841 
    842     lock.lock();
    843     for (uint32_t i = 0; i < commandBufferCount; i++) {
    844         free_command_buffer(device, pCommandBuffers[i]);
    845     }
    846 }
    847 
    848 void explicit_DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
    849     std::unique_lock<std::mutex> lock(global_lock);
    850     // A swapchain's images are implicitly deleted when the swapchain is deleted.
    851     // Remove this swapchain's images from our map of such images.
    852     std::unordered_map<uint64_t, OBJTRACK_NODE *>::iterator itr = swapchainImageMap.begin();
    853     while (itr != swapchainImageMap.end()) {
    854         OBJTRACK_NODE *pNode = (*itr).second;
    855         if (pNode->parentObj == reinterpret_cast<uint64_t &>(swapchain)) {
    856             delete pNode;
    857             swapchainImageMap.erase(itr++);
    858         } else {
    859             ++itr;
    860         }
    861     }
    862     destroy_swapchain_khr(device, swapchain);
    863     lock.unlock();
    864 
    865     get_dispatch_table(object_tracker_device_table_map, device)->DestroySwapchainKHR(device, swapchain, pAllocator);
    866 }
    867 
    868 void explicit_FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
    869     std::unique_lock<std::mutex> lock(global_lock);
    870     validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    871     lock.unlock();
    872 
    873     get_dispatch_table(object_tracker_device_table_map, device)->FreeMemory(device, mem, pAllocator);
    874 
    875     lock.lock();
    876     destroy_device_memory(device, mem);
    877 }
    878 
    879 VkResult explicit_FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
    880                                      const VkDescriptorSet *pDescriptorSets) {
    881     bool skipCall = false;
    882     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
    883     std::unique_lock<std::mutex> lock(global_lock);
    884     skipCall |= validate_descriptor_pool(device, descriptorPool, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, false);
    885     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    886     for (uint32_t i = 0; i < count; i++) {
    887         skipCall |= validate_descriptor_set(device, descriptorPool, pDescriptorSets[i]);
    888     }
    889 
    890     lock.unlock();
    891     if (!skipCall) {
    892         result = get_dispatch_table(object_tracker_device_table_map, device)
    893                      ->FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
    894     }
    895 
    896     lock.lock();
    897     for (uint32_t i = 0; i < count; i++) {
    898         free_descriptor_set(device, pDescriptorSets[i]);
    899     }
    900     return result;
    901 }
    902 
    903 void explicit_DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) {
    904     bool skipCall = VK_FALSE;
    905     std::unique_lock<std::mutex> lock(global_lock);
    906     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    907     skipCall |= validate_descriptor_pool(device, descriptorPool, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, false);
    908     lock.unlock();
    909     if (skipCall) {
    910         return;
    911     }
    912     // A DescriptorPool's descriptor sets are implicitly deleted when the pool is deleted.
    913     // Remove this pool's descriptor sets from our descriptorSet map.
    914     lock.lock();
    915     std::unordered_map<uint64_t, OBJTRACK_NODE *>::iterator itr = VkDescriptorSetMap.begin();
    916     while (itr != VkDescriptorSetMap.end()) {
    917         OBJTRACK_NODE *pNode = (*itr).second;
    918         auto del_itr = itr++;
    919         if (pNode->parentObj == (uint64_t)(descriptorPool)) {
    920             destroy_descriptor_set(device, (VkDescriptorSet)((*del_itr).first));
    921         }
    922     }
    923     destroy_descriptor_pool(device, descriptorPool);
    924     lock.unlock();
    925     get_dispatch_table(object_tracker_device_table_map, device)->DestroyDescriptorPool(device, descriptorPool, pAllocator);
    926 }
    927 
    928 void explicit_DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
    929     bool skipCall = false;
    930     std::unique_lock<std::mutex> lock(global_lock);
    931     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    932     skipCall |= validate_command_pool(device, commandPool, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, false);
    933     lock.unlock();
    934     if (skipCall) {
    935         return;
    936     }
    937     lock.lock();
    938     // A CommandPool's command buffers are implicitly deleted when the pool is deleted.
    939     // Remove this pool's cmdBuffers from our cmd buffer map.
    940     std::unordered_map<uint64_t, OBJTRACK_NODE *>::iterator itr = VkCommandBufferMap.begin();
    941     std::unordered_map<uint64_t, OBJTRACK_NODE *>::iterator del_itr;
    942     while (itr != VkCommandBufferMap.end()) {
    943         OBJTRACK_NODE *pNode = (*itr).second;
    944         del_itr = itr++;
    945         if (pNode->parentObj == (uint64_t)(commandPool)) {
    946             skipCall |= validate_command_buffer(device, commandPool, reinterpret_cast<VkCommandBuffer>((*del_itr).first));
    947             free_command_buffer(device, reinterpret_cast<VkCommandBuffer>((*del_itr).first));
    948         }
    949     }
    950     destroy_command_pool(device, commandPool);
    951     lock.unlock();
    952     get_dispatch_table(object_tracker_device_table_map, device)->DestroyCommandPool(device, commandPool, pAllocator);
    953 }
    954 
    955 VkResult explicit_GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount, VkImage *pSwapchainImages) {
    956     bool skipCall = VK_FALSE;
    957     std::unique_lock<std::mutex> lock(global_lock);
    958     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    959     lock.unlock();
    960     if (skipCall)
    961         return VK_ERROR_VALIDATION_FAILED_EXT;
    962 
    963     VkResult result = get_dispatch_table(object_tracker_device_table_map, device)
    964                           ->GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
    965 
    966     if (pSwapchainImages != NULL) {
    967         lock.lock();
    968         for (uint32_t i = 0; i < *pCount; i++) {
    969             create_swapchain_image_obj(device, pSwapchainImages[i], swapchain);
    970         }
    971         lock.unlock();
    972     }
    973     return result;
    974 }
    975 
    976 // TODO: Add special case to codegen to cover validating all the pipelines instead of just the first
    977 VkResult explicit_CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
    978                                           const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
    979                                           VkPipeline *pPipelines) {
    980     bool skipCall = VK_FALSE;
    981     std::unique_lock<std::mutex> lock(global_lock);
    982     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
    983     if (pCreateInfos) {
    984         for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
    985             if (pCreateInfos[idx0].basePipelineHandle) {
    986                 skipCall |= validate_pipeline(device, pCreateInfos[idx0].basePipelineHandle,
    987                                               VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, true);
    988             }
    989             if (pCreateInfos[idx0].layout) {
    990                 skipCall |= validate_pipeline_layout(device, pCreateInfos[idx0].layout,
    991                                                      VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT, false);
    992             }
    993             if (pCreateInfos[idx0].pStages) {
    994                 for (uint32_t idx1 = 0; idx1 < pCreateInfos[idx0].stageCount; ++idx1) {
    995                     if (pCreateInfos[idx0].pStages[idx1].module) {
    996                         skipCall |= validate_shader_module(device, pCreateInfos[idx0].pStages[idx1].module,
    997                                                            VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT, false);
    998                     }
    999                 }
   1000             }
   1001             if (pCreateInfos[idx0].renderPass) {
   1002                 skipCall |=
   1003                     validate_render_pass(device, pCreateInfos[idx0].renderPass, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, false);
   1004             }
   1005         }
   1006     }
   1007     if (pipelineCache) {
   1008         skipCall |= validate_pipeline_cache(device, pipelineCache, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT, false);
   1009     }
   1010     lock.unlock();
   1011     if (skipCall)
   1012         return VK_ERROR_VALIDATION_FAILED_EXT;
   1013     VkResult result = get_dispatch_table(object_tracker_device_table_map, device)
   1014                           ->CreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
   1015     lock.lock();
   1016     if (result == VK_SUCCESS) {
   1017         for (uint32_t idx2 = 0; idx2 < createInfoCount; ++idx2) {
   1018             create_pipeline(device, pPipelines[idx2], VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT);
   1019         }
   1020     }
   1021     lock.unlock();
   1022     return result;
   1023 }
   1024 
   1025 // TODO: Add special case to codegen to cover validating all the pipelines instead of just the first
   1026 VkResult explicit_CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
   1027                                          const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
   1028                                          VkPipeline *pPipelines) {
   1029     bool skipCall = VK_FALSE;
   1030     std::unique_lock<std::mutex> lock(global_lock);
   1031     skipCall |= validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);
   1032     if (pCreateInfos) {
   1033         for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
   1034             if (pCreateInfos[idx0].basePipelineHandle) {
   1035                 skipCall |= validate_pipeline(device, pCreateInfos[idx0].basePipelineHandle,
   1036                                               VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, true);
   1037             }
   1038             if (pCreateInfos[idx0].layout) {
   1039                 skipCall |= validate_pipeline_layout(device, pCreateInfos[idx0].layout,
   1040                                                      VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT, false);
   1041             }
   1042             if (pCreateInfos[idx0].stage.module) {
   1043                 skipCall |= validate_shader_module(device, pCreateInfos[idx0].stage.module,
   1044                                                    VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT, false);
   1045             }
   1046         }
   1047     }
   1048     if (pipelineCache) {
   1049         skipCall |= validate_pipeline_cache(device, pipelineCache, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT, false);
   1050     }
   1051     lock.unlock();
   1052     if (skipCall)
   1053         return VK_ERROR_VALIDATION_FAILED_EXT;
   1054     VkResult result = get_dispatch_table(object_tracker_device_table_map, device)
   1055                           ->CreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
   1056     lock.lock();
   1057     if (result == VK_SUCCESS) {
   1058         for (uint32_t idx1 = 0; idx1 < createInfoCount; ++idx1) {
   1059             create_pipeline(device, pPipelines[idx1], VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT);
   1060         }
   1061     }
   1062     lock.unlock();
   1063     return result;
   1064 }
   1065 
   1066 } // namespace object_tracker
   1067