1 /* 2 * Copyright (c) 2021-2023 The Khronos Group Inc. 3 * Copyright (c) 2021-2023 Valve Corporation 4 * Copyright (c) 2021-2023 LunarG, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and/or associated documentation files (the "Materials"), to 8 * deal in the Materials without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Materials, and to permit persons to whom the Materials are 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice(s) and this permission notice shall be included in 14 * all copies or substantial portions of the Materials. 15 * 16 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 * 20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 23 * USE OR OTHER DEALINGS IN THE MATERIALS. 24 * 25 * Author: Charles Giessen <charles@lunarg.com> 26 */ 27 28 #pragma once 29 30 #include "test_util.h" 31 32 #include "layer/layer_util.h" 33 34 enum class CalledICDGIPA { not_called, vk_icd_gipa, vk_gipa }; 35 36 enum class CalledNegotiateInterface { not_called, vk_icd_negotiate, vk_icd_gipa_first }; 37 38 enum class InterfaceVersionCheck { 39 not_called, 40 loader_version_too_old, 41 loader_version_too_new, 42 icd_version_too_new, 43 version_is_supported 44 }; 45 46 // clang-format off 47 inline std::ostream& operator<<(std::ostream& os, const CalledICDGIPA& result) { 48 switch (result) { 49 case (CalledICDGIPA::not_called): return os << "CalledICDGIPA::not_called"; 50 case (CalledICDGIPA::vk_icd_gipa): return os << "CalledICDGIPA::vk_icd_gipa"; 51 case (CalledICDGIPA::vk_gipa): return os << "CalledICDGIPA::vk_gipa"; 52 } 53 return os << static_cast<uint32_t>(result); 54 } 55 inline std::ostream& operator<<(std::ostream& os, const CalledNegotiateInterface& result) { 56 switch (result) { 57 case (CalledNegotiateInterface::not_called): return os << "CalledNegotiateInterface::not_called"; 58 case (CalledNegotiateInterface::vk_icd_negotiate): return os << "CalledNegotiateInterface::vk_icd_negotiate"; 59 case (CalledNegotiateInterface::vk_icd_gipa_first): return os << "CalledNegotiateInterface::vk_icd_gipa_first"; 60 } 61 return os << static_cast<uint32_t>(result); 62 } 63 inline std::ostream& operator<<(std::ostream& os, const InterfaceVersionCheck& result) { 64 switch (result) { 65 case (InterfaceVersionCheck::not_called): return os << "InterfaceVersionCheck::not_called"; 66 case (InterfaceVersionCheck::loader_version_too_old): return os << "InterfaceVersionCheck::loader_version_too_old"; 67 case (InterfaceVersionCheck::loader_version_too_new): return os << "InterfaceVersionCheck::loader_version_too_new"; 68 case (InterfaceVersionCheck::icd_version_too_new): return os << "InterfaceVersionCheck::icd_version_too_new"; 69 case (InterfaceVersionCheck::version_is_supported): return os << "InterfaceVersionCheck::version_is_supported"; 70 } 71 return os << static_cast<uint32_t>(result); 72 } 73 // clang-format on 74 75 // Move only type because it holds a DispatchableHandle<VkPhysicalDevice> 76 struct PhysicalDevice { PhysicalDevicePhysicalDevice77 PhysicalDevice() {} PhysicalDevicePhysicalDevice78 PhysicalDevice(std::string name) : deviceName(name) {} PhysicalDevicePhysicalDevice79 PhysicalDevice(const char* name) : deviceName(name) {} 80 81 DispatchableHandle<VkPhysicalDevice> vk_physical_device; 82 BUILDER_VALUE(PhysicalDevice, std::string, deviceName, "") 83 BUILDER_VALUE(PhysicalDevice, VkPhysicalDeviceProperties, properties, {}) 84 BUILDER_VALUE(PhysicalDevice, VkPhysicalDeviceFeatures, features, {}) 85 BUILDER_VALUE(PhysicalDevice, VkPhysicalDeviceMemoryProperties, memory_properties, {}) 86 BUILDER_VALUE(PhysicalDevice, VkImageFormatProperties, image_format_properties, {}) 87 BUILDER_VALUE(PhysicalDevice, VkExternalMemoryProperties, external_memory_properties, {}) 88 BUILDER_VALUE(PhysicalDevice, VkExternalSemaphoreProperties, external_semaphore_properties, {}) 89 BUILDER_VALUE(PhysicalDevice, VkExternalFenceProperties, external_fence_properties, {}) 90 BUILDER_VALUE(PhysicalDevice, uint32_t, pci_bus, {}) 91 BUILDER_VECTORPhysicalDevice92 BUILDER_VECTOR(PhysicalDevice, MockQueueFamilyProperties, queue_family_properties, queue_family_properties) 93 BUILDER_VECTOR(PhysicalDevice, VkFormatProperties, format_properties, format_properties) 94 BUILDER_VECTOR(PhysicalDevice, VkSparseImageFormatProperties, sparse_image_format_properties, sparse_image_format_properties) 95 96 BUILDER_VECTOR(PhysicalDevice, Extension, extensions, extension) 97 98 BUILDER_VALUE(PhysicalDevice, VkSurfaceCapabilitiesKHR, surface_capabilities, {}) 99 BUILDER_VECTOR(PhysicalDevice, VkSurfaceFormatKHR, surface_formats, surface_format) 100 BUILDER_VECTOR(PhysicalDevice, VkPresentModeKHR, surface_present_modes, surface_present_mode) 101 BUILDER_VALUE(PhysicalDevice, VkSurfacePresentScalingCapabilitiesEXT, surface_present_scaling_capabilities, {}) 102 // No good way to make this a builder value. Each std::vector<VkPresentModeKHR> corresponds to each surface_present_modes 103 // element 104 std::vector<std::vector<VkPresentModeKHR>> surface_present_mode_compatibility{}; 105 BUILDER_VECTORPhysicalDevice106 BUILDER_VECTOR(PhysicalDevice, VkDisplayPropertiesKHR, display_properties, display_properties) 107 BUILDER_VECTOR(PhysicalDevice, VkDisplayPlanePropertiesKHR, display_plane_properties, display_plane_properties) 108 BUILDER_VECTOR(PhysicalDevice, VkDisplayKHR, displays, displays) 109 BUILDER_VECTOR(PhysicalDevice, VkDisplayModePropertiesKHR, display_mode_properties, display_mode_properties) 110 BUILDER_VALUE(PhysicalDevice, VkDisplayModeKHR, display_mode, {}) 111 BUILDER_VALUE(PhysicalDevice, VkDisplayPlaneCapabilitiesKHR, display_plane_capabilities, {}) 112 113 BUILDER_VALUE(PhysicalDevice, VkLayeredDriverUnderlyingApiMSFT, layered_driver_underlying_api, 114 VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT) 115 116 PhysicalDevice& set_api_version(uint32_t version) { 117 properties.apiVersion = version; 118 return *this; 119 } 120 finishPhysicalDevice121 PhysicalDevice&& finish() { return std::move(*this); } 122 123 // Objects created from this physical device 124 std::vector<VkDevice> device_handles; 125 std::vector<DeviceCreateInfo> device_create_infos; 126 std::vector<DispatchableHandle<VkQueue>> queue_handles; 127 128 // Unknown physical device functions. Add a `VulkanFunction` to this list which will be searched in 129 // vkGetInstanceProcAddr for custom_instance_functions and vk_icdGetPhysicalDeviceProcAddr for custom_physical_device_functions. 130 // To add unknown device functions, add it to the PhysicalDevice directly (in the known_device_functions member) 131 BUILDER_VECTOR(PhysicalDevice, VulkanFunction, custom_physical_device_functions, custom_physical_device_function) 132 133 // List of function names which are 'known' to the physical device but have test defined implementations 134 // The purpose of this list is so that vkGetDeviceProcAddr returns 'a real function pointer' in tests 135 // without actually implementing any of the logic inside of it. 136 BUILDER_VECTOR(PhysicalDevice, VulkanFunction, known_device_functions, device_function) 137 }; 138 139 struct PhysicalDeviceGroup { PhysicalDeviceGroupPhysicalDeviceGroup140 PhysicalDeviceGroup() {} PhysicalDeviceGroupPhysicalDeviceGroup141 PhysicalDeviceGroup(PhysicalDevice const& physical_device) { physical_device_handles.push_back(&physical_device); } PhysicalDeviceGroupPhysicalDeviceGroup142 PhysicalDeviceGroup(std::vector<PhysicalDevice*> const& physical_devices) { 143 physical_device_handles.insert(physical_device_handles.end(), physical_devices.begin(), physical_devices.end()); 144 } use_physical_devicePhysicalDeviceGroup145 PhysicalDeviceGroup& use_physical_device(PhysicalDevice const& physical_device) { 146 physical_device_handles.push_back(&physical_device); 147 return *this; 148 } 149 150 std::vector<PhysicalDevice const*> physical_device_handles; 151 VkBool32 subset_allocation = false; 152 }; 153 154 struct TestICD { 155 std::filesystem::path manifest_file_path; 156 157 BUILDER_VALUE(TestICD, bool, exposes_vk_icdNegotiateLoaderICDInterfaceVersion, true) 158 BUILDER_VALUE(TestICD, bool, exposes_vkEnumerateInstanceExtensionProperties, true) 159 BUILDER_VALUE(TestICD, bool, exposes_vkCreateInstance, true) 160 BUILDER_VALUE(TestICD, bool, exposes_vk_icdGetPhysicalDeviceProcAddr, true) 161 #if defined(WIN32) 162 BUILDER_VALUE(TestICD, bool, exposes_vk_icdEnumerateAdapterPhysicalDevices, true) 163 #endif 164 165 CalledICDGIPA called_vk_icd_gipa = CalledICDGIPA::not_called; 166 CalledNegotiateInterface called_negotiate_interface = CalledNegotiateInterface::not_called; 167 168 InterfaceVersionCheck interface_version_check = InterfaceVersionCheck::not_called; 169 BUILDER_VALUE(TestICD, uint32_t, min_icd_interface_version, 0) 170 BUILDER_VALUE(TestICD, uint32_t, max_icd_interface_version, 7) 171 uint32_t icd_interface_version_received = 0; 172 173 bool called_enumerate_adapter_physical_devices = false; 174 175 BUILDER_VALUE(TestICD, bool, enable_icd_wsi, false); 176 bool is_using_icd_wsi = false; 177 178 TestICD& setup_WSI(const char* api_selection = nullptr) { 179 enable_icd_wsi = true; 180 add_instance_extensions({"VK_KHR_surface", get_platform_wsi_extension(api_selection)}); 181 min_icd_interface_version = (3U < min_icd_interface_version) ? min_icd_interface_version : 3U; 182 return *this; 183 } 184 185 BUILDER_VALUE(TestICD, uint32_t, icd_api_version, VK_API_VERSION_1_0) 186 BUILDER_VECTOR(TestICD, LayerDefinition, instance_layers, instance_layer) 187 BUILDER_VECTOR(TestICD, Extension, instance_extensions, instance_extension) 188 std::vector<Extension> enabled_instance_extensions; 189 190 BUILDER_VECTOR_MOVE_ONLY(TestICD, PhysicalDevice, physical_devices, physical_device); 191 192 BUILDER_VECTOR(TestICD, PhysicalDeviceGroup, physical_device_groups, physical_device_group); 193 194 DispatchableHandle<VkInstance> instance_handle; 195 std::vector<DispatchableHandle<VkDevice>> device_handles; 196 std::vector<uint64_t> surface_handles; 197 std::vector<uint64_t> messenger_handles; 198 std::vector<uint64_t> callback_handles; 199 std::vector<uint64_t> swapchain_handles; 200 201 BUILDER_VALUE(TestICD, bool, can_query_vkEnumerateInstanceVersion, true); 202 BUILDER_VALUE(TestICD, bool, can_query_GetPhysicalDeviceFuncs, true); 203 204 // Unknown instance functions Add a `VulkanFunction` to this list which will be searched in 205 // vkGetInstanceProcAddr for custom_instance_functions and vk_icdGetPhysicalDeviceProcAddr for 206 // custom_physical_device_functions. To add unknown device functions, add it to the PhysicalDevice directly (in the 207 // known_device_functions member) 208 BUILDER_VECTOR(TestICD, VulkanFunction, custom_instance_functions, custom_instance_function) 209 210 // Must explicitely state support for the tooling info extension, that way we can control if vkGetInstanceProcAddr returns a 211 // function pointer for vkGetPhysicalDeviceToolPropertiesEXT or vkGetPhysicalDeviceToolProperties (core version) 212 BUILDER_VALUE(TestICD, bool, supports_tooling_info_ext, false); 213 BUILDER_VALUE(TestICD, bool, supports_tooling_info_core, false); 214 // List of tooling properties that this driver 'supports' 215 BUILDER_VECTOR(TestICD, VkPhysicalDeviceToolPropertiesEXT, tooling_properties, tooling_property) 216 std::vector<DispatchableHandle<VkCommandBuffer>> allocated_command_buffers; 217 218 VkInstanceCreateFlags passed_in_instance_create_flags{}; 219 220 BUILDER_VALUE(TestICD, VkResult, enum_physical_devices_return_code, VK_SUCCESS); 221 BUILDER_VALUE(TestICD, VkResult, enum_adapter_physical_devices_return_code, VK_SUCCESS); 222 GetPhysDeviceTestICD223 PhysicalDevice& GetPhysDevice(VkPhysicalDevice physicalDevice) { 224 for (auto& phys_dev : physical_devices) { 225 if (phys_dev.vk_physical_device.handle == physicalDevice) return phys_dev; 226 } 227 assert(false && "vkPhysicalDevice not found!"); 228 return physical_devices[0]; 229 } 230 GetVkInstanceCreateInfoTestICD231 InstanceCreateInfo GetVkInstanceCreateInfo() { 232 InstanceCreateInfo info; 233 for (auto& layer : instance_layers) info.enabled_layers.push_back(layer.layerName.data()); 234 for (auto& ext : instance_extensions) info.enabled_extensions.push_back(ext.extensionName.data()); 235 return info; 236 } 237 238 struct FindDevice { 239 bool found = false; 240 uint32_t phys_dev_index = 0; 241 uint32_t dev_index = 0; 242 }; 243 lookup_deviceTestICD244 FindDevice lookup_device(VkDevice device) { 245 FindDevice fd{}; 246 for (uint32_t p = 0; p < physical_devices.size(); p++) { 247 auto const& phys_dev = physical_devices.at(p); 248 for (uint32_t d = 0; d < phys_dev.device_handles.size(); d++) { 249 if (phys_dev.device_handles.at(d) == device) { 250 fd.found = true; 251 fd.phys_dev_index = p; 252 fd.dev_index = d; 253 return fd; 254 } 255 } 256 } 257 return fd; 258 } 259 260 #if defined(WIN32) 261 BUILDER_VALUE(TestICD, LUID, adapterLUID, {}) 262 #endif // defined(WIN32) 263 }; 264 265 using GetTestICDFunc = TestICD* (*)(); 266 #define GET_TEST_ICD_FUNC_STR "get_test_icd_func" 267 268 using GetNewTestICDFunc = TestICD* (*)(); 269 #define RESET_ICD_FUNC_STR "reset_icd_func" 270