1*b7893ccfSSadaf Ebrahimi /* Copyright (c) 2015-2019 The Khronos Group Inc. 2*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2019 Valve Corporation 3*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2019 LunarG, Inc. 4*b7893ccfSSadaf Ebrahimi * Copyright (C) 2015-2019 Google Inc. 5*b7893ccfSSadaf Ebrahimi * 6*b7893ccfSSadaf Ebrahimi * Licensed under the Apache License, Version 2.0 (the "License"); 7*b7893ccfSSadaf Ebrahimi * you may not use this file except in compliance with the License. 8*b7893ccfSSadaf Ebrahimi * You may obtain a copy of the License at 9*b7893ccfSSadaf Ebrahimi * 10*b7893ccfSSadaf Ebrahimi * http://www.apache.org/licenses/LICENSE-2.0 11*b7893ccfSSadaf Ebrahimi * 12*b7893ccfSSadaf Ebrahimi * Unless required by applicable law or agreed to in writing, software 13*b7893ccfSSadaf Ebrahimi * distributed under the License is distributed on an "AS IS" BASIS, 14*b7893ccfSSadaf Ebrahimi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15*b7893ccfSSadaf Ebrahimi * See the License for the specific language governing permissions and 16*b7893ccfSSadaf Ebrahimi * limitations under the License. 17*b7893ccfSSadaf Ebrahimi * 18*b7893ccfSSadaf Ebrahimi * Author: Mark Lobodzinski <[email protected]> 19*b7893ccfSSadaf Ebrahimi * Author: Jon Ashburn <[email protected]> 20*b7893ccfSSadaf Ebrahimi * Author: Tobin Ehlis <[email protected]> 21*b7893ccfSSadaf Ebrahimi */ 22*b7893ccfSSadaf Ebrahimi 23*b7893ccfSSadaf Ebrahimi // shared_mutex support added in MSVC 2015 update 2 24*b7893ccfSSadaf Ebrahimi #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && NTDDI_VERSION > NTDDI_WIN10_RS2 25*b7893ccfSSadaf Ebrahimi #include <shared_mutex> 26*b7893ccfSSadaf Ebrahimi typedef std::shared_mutex object_lifetime_mutex_t; 27*b7893ccfSSadaf Ebrahimi typedef std::shared_lock<object_lifetime_mutex_t> read_object_lifetime_mutex_t; 28*b7893ccfSSadaf Ebrahimi typedef std::unique_lock<object_lifetime_mutex_t> write_object_lifetime_mutex_t; 29*b7893ccfSSadaf Ebrahimi #else 30*b7893ccfSSadaf Ebrahimi typedef std::mutex object_lifetime_mutex_t; 31*b7893ccfSSadaf Ebrahimi typedef std::unique_lock<object_lifetime_mutex_t> read_object_lifetime_mutex_t; 32*b7893ccfSSadaf Ebrahimi typedef std::unique_lock<object_lifetime_mutex_t> write_object_lifetime_mutex_t; 33*b7893ccfSSadaf Ebrahimi #endif 34*b7893ccfSSadaf Ebrahimi 35*b7893ccfSSadaf Ebrahimi // Suppress unused warning on Linux 36*b7893ccfSSadaf Ebrahimi #if defined(__GNUC__) 37*b7893ccfSSadaf Ebrahimi #define DECORATE_UNUSED __attribute__((unused)) 38*b7893ccfSSadaf Ebrahimi #else 39*b7893ccfSSadaf Ebrahimi #define DECORATE_UNUSED 40*b7893ccfSSadaf Ebrahimi #endif 41*b7893ccfSSadaf Ebrahimi 42*b7893ccfSSadaf Ebrahimi // clang-format off 43*b7893ccfSSadaf Ebrahimi static const char DECORATE_UNUSED *kVUID_ObjectTracker_Info = "UNASSIGNED-ObjectTracker-Info"; 44*b7893ccfSSadaf Ebrahimi static const char DECORATE_UNUSED *kVUID_ObjectTracker_InternalError = "UNASSIGNED-ObjectTracker-InternalError"; 45*b7893ccfSSadaf Ebrahimi static const char DECORATE_UNUSED *kVUID_ObjectTracker_ObjectLeak = "UNASSIGNED-ObjectTracker-ObjectLeak"; 46*b7893ccfSSadaf Ebrahimi static const char DECORATE_UNUSED *kVUID_ObjectTracker_UnknownObject = "UNASSIGNED-ObjectTracker-UnknownObject"; 47*b7893ccfSSadaf Ebrahimi // clang-format on 48*b7893ccfSSadaf Ebrahimi 49*b7893ccfSSadaf Ebrahimi #undef DECORATE_UNUSED 50*b7893ccfSSadaf Ebrahimi 51*b7893ccfSSadaf Ebrahimi extern uint64_t object_track_index; 52*b7893ccfSSadaf Ebrahimi 53*b7893ccfSSadaf Ebrahimi // Object Status -- used to track state of individual objects 54*b7893ccfSSadaf Ebrahimi typedef VkFlags ObjectStatusFlags; 55*b7893ccfSSadaf Ebrahimi enum ObjectStatusFlagBits { 56*b7893ccfSSadaf Ebrahimi OBJSTATUS_NONE = 0x00000000, // No status is set 57*b7893ccfSSadaf Ebrahimi OBJSTATUS_COMMAND_BUFFER_SECONDARY = 0x00000001, // Command Buffer is of type SECONDARY 58*b7893ccfSSadaf Ebrahimi OBJSTATUS_CUSTOM_ALLOCATOR = 0x00000002, // Allocated with custom allocator 59*b7893ccfSSadaf Ebrahimi }; 60*b7893ccfSSadaf Ebrahimi 61*b7893ccfSSadaf Ebrahimi // Object and state information structure 62*b7893ccfSSadaf Ebrahimi struct ObjTrackState { 63*b7893ccfSSadaf Ebrahimi uint64_t handle; // Object handle (new) 64*b7893ccfSSadaf Ebrahimi VulkanObjectType object_type; // Object type identifier 65*b7893ccfSSadaf Ebrahimi ObjectStatusFlags status; // Object state 66*b7893ccfSSadaf Ebrahimi uint64_t parent_object; // Parent object 67*b7893ccfSSadaf Ebrahimi std::unique_ptr<std::unordered_set<uint64_t> > child_objects; // Child objects (used for VkDescriptorPool only) 68*b7893ccfSSadaf Ebrahimi }; 69*b7893ccfSSadaf Ebrahimi 70*b7893ccfSSadaf Ebrahimi typedef vl_concurrent_unordered_map<uint64_t, std::shared_ptr<ObjTrackState>, 6> object_map_type; 71*b7893ccfSSadaf Ebrahimi 72*b7893ccfSSadaf Ebrahimi class ObjectLifetimes : public ValidationObject { 73*b7893ccfSSadaf Ebrahimi public: 74*b7893ccfSSadaf Ebrahimi // Override chassis read/write locks for this validation object 75*b7893ccfSSadaf Ebrahimi // This override takes a deferred lock. i.e. it is not acquired. 76*b7893ccfSSadaf Ebrahimi // This class does its own locking with a shared mutex. write_lock()77*b7893ccfSSadaf Ebrahimi virtual std::unique_lock<std::mutex> write_lock() { 78*b7893ccfSSadaf Ebrahimi return std::unique_lock<std::mutex>(validation_object_mutex, std::defer_lock); 79*b7893ccfSSadaf Ebrahimi } 80*b7893ccfSSadaf Ebrahimi 81*b7893ccfSSadaf Ebrahimi object_lifetime_mutex_t object_lifetime_mutex; write_shared_lock()82*b7893ccfSSadaf Ebrahimi write_object_lifetime_mutex_t write_shared_lock() { return write_object_lifetime_mutex_t(object_lifetime_mutex); } read_shared_lock()83*b7893ccfSSadaf Ebrahimi read_object_lifetime_mutex_t read_shared_lock() { return read_object_lifetime_mutex_t(object_lifetime_mutex); } 84*b7893ccfSSadaf Ebrahimi 85*b7893ccfSSadaf Ebrahimi std::atomic<uint64_t> num_objects[kVulkanObjectTypeMax + 1]; 86*b7893ccfSSadaf Ebrahimi std::atomic<uint64_t> num_total_objects; 87*b7893ccfSSadaf Ebrahimi // Vector of unordered_maps per object type to hold ObjTrackState info 88*b7893ccfSSadaf Ebrahimi object_map_type object_map[kVulkanObjectTypeMax + 1]; 89*b7893ccfSSadaf Ebrahimi // Special-case map for swapchain images 90*b7893ccfSSadaf Ebrahimi object_map_type swapchainImageMap; 91*b7893ccfSSadaf Ebrahimi 92*b7893ccfSSadaf Ebrahimi // Constructor for object lifetime tracking ObjectLifetimes()93*b7893ccfSSadaf Ebrahimi ObjectLifetimes() : num_objects{}, num_total_objects(0) {} 94*b7893ccfSSadaf Ebrahimi InsertObject(object_map_type & map,uint64_t object_handle,VulkanObjectType object_type,std::shared_ptr<ObjTrackState> pNode)95*b7893ccfSSadaf Ebrahimi void InsertObject(object_map_type &map, uint64_t object_handle, VulkanObjectType object_type, 96*b7893ccfSSadaf Ebrahimi std::shared_ptr<ObjTrackState> pNode) { 97*b7893ccfSSadaf Ebrahimi bool inserted = map.insert(object_handle, pNode); 98*b7893ccfSSadaf Ebrahimi if (!inserted) { 99*b7893ccfSSadaf Ebrahimi // The object should not already exist. If we couldn't add it to the map, there was probably 100*b7893ccfSSadaf Ebrahimi // a race condition in the app. Report an error and move on. 101*b7893ccfSSadaf Ebrahimi VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type]; 102*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, kVUID_ObjectTracker_Info, 103*b7893ccfSSadaf Ebrahimi "Couldn't insert %s Object 0x%" PRIxLEAST64 104*b7893ccfSSadaf Ebrahimi ", already existed. This should not happen and may indicate a " 105*b7893ccfSSadaf Ebrahimi "race condition in the application.", 106*b7893ccfSSadaf Ebrahimi object_string[object_type], object_handle); 107*b7893ccfSSadaf Ebrahimi } 108*b7893ccfSSadaf Ebrahimi } 109*b7893ccfSSadaf Ebrahimi 110*b7893ccfSSadaf Ebrahimi bool DeviceReportUndestroyedObjects(VkDevice device, VulkanObjectType object_type, const std::string &error_code); 111*b7893ccfSSadaf Ebrahimi void DeviceDestroyUndestroyedObjects(VkDevice device, VulkanObjectType object_type); 112*b7893ccfSSadaf Ebrahimi void CreateQueue(VkDevice device, VkQueue vkObj); 113*b7893ccfSSadaf Ebrahimi void AllocateCommandBuffer(VkDevice device, const VkCommandPool command_pool, const VkCommandBuffer command_buffer, 114*b7893ccfSSadaf Ebrahimi VkCommandBufferLevel level); 115*b7893ccfSSadaf Ebrahimi void AllocateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set); 116*b7893ccfSSadaf Ebrahimi void CreateSwapchainImageObject(VkDevice dispatchable_object, VkImage swapchain_image, VkSwapchainKHR swapchain); 117*b7893ccfSSadaf Ebrahimi bool ReportUndestroyedObjects(VkDevice device, const std::string &error_code); 118*b7893ccfSSadaf Ebrahimi void DestroyUndestroyedObjects(VkDevice device); 119*b7893ccfSSadaf Ebrahimi bool ValidateDeviceObject(const VulkanTypedHandle &device_typed, const char *invalid_handle_code, 120*b7893ccfSSadaf Ebrahimi const char *wrong_device_code); 121*b7893ccfSSadaf Ebrahimi void DestroyQueueDataStructures(VkDevice device); 122*b7893ccfSSadaf Ebrahimi bool ValidateCommandBuffer(VkDevice device, VkCommandPool command_pool, VkCommandBuffer command_buffer); 123*b7893ccfSSadaf Ebrahimi bool ValidateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set); 124*b7893ccfSSadaf Ebrahimi bool ValidateSamplerObjects(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo); 125*b7893ccfSSadaf Ebrahimi template <typename DispObj> 126*b7893ccfSSadaf Ebrahimi bool ValidateDescriptorWrite(DispObj disp, VkWriteDescriptorSet const *desc, bool isPush); 127*b7893ccfSSadaf Ebrahimi GetObjectLifetimeData(std::vector<ValidationObject * > & object_dispatch)128*b7893ccfSSadaf Ebrahimi ObjectLifetimes *GetObjectLifetimeData(std::vector<ValidationObject *> &object_dispatch) { 129*b7893ccfSSadaf Ebrahimi for (auto layer_object : object_dispatch) { 130*b7893ccfSSadaf Ebrahimi if (layer_object->container_type == LayerObjectTypeObjectTracker) { 131*b7893ccfSSadaf Ebrahimi return (reinterpret_cast<ObjectLifetimes *>(layer_object)); 132*b7893ccfSSadaf Ebrahimi } 133*b7893ccfSSadaf Ebrahimi } 134*b7893ccfSSadaf Ebrahimi return nullptr; 135*b7893ccfSSadaf Ebrahimi }; 136*b7893ccfSSadaf Ebrahimi 137*b7893ccfSSadaf Ebrahimi template <typename T1, typename T2> ValidateObject(T1 dispatchable_object,T2 object,VulkanObjectType object_type,bool null_allowed,const char * invalid_handle_code,const char * wrong_device_code)138*b7893ccfSSadaf Ebrahimi bool ValidateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, bool null_allowed, 139*b7893ccfSSadaf Ebrahimi const char *invalid_handle_code, const char *wrong_device_code) { 140*b7893ccfSSadaf Ebrahimi if (null_allowed && (object == VK_NULL_HANDLE)) { 141*b7893ccfSSadaf Ebrahimi return false; 142*b7893ccfSSadaf Ebrahimi } 143*b7893ccfSSadaf Ebrahimi auto object_handle = HandleToUint64(object); 144*b7893ccfSSadaf Ebrahimi 145*b7893ccfSSadaf Ebrahimi if (object_type == kVulkanObjectTypeDevice) { 146*b7893ccfSSadaf Ebrahimi return ValidateDeviceObject(VulkanTypedHandle(object, object_type), invalid_handle_code, wrong_device_code); 147*b7893ccfSSadaf Ebrahimi } 148*b7893ccfSSadaf Ebrahimi 149*b7893ccfSSadaf Ebrahimi VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type]; 150*b7893ccfSSadaf Ebrahimi 151*b7893ccfSSadaf Ebrahimi // Look for object in object map 152*b7893ccfSSadaf Ebrahimi if (!object_map[object_type].contains(object_handle)) { 153*b7893ccfSSadaf Ebrahimi // If object is an image, also look for it in the swapchain image map 154*b7893ccfSSadaf Ebrahimi if ((object_type != kVulkanObjectTypeImage) || (swapchainImageMap.find(object_handle) == swapchainImageMap.end())) { 155*b7893ccfSSadaf Ebrahimi // Object not found, look for it in other device object maps 156*b7893ccfSSadaf Ebrahimi for (auto other_device_data : layer_data_map) { 157*b7893ccfSSadaf Ebrahimi for (auto layer_object_data : other_device_data.second->object_dispatch) { 158*b7893ccfSSadaf Ebrahimi if (layer_object_data->container_type == LayerObjectTypeObjectTracker) { 159*b7893ccfSSadaf Ebrahimi auto object_lifetime_data = reinterpret_cast<ObjectLifetimes *>(layer_object_data); 160*b7893ccfSSadaf Ebrahimi if (object_lifetime_data && (object_lifetime_data != this)) { 161*b7893ccfSSadaf Ebrahimi if (object_lifetime_data->object_map[object_type].find(object_handle) != 162*b7893ccfSSadaf Ebrahimi object_lifetime_data->object_map[object_type].end() || 163*b7893ccfSSadaf Ebrahimi (object_type == kVulkanObjectTypeImage && 164*b7893ccfSSadaf Ebrahimi object_lifetime_data->swapchainImageMap.find(object_handle) != 165*b7893ccfSSadaf Ebrahimi object_lifetime_data->swapchainImageMap.end())) { 166*b7893ccfSSadaf Ebrahimi // Object found on other device, report an error if object has a device parent error code 167*b7893ccfSSadaf Ebrahimi if ((wrong_device_code != kVUIDUndefined) && (object_type != kVulkanObjectTypeSurfaceKHR)) { 168*b7893ccfSSadaf Ebrahimi return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, 169*b7893ccfSSadaf Ebrahimi wrong_device_code, 170*b7893ccfSSadaf Ebrahimi "Object 0x%" PRIxLEAST64 171*b7893ccfSSadaf Ebrahimi " was not created, allocated or retrieved from the correct device.", 172*b7893ccfSSadaf Ebrahimi object_handle); 173*b7893ccfSSadaf Ebrahimi } else { 174*b7893ccfSSadaf Ebrahimi return false; 175*b7893ccfSSadaf Ebrahimi } 176*b7893ccfSSadaf Ebrahimi } 177*b7893ccfSSadaf Ebrahimi } 178*b7893ccfSSadaf Ebrahimi } 179*b7893ccfSSadaf Ebrahimi } 180*b7893ccfSSadaf Ebrahimi } 181*b7893ccfSSadaf Ebrahimi // Report an error if object was not found anywhere 182*b7893ccfSSadaf Ebrahimi return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, invalid_handle_code, 183*b7893ccfSSadaf Ebrahimi "Invalid %s Object 0x%" PRIxLEAST64 ".", object_string[object_type], object_handle); 184*b7893ccfSSadaf Ebrahimi } 185*b7893ccfSSadaf Ebrahimi } 186*b7893ccfSSadaf Ebrahimi return false; 187*b7893ccfSSadaf Ebrahimi } 188*b7893ccfSSadaf Ebrahimi 189*b7893ccfSSadaf Ebrahimi template <typename T1, typename T2> CreateObject(T1 dispatchable_object,T2 object,VulkanObjectType object_type,const VkAllocationCallbacks * pAllocator)190*b7893ccfSSadaf Ebrahimi void CreateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, const VkAllocationCallbacks *pAllocator) { 191*b7893ccfSSadaf Ebrahimi uint64_t object_handle = HandleToUint64(object); 192*b7893ccfSSadaf Ebrahimi bool custom_allocator = (pAllocator != nullptr); 193*b7893ccfSSadaf Ebrahimi if (!object_map[object_type].contains(object_handle)) { 194*b7893ccfSSadaf Ebrahimi auto pNewObjNode = std::make_shared<ObjTrackState>(); 195*b7893ccfSSadaf Ebrahimi pNewObjNode->object_type = object_type; 196*b7893ccfSSadaf Ebrahimi pNewObjNode->status = custom_allocator ? OBJSTATUS_CUSTOM_ALLOCATOR : OBJSTATUS_NONE; 197*b7893ccfSSadaf Ebrahimi pNewObjNode->handle = object_handle; 198*b7893ccfSSadaf Ebrahimi 199*b7893ccfSSadaf Ebrahimi InsertObject(object_map[object_type], object_handle, object_type, pNewObjNode); 200*b7893ccfSSadaf Ebrahimi num_objects[object_type]++; 201*b7893ccfSSadaf Ebrahimi num_total_objects++; 202*b7893ccfSSadaf Ebrahimi 203*b7893ccfSSadaf Ebrahimi if (object_type == kVulkanObjectTypeDescriptorPool) { 204*b7893ccfSSadaf Ebrahimi pNewObjNode->child_objects.reset(new std::unordered_set<uint64_t>); 205*b7893ccfSSadaf Ebrahimi } 206*b7893ccfSSadaf Ebrahimi } 207*b7893ccfSSadaf Ebrahimi } 208*b7893ccfSSadaf Ebrahimi 209*b7893ccfSSadaf Ebrahimi template <typename T1> DestroyObjectSilently(T1 object,VulkanObjectType object_type)210*b7893ccfSSadaf Ebrahimi void DestroyObjectSilently(T1 object, VulkanObjectType object_type) { 211*b7893ccfSSadaf Ebrahimi auto object_handle = HandleToUint64(object); 212*b7893ccfSSadaf Ebrahimi assert(object_handle != VK_NULL_HANDLE); 213*b7893ccfSSadaf Ebrahimi 214*b7893ccfSSadaf Ebrahimi auto item = object_map[object_type].pop(object_handle); 215*b7893ccfSSadaf Ebrahimi if (item == object_map[object_type].end()) { 216*b7893ccfSSadaf Ebrahimi // We've already checked that the object exists. If we couldn't find and atomically remove it 217*b7893ccfSSadaf Ebrahimi // from the map, there must have been a race condition in the app. Report an error and move on. 218*b7893ccfSSadaf Ebrahimi VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type]; 219*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, kVUID_ObjectTracker_Info, 220*b7893ccfSSadaf Ebrahimi "Couldn't destroy %s Object 0x%" PRIxLEAST64 221*b7893ccfSSadaf Ebrahimi ", not found. This should not happen and may indicate a " 222*b7893ccfSSadaf Ebrahimi "race condition in the application.", 223*b7893ccfSSadaf Ebrahimi object_string[object_type], object_handle); 224*b7893ccfSSadaf Ebrahimi return; 225*b7893ccfSSadaf Ebrahimi } 226*b7893ccfSSadaf Ebrahimi assert(num_total_objects > 0); 227*b7893ccfSSadaf Ebrahimi 228*b7893ccfSSadaf Ebrahimi num_total_objects--; 229*b7893ccfSSadaf Ebrahimi assert(num_objects[item->second->object_type] > 0); 230*b7893ccfSSadaf Ebrahimi 231*b7893ccfSSadaf Ebrahimi num_objects[item->second->object_type]--; 232*b7893ccfSSadaf Ebrahimi } 233*b7893ccfSSadaf Ebrahimi 234*b7893ccfSSadaf Ebrahimi template <typename T1, typename T2> RecordDestroyObject(T1 dispatchable_object,T2 object,VulkanObjectType object_type)235*b7893ccfSSadaf Ebrahimi void RecordDestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type) { 236*b7893ccfSSadaf Ebrahimi auto object_handle = HandleToUint64(object); 237*b7893ccfSSadaf Ebrahimi if (object_handle != VK_NULL_HANDLE) { 238*b7893ccfSSadaf Ebrahimi if (object_map[object_type].contains(object_handle)) { 239*b7893ccfSSadaf Ebrahimi DestroyObjectSilently(object, object_type); 240*b7893ccfSSadaf Ebrahimi } 241*b7893ccfSSadaf Ebrahimi } 242*b7893ccfSSadaf Ebrahimi } 243*b7893ccfSSadaf Ebrahimi 244*b7893ccfSSadaf Ebrahimi template <typename T1, typename T2> ValidateDestroyObject(T1 dispatchable_object,T2 object,VulkanObjectType object_type,const VkAllocationCallbacks * pAllocator,const char * expected_custom_allocator_code,const char * expected_default_allocator_code)245*b7893ccfSSadaf Ebrahimi bool ValidateDestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, 246*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, const char *expected_custom_allocator_code, 247*b7893ccfSSadaf Ebrahimi const char *expected_default_allocator_code) { 248*b7893ccfSSadaf Ebrahimi auto object_handle = HandleToUint64(object); 249*b7893ccfSSadaf Ebrahimi bool custom_allocator = pAllocator != nullptr; 250*b7893ccfSSadaf Ebrahimi VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type]; 251*b7893ccfSSadaf Ebrahimi bool skip = false; 252*b7893ccfSSadaf Ebrahimi 253*b7893ccfSSadaf Ebrahimi if ((expected_custom_allocator_code != kVUIDUndefined || expected_default_allocator_code != kVUIDUndefined) && 254*b7893ccfSSadaf Ebrahimi object_handle != VK_NULL_HANDLE) { 255*b7893ccfSSadaf Ebrahimi auto item = object_map[object_type].find(object_handle); 256*b7893ccfSSadaf Ebrahimi if (item != object_map[object_type].end()) { 257*b7893ccfSSadaf Ebrahimi auto allocated_with_custom = (item->second->status & OBJSTATUS_CUSTOM_ALLOCATOR) ? true : false; 258*b7893ccfSSadaf Ebrahimi if (allocated_with_custom && !custom_allocator && expected_custom_allocator_code != kVUIDUndefined) { 259*b7893ccfSSadaf Ebrahimi // This check only verifies that custom allocation callbacks were provided to both Create and Destroy calls, 260*b7893ccfSSadaf Ebrahimi // it cannot verify that these allocation callbacks are compatible with each other. 261*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, 262*b7893ccfSSadaf Ebrahimi expected_custom_allocator_code, 263*b7893ccfSSadaf Ebrahimi "Custom allocator not specified while destroying %s obj 0x%" PRIxLEAST64 264*b7893ccfSSadaf Ebrahimi " but specified at creation.", 265*b7893ccfSSadaf Ebrahimi object_string[object_type], object_handle); 266*b7893ccfSSadaf Ebrahimi } else if (!allocated_with_custom && custom_allocator && expected_default_allocator_code != kVUIDUndefined) { 267*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, 268*b7893ccfSSadaf Ebrahimi expected_default_allocator_code, 269*b7893ccfSSadaf Ebrahimi "Custom allocator specified while destroying %s obj 0x%" PRIxLEAST64 270*b7893ccfSSadaf Ebrahimi " but not specified at creation.", 271*b7893ccfSSadaf Ebrahimi object_string[object_type], object_handle); 272*b7893ccfSSadaf Ebrahimi } 273*b7893ccfSSadaf Ebrahimi } 274*b7893ccfSSadaf Ebrahimi } 275*b7893ccfSSadaf Ebrahimi return skip; 276*b7893ccfSSadaf Ebrahimi } 277*b7893ccfSSadaf Ebrahimi 278*b7893ccfSSadaf Ebrahimi #include "object_tracker.h" 279*b7893ccfSSadaf Ebrahimi }; 280