xref: /aosp_15_r20/external/vulkan-validation-layers/layers/object_lifetime_validation.h (revision b7893ccf7851cd6a48cc5a1e965257d8a5cdcc70)
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