Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2017 The Khronos Group Inc.
      2  * Copyright (c) 2015-2017 Valve Corporation
      3  * Copyright (c) 2015-2017 LunarG, Inc.
      4  * Copyright (C) 2015-2017 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: Mark Lobodzinski <mark (at) lunarg.com>
     19  * Author: Jon Ashburn <jon (at) lunarg.com>
     20  * Author: Tobin Ehlis <tobin (at) lunarg.com>
     21  */
     22 
     23 #include <mutex>
     24 #include <cinttypes>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <unordered_map>
     29 
     30 #include "vk_loader_platform.h"
     31 #include "vulkan/vulkan.h"
     32 #include "vk_layer_config.h"
     33 #include "vk_layer_data.h"
     34 #include "vk_layer_logging.h"
     35 #include "vk_layer_table.h"
     36 #include "vk_object_types.h"
     37 #include "vulkan/vk_layer.h"
     38 #include "vk_object_types.h"
     39 #include "vk_enum_string_helper.h"
     40 #include "vk_layer_extension_utils.h"
     41 #include "vk_layer_table.h"
     42 #include "vk_layer_utils.h"
     43 #include "vulkan/vk_layer.h"
     44 #include "vk_dispatch_table_helper.h"
     45 #include "vk_validation_error_messages.h"
     46 
     47 namespace object_tracker {
     48 
     49 // Object Tracker ERROR codes
     50 enum ObjectTrackerError {
     51     OBJTRACK_NONE,            // Used for INFO & other non-error messages
     52     OBJTRACK_UNKNOWN_OBJECT,  // Updating uses of object that's not in global object list
     53     OBJTRACK_INTERNAL_ERROR,  // Bug with data tracking within the layer
     54     OBJTRACK_OBJECT_LEAK,     // OBJECT was not correctly freed/destroyed
     55 };
     56 
     57 // Object Status -- used to track state of individual objects
     58 typedef VkFlags ObjectStatusFlags;
     59 enum ObjectStatusFlagBits {
     60     OBJSTATUS_NONE = 0x00000000,                      // No status is set
     61     OBJSTATUS_FENCE_IS_SUBMITTED = 0x00000001,        // Fence has been submitted
     62     OBJSTATUS_VIEWPORT_BOUND = 0x00000002,            // Viewport state object has been bound
     63     OBJSTATUS_RASTER_BOUND = 0x00000004,              // Viewport state object has been bound
     64     OBJSTATUS_COLOR_BLEND_BOUND = 0x00000008,         // Viewport state object has been bound
     65     OBJSTATUS_DEPTH_STENCIL_BOUND = 0x00000010,       // Viewport state object has been bound
     66     OBJSTATUS_GPU_MEM_MAPPED = 0x00000020,            // Memory object is currently mapped
     67     OBJSTATUS_COMMAND_BUFFER_SECONDARY = 0x00000040,  // Command Buffer is of type SECONDARY
     68     OBJSTATUS_CUSTOM_ALLOCATOR = 0x00000080,          // Allocated with custom allocator
     69 };
     70 
     71 // Object and state information structure
     72 struct ObjTrackState {
     73     uint64_t handle;               // Object handle (new)
     74     VulkanObjectType object_type;  // Object type identifier
     75     ObjectStatusFlags status;      // Object state
     76     uint64_t parent_object;        // Parent object
     77 };
     78 
     79 // Track Queue information
     80 struct ObjTrackQueueInfo {
     81     uint32_t queue_node_index;
     82     VkQueue queue;
     83 };
     84 
     85 // Layer name string to be logged with validation messages.
     86 const char LayerName[] = "ObjectTracker";
     87 
     88 typedef std::unordered_map<uint64_t, ObjTrackState *> object_map_type;
     89 
     90 struct layer_data {
     91     VkInstance instance;
     92     VkPhysicalDevice physical_device;
     93 
     94     uint64_t num_objects[kVulkanObjectTypeMax + 1];
     95     uint64_t num_total_objects;
     96 
     97     debug_report_data *report_data;
     98     std::vector<VkDebugReportCallbackEXT> logging_callback;
     99     // The following are for keeping track of the temporary callbacks that can
    100     // be used in vkCreateInstance and vkDestroyInstance:
    101     uint32_t num_tmp_callbacks;
    102     VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
    103     VkDebugReportCallbackEXT *tmp_callbacks;
    104 
    105     std::vector<VkQueueFamilyProperties> queue_family_properties;
    106 
    107     // Vector of unordered_maps per object type to hold ObjTrackState info
    108     std::vector<object_map_type> object_map;
    109     // Special-case map for swapchain images
    110     std::unordered_map<uint64_t, ObjTrackState *> swapchainImageMap;
    111     // Map of queue information structures, one per queue
    112     std::unordered_map<VkQueue, ObjTrackQueueInfo *> queue_info_map;
    113 
    114     VkLayerDispatchTable dispatch_table;
    115     // Default constructor
    116     layer_data()
    117         : instance(nullptr),
    118           physical_device(nullptr),
    119           num_objects{},
    120           num_total_objects(0),
    121           report_data(nullptr),
    122           num_tmp_callbacks(0),
    123           tmp_dbg_create_infos(nullptr),
    124           tmp_callbacks(nullptr),
    125           object_map{},
    126           dispatch_table{} {
    127         object_map.resize(kVulkanObjectTypeMax + 1);
    128     }
    129 };
    130 
    131 extern std::unordered_map<void *, layer_data *> layer_data_map;
    132 extern device_table_map ot_device_table_map;
    133 extern instance_table_map ot_instance_table_map;
    134 extern std::mutex global_lock;
    135 extern uint64_t object_track_index;
    136 extern uint32_t loader_layer_if_version;
    137 extern const std::unordered_map<std::string, void *> name_to_funcptr_map;
    138 
    139 void DeviceReportUndestroyedObjects(VkDevice device, VulkanObjectType object_type, enum UNIQUE_VALIDATION_ERROR_CODE error_code);
    140 void CreateQueue(VkDevice device, VkQueue vkObj);
    141 void AddQueueInfo(VkDevice device, uint32_t queue_node_index, VkQueue queue);
    142 void ValidateQueueFlags(VkQueue queue, const char *function);
    143 void AllocateCommandBuffer(VkDevice device, const VkCommandPool command_pool, const VkCommandBuffer command_buffer,
    144                            VkCommandBufferLevel level);
    145 void AllocateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set);
    146 void CreateSwapchainImageObject(VkDevice dispatchable_object, VkImage swapchain_image, VkSwapchainKHR swapchain);
    147 void ReportUndestroyedObjects(VkDevice device, UNIQUE_VALIDATION_ERROR_CODE error_code);
    148 bool ValidateDeviceObject(uint64_t device_handle, enum UNIQUE_VALIDATION_ERROR_CODE invalid_handle_code,
    149                           enum UNIQUE_VALIDATION_ERROR_CODE wrong_device_code);
    150 
    151 template <typename T1, typename T2>
    152 bool ValidateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, bool null_allowed,
    153                     enum UNIQUE_VALIDATION_ERROR_CODE invalid_handle_code, enum UNIQUE_VALIDATION_ERROR_CODE wrong_device_code) {
    154     if (null_allowed && (object == VK_NULL_HANDLE)) {
    155         return false;
    156     }
    157     auto object_handle = HandleToUint64(object);
    158 
    159     if (object_type == kVulkanObjectTypeDevice) {
    160         return ValidateDeviceObject(object_handle, invalid_handle_code, wrong_device_code);
    161     }
    162 
    163     VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
    164 
    165     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
    166     // Look for object in device object map
    167     if (device_data->object_map[object_type].find(object_handle) == device_data->object_map[object_type].end()) {
    168         // If object is an image, also look for it in the swapchain image map
    169         if ((object_type != kVulkanObjectTypeImage) ||
    170             (device_data->swapchainImageMap.find(object_handle) == device_data->swapchainImageMap.end())) {
    171             // Object not found, look for it in other device object maps
    172             for (auto other_device_data : layer_data_map) {
    173                 if (other_device_data.second != device_data) {
    174                     if (other_device_data.second->object_map[object_type].find(object_handle) !=
    175                             other_device_data.second->object_map[object_type].end() ||
    176                         (object_type == kVulkanObjectTypeImage && other_device_data.second->swapchainImageMap.find(object_handle) !=
    177                                                                       other_device_data.second->swapchainImageMap.end())) {
    178                         // Object found on other device, report an error if object has a device parent error code
    179                         if ((wrong_device_code != VALIDATION_ERROR_UNDEFINED) && (object_type != kVulkanObjectTypeSurfaceKHR)) {
    180                             return log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type,
    181                                            object_handle, __LINE__, wrong_device_code, LayerName,
    182                                            "Object 0x%" PRIxLEAST64
    183                                            " was not created, allocated or retrieved from the correct device. %s",
    184                                            object_handle, validation_error_map[wrong_device_code]);
    185                         } else {
    186                             return false;
    187                         }
    188                     }
    189                 }
    190             }
    191             // Report an error if object was not found anywhere
    192             return log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, __LINE__,
    193                            invalid_handle_code, LayerName, "Invalid %s Object 0x%" PRIxLEAST64 ". %s", object_string[object_type],
    194                            object_handle, validation_error_map[invalid_handle_code]);
    195         }
    196     }
    197     return false;
    198 }
    199 
    200 template <typename T1, typename T2>
    201 void CreateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, const VkAllocationCallbacks *pAllocator) {
    202     layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
    203 
    204     auto object_handle = HandleToUint64(object);
    205     bool custom_allocator = pAllocator != nullptr;
    206 
    207     if (!instance_data->object_map[object_type].count(object_handle)) {
    208         VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
    209         log_msg(instance_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, debug_object_type, object_handle, __LINE__,
    210                 OBJTRACK_NONE, LayerName, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++,
    211                 object_string[object_type], object_handle);
    212 
    213         ObjTrackState *pNewObjNode = new ObjTrackState;
    214         pNewObjNode->object_type = object_type;
    215         pNewObjNode->status = custom_allocator ? OBJSTATUS_CUSTOM_ALLOCATOR : OBJSTATUS_NONE;
    216         pNewObjNode->handle = object_handle;
    217 
    218         instance_data->object_map[object_type][object_handle] = pNewObjNode;
    219         instance_data->num_objects[object_type]++;
    220         instance_data->num_total_objects++;
    221     }
    222 }
    223 
    224 template <typename T1, typename T2>
    225 void DestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, const VkAllocationCallbacks *pAllocator,
    226                    enum UNIQUE_VALIDATION_ERROR_CODE expected_custom_allocator_code,
    227                    enum UNIQUE_VALIDATION_ERROR_CODE expected_default_allocator_code) {
    228     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
    229 
    230     auto object_handle = HandleToUint64(object);
    231     bool custom_allocator = pAllocator != nullptr;
    232     VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
    233 
    234     if (object_handle != VK_NULL_HANDLE) {
    235         auto item = device_data->object_map[object_type].find(object_handle);
    236         if (item != device_data->object_map[object_type].end()) {
    237             ObjTrackState *pNode = item->second;
    238             assert(device_data->num_total_objects > 0);
    239             device_data->num_total_objects--;
    240             assert(device_data->num_objects[pNode->object_type] > 0);
    241             device_data->num_objects[pNode->object_type]--;
    242 
    243             log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, debug_object_type, object_handle, __LINE__,
    244                     OBJTRACK_NONE, LayerName,
    245                     "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",
    246                     object_string[object_type], HandleToUint64(object), device_data->num_total_objects,
    247                     device_data->num_objects[pNode->object_type], object_string[object_type]);
    248 
    249             auto allocated_with_custom = (pNode->status & OBJSTATUS_CUSTOM_ALLOCATOR) ? true : false;
    250             if (allocated_with_custom && !custom_allocator && expected_custom_allocator_code != VALIDATION_ERROR_UNDEFINED) {
    251                 // This check only verifies that custom allocation callbacks were provided to both Create and Destroy calls,
    252                 // it cannot verify that these allocation callbacks are compatible with each other.
    253                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, __LINE__,
    254                         expected_custom_allocator_code, LayerName,
    255                         "Custom allocator not specified while destroying %s obj 0x%" PRIxLEAST64 " but specified at creation. %s",
    256                         object_string[object_type], object_handle, validation_error_map[expected_custom_allocator_code]);
    257             } else if (!allocated_with_custom && custom_allocator &&
    258                        expected_default_allocator_code != VALIDATION_ERROR_UNDEFINED) {
    259                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, __LINE__,
    260                         expected_default_allocator_code, LayerName,
    261                         "Custom allocator specified while destroying %s obj 0x%" PRIxLEAST64 " but not specified at creation. %s",
    262                         object_string[object_type], object_handle, validation_error_map[expected_default_allocator_code]);
    263             }
    264 
    265             delete pNode;
    266             device_data->object_map[object_type].erase(item);
    267         } else {
    268             log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, object_handle,
    269                     __LINE__, OBJTRACK_UNKNOWN_OBJECT, LayerName,
    270                     "Unable to remove %s obj 0x%" PRIxLEAST64 ". Was it created? Has it already been destroyed?",
    271                     object_string[object_type], object_handle);
    272         }
    273     }
    274 }
    275 
    276 }  // namespace object_tracker
    277