Add core validation for VK_KHR_get_display_properties2

This adds core validation for VK_KHR_get_display_properties2, which is
based on the existing validation for the corresponding functions in
VK_KHR_display. The VK_KHR_get_display_properties2 has no explicit VUs,
only implicit ones that correct generated in the param validation
layer.

This MR also adds object tracking for VkDisplayKHR and
VkDisplayModeKHR for both VK_KHR_display and
VK_KHR_get_display_properties2. Note that the lifetime of these objects
is tied to the physical device. They aren't "created" just queried by
the application. Similar to how VkQueue objects are with respect to a
VkDevice.

This has been tested with the Vulkan CTS
VK_KHR_get_display_properties2 tests and showed some valid usage
violations in the test. These violations are reported here
Tracker/vk-gl-cts#1155 (closed) and fixed here
https://gerrit.khronos.org/#/c/2507/.
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 2eb37ce..6509ed6 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -12561,23 +12561,41 @@
     return result;
 }
 
+VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                           uint32_t *pPropertyCount,
+                                                                           VkDisplayPlaneProperties2KHR *pProperties) {
+    VkResult result = VK_SUCCESS;
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+
+    result = instance_data->dispatch_table.GetPhysicalDeviceDisplayPlaneProperties2KHR(physicalDevice, pPropertyCount, pProperties);
+
+    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
+        PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(instance_data, physicalDevice, pPropertyCount,
+                                                                 (pProperties) ? &pProperties->displayPlaneProperties : 0);
+    }
+
+    return result;
+}
+
 static bool ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_layer_data *instance_data,
                                                                     VkPhysicalDevice physicalDevice, uint32_t planeIndex,
                                                                     const char *api_name) {
     bool skip = false;
     auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
     if (physical_device_state->vkGetPhysicalDeviceDisplayPlanePropertiesKHRState == UNCALLED) {
-        skip |= log_msg(
-            instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
-            HandleToUint64(physicalDevice), SWAPCHAIN_GET_SUPPORTED_DISPLAYS_WITHOUT_QUERY,
-            "Potential problem with calling %s() without first querying vkGetPhysicalDeviceDisplayPlanePropertiesKHR.", api_name);
+        skip |=
+            log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                    HandleToUint64(physicalDevice), SWAPCHAIN_GET_SUPPORTED_DISPLAYS_WITHOUT_QUERY,
+                    "Potential problem with calling %s() without first querying vkGetPhysicalDeviceDisplayPlanePropertiesKHR "
+                    "or vkGetPhysicalDeviceDisplayPlaneProperties2KHR.",
+                    api_name);
     } else {
         if (planeIndex >= physical_device_state->display_plane_property_count) {
             skip |= log_msg(
                 instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
                 HandleToUint64(physicalDevice), "VUID-vkGetDisplayPlaneSupportedDisplaysKHR-planeIndex-01249",
-                "%s(): planeIndex must be in the range [0, %d] that was returned by vkGetPhysicalDeviceDisplayPlanePropertiesKHR. "
-                "Do you have the plane index hardcoded?",
+                "%s(): planeIndex must be in the range [0, %d] that was returned by vkGetPhysicalDeviceDisplayPlanePropertiesKHR "
+                "or vkGetPhysicalDeviceDisplayPlaneProperties2KHR. Do you have the plane index hardcoded?",
                 api_name, physical_device_state->display_plane_property_count - 1);
         }
     }
@@ -12627,6 +12645,20 @@
     return result;
 }
 
+VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice,
+                                                               const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
+                                                               VkDisplayPlaneCapabilities2KHR *pCapabilities) {
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    bool skip = PreCallValidateGetDisplayPlaneCapabilitiesKHR(instance_data, physicalDevice, pDisplayPlaneInfo->planeIndex);
+
+    if (!skip) {
+        result = instance_data->dispatch_table.GetDisplayPlaneCapabilities2KHR(physicalDevice, pDisplayPlaneInfo, pCapabilities);
+    }
+
+    return result;
+}
+
 VKAPI_ATTR VkResult VKAPI_CALL DebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
     unique_lock_t lock(global_lock);
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
@@ -13073,8 +13105,10 @@
     {"vkDestroyDebugReportCallbackEXT", (void *)DestroyDebugReportCallbackEXT},
     {"vkDebugReportMessageEXT", (void *)DebugReportMessageEXT},
     {"vkGetPhysicalDeviceDisplayPlanePropertiesKHR", (void *)GetPhysicalDeviceDisplayPlanePropertiesKHR},
+    {"vkGetPhysicalDeviceDisplayPlaneProperties2KHR", (void *)GetPhysicalDeviceDisplayPlaneProperties2KHR},
     {"vkGetDisplayPlaneSupportedDisplaysKHR", (void *)GetDisplayPlaneSupportedDisplaysKHR},
     {"vkGetDisplayPlaneCapabilitiesKHR", (void *)GetDisplayPlaneCapabilitiesKHR},
+    {"vkGetDisplayPlaneCapabilities2KHR", (void *)GetDisplayPlaneCapabilities2KHR},
     {"vkImportSemaphoreFdKHR", (void *)ImportSemaphoreFdKHR},
     {"vkGetSemaphoreFdKHR", (void *)GetSemaphoreFdKHR},
     {"vkImportFenceFdKHR", (void *)ImportFenceFdKHR},
diff --git a/layers/object_tracker_utils.cpp b/layers/object_tracker_utils.cpp
index 5e96e81..e9b1796 100644
--- a/layers/object_tracker_utils.cpp
+++ b/layers/object_tracker_utils.cpp
@@ -1363,6 +1363,71 @@
     return instance_data->instance_dispatch_table.GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+                                                                      VkDisplayProperties2KHR *pProperties) {
+    bool skip = false;
+    {
+        std::lock_guard<std::mutex> lock(global_lock);
+        skip |=
+            ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false, kVUIDUndefined, kVUIDUndefined);
+    }
+    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    VkResult result = get_dispatch_table(ot_instance_table_map, physicalDevice)
+                          ->GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, pPropertyCount, pProperties);
+    if (pProperties && (VK_SUCCESS == result || VK_INCOMPLETE == result)) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        for (uint32_t index = 0; index < *pPropertyCount; ++index) {
+            CreateObject(physicalDevice, pProperties[index].displayProperties.display, kVulkanObjectTypeDisplayKHR, nullptr);
+        }
+    }
+
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+                                                                   uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
+    bool skip = false;
+    {
+        std::lock_guard<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
+                               "VUID-vkGetDisplayPlaneSupportedDisplaysKHR-physicalDevice-parameter", kVUIDUndefined);
+    }
+    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    VkResult result = get_dispatch_table(ot_instance_table_map, physicalDevice)
+                          ->GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, pDisplayCount, pDisplays);
+    if (pDisplays && (VK_SUCCESS == result || VK_INCOMPLETE == result)) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        for (uint32_t index = 0; index < *pDisplayCount; ++index) {
+            CreateObject(physicalDevice, pDisplays[index], kVulkanObjectTypeDisplayKHR, nullptr);
+        }
+    }
+
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                                            uint32_t *pPropertyCount, VkDisplayModeProperties2KHR *pProperties) {
+    bool skip = false;
+    {
+        std::lock_guard<std::mutex> lock(global_lock);
+        skip |=
+            ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false, kVUIDUndefined, kVUIDUndefined);
+        skip |= ValidateObject(physicalDevice, display, kVulkanObjectTypeDisplayKHR, false, kVUIDUndefined, kVUIDUndefined);
+    }
+    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    VkResult result = get_dispatch_table(ot_instance_table_map, physicalDevice)
+                          ->GetDisplayModeProperties2KHR(physicalDevice, display, pPropertyCount, pProperties);
+    if (pProperties && (VK_SUCCESS == result || VK_INCOMPLETE == result)) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        for (uint32_t index = 0; index < *pPropertyCount; ++index) {
+            CreateObject(physicalDevice, pProperties[index].displayModeProperties.displayMode, kVulkanObjectTypeDisplayModeKHR,
+                         nullptr);
+        }
+    }
+
+    return result;
+}
+
 }  // namespace object_tracker
 
 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
diff --git a/scripts/object_tracker_generator.py b/scripts/object_tracker_generator.py
index 710d1e9..0a6626a 100644
--- a/scripts/object_tracker_generator.py
+++ b/scripts/object_tracker_generator.py
@@ -188,6 +188,9 @@
             'vkCmdInsertDebugUtilsLabelEXT',
             'vkGetDisplayModePropertiesKHR',
             'vkGetPhysicalDeviceDisplayPropertiesKHR',
+            'vkGetPhysicalDeviceDisplayProperties2KHR',
+            'vkGetDisplayPlaneSupportedDisplaysKHR',
+            'vkGetDisplayModeProperties2KHR',
             ]
         # These VUIDS are not implicit, but are best handled in this layer. Codegen for vkDestroy calls will generate a key
         # which is translated here into a good VU.  Saves ~40 checks.