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 #include "physical_device.h"
35 
36 enum class CalledICDGIPA { not_called, vk_icd_gipa, vk_gipa };
37 
38 enum class CalledNegotiateInterface { not_called, vk_icd_negotiate, vk_icd_gipa_first };
39 
40 enum class InterfaceVersionCheck {
41     not_called,
42     loader_version_too_old,
43     loader_version_too_new,
44     icd_version_too_new,
45     version_is_supported
46 };
47 
48 // clang-format off
operator <<(std::ostream& os, const CalledICDGIPA& result)49 inline std::ostream& operator<<(std::ostream& os, const CalledICDGIPA& result) {
50     switch (result) {
51         case (CalledICDGIPA::not_called): return os << "CalledICDGIPA::not_called";
52         case (CalledICDGIPA::vk_icd_gipa): return os << "CalledICDGIPA::vk_icd_gipa";
53         case (CalledICDGIPA::vk_gipa): return os << "CalledICDGIPA::vk_gipa";
54     }
55     return os << static_cast<uint32_t>(result);
56 }
operator <<(std::ostream& os, const CalledNegotiateInterface& result)57 inline std::ostream& operator<<(std::ostream& os, const CalledNegotiateInterface& result) {
58     switch (result) {
59         case (CalledNegotiateInterface::not_called): return os << "CalledNegotiateInterface::not_called";
60         case (CalledNegotiateInterface::vk_icd_negotiate): return os << "CalledNegotiateInterface::vk_icd_negotiate";
61         case (CalledNegotiateInterface::vk_icd_gipa_first): return os << "CalledNegotiateInterface::vk_icd_gipa_first";
62     }
63     return os << static_cast<uint32_t>(result);
64 }
operator <<(std::ostream& os, const InterfaceVersionCheck& result)65 inline std::ostream& operator<<(std::ostream& os, const InterfaceVersionCheck& result) {
66     switch (result) {
67         case (InterfaceVersionCheck::not_called): return os << "InterfaceVersionCheck::not_called";
68         case (InterfaceVersionCheck::loader_version_too_old): return os << "InterfaceVersionCheck::loader_version_too_old";
69         case (InterfaceVersionCheck::loader_version_too_new): return os << "InterfaceVersionCheck::loader_version_too_new";
70         case (InterfaceVersionCheck::icd_version_too_new): return os << "InterfaceVersionCheck::icd_version_too_new";
71         case (InterfaceVersionCheck::version_is_supported): return os << "InterfaceVersionCheck::version_is_supported";
72     }
73     return os << static_cast<uint32_t>(result);
74 }
75 // clang-format on
76 
77 struct TestICD {
78     fs::path manifest_file_path;
79 
80     BUILDER_VALUE(TestICD, bool, exposes_vk_icdNegotiateLoaderICDInterfaceVersion, true)
81     BUILDER_VALUE(TestICD, bool, exposes_vkEnumerateInstanceExtensionProperties, true)
82     BUILDER_VALUE(TestICD, bool, exposes_vkCreateInstance, true)
83     BUILDER_VALUE(TestICD, bool, exposes_vk_icdGetPhysicalDeviceProcAddr, true)
84 #if defined(WIN32)
85     BUILDER_VALUE(TestICD, bool, exposes_vk_icdEnumerateAdapterPhysicalDevices, true)
86 #endif
87 
88     CalledICDGIPA called_vk_icd_gipa = CalledICDGIPA::not_called;
89     CalledNegotiateInterface called_negotiate_interface = CalledNegotiateInterface::not_called;
90 
91     InterfaceVersionCheck interface_version_check = InterfaceVersionCheck::not_called;
92     BUILDER_VALUE(TestICD, uint32_t, min_icd_interface_version, 0)
93     BUILDER_VALUE(TestICD, uint32_t, max_icd_interface_version, 7)
94     uint32_t icd_interface_version_received = 0;
95 
96     bool called_enumerate_adapter_physical_devices = false;
97 
98     BUILDER_VALUE(TestICD, bool, enable_icd_wsi, false);
99     bool is_using_icd_wsi = false;
100 
setup_WSITestICD101     TestICD& setup_WSI(const char* api_selection = nullptr) {
102         enable_icd_wsi = true;
103         add_instance_extensions({"VK_KHR_surface", get_platform_wsi_extension(api_selection)});
104         min_icd_interface_version = (3U < min_icd_interface_version) ? min_icd_interface_version : 3U;
105         return *this;
106     }
107 
108     BUILDER_VALUE(TestICD, uint32_t, icd_api_version, VK_API_VERSION_1_0)
109     BUILDER_VECTOR(TestICD, LayerDefinition, instance_layers, instance_layer)
110     BUILDER_VECTOR(TestICD, Extension, instance_extensions, instance_extension)
111     BUILDER_VECTOR(TestICD, Extension, enabled_instance_extensions, enabled_instance_extension)
112 
113     BUILDER_VECTOR_MOVE_ONLY(TestICD, PhysicalDevice, physical_devices, physical_device);
114 
115     BUILDER_VECTOR(TestICD, PhysicalDeviceGroup, physical_device_groups, physical_device_group);
116 
117     DispatchableHandle<VkInstance> instance_handle;
118     std::vector<DispatchableHandle<VkDevice>> device_handles;
119     std::vector<uint64_t> surface_handles;
120     std::vector<uint64_t> messenger_handles;
121     std::vector<uint64_t> swapchain_handles;
122 
123     BUILDER_VALUE(TestICD, bool, can_query_vkEnumerateInstanceVersion, true);
124     BUILDER_VALUE(TestICD, bool, can_query_GetPhysicalDeviceFuncs, true);
125 
126     // Unknown instance functions Add a `VulkanFunction` to this list which will be searched in
127     // vkGetInstanceProcAddr for custom_instance_functions and vk_icdGetPhysicalDeviceProcAddr for
128     // custom_physical_device_functions. To add unknown device functions, add it to the PhysicalDevice directly (in the
129     // known_device_functions member)
130     BUILDER_VECTOR(TestICD, VulkanFunction, custom_instance_functions, custom_instance_function)
131 
132     // Must explicitely state support for the tooling info extension, that way we can control if vkGetInstanceProcAddr returns a
133     // function pointer for vkGetPhysicalDeviceToolPropertiesEXT or vkGetPhysicalDeviceToolProperties (core version)
134     BUILDER_VALUE(TestICD, bool, supports_tooling_info_ext, false);
135     BUILDER_VALUE(TestICD, bool, supports_tooling_info_core, false);
136     // List of tooling properties that this driver 'supports'
137     BUILDER_VECTOR(TestICD, VkPhysicalDeviceToolPropertiesEXT, tooling_properties, tooling_property)
138     std::vector<DispatchableHandle<VkCommandBuffer>> allocated_command_buffers;
139 
140     VkInstanceCreateFlags passed_in_instance_create_flags{};
141 
GetPhysDeviceTestICD142     PhysicalDevice& GetPhysDevice(VkPhysicalDevice physicalDevice) {
143         for (auto& phys_dev : physical_devices) {
144             if (phys_dev.vk_physical_device.handle == physicalDevice) return phys_dev;
145         }
146         assert(false && "vkPhysicalDevice not found!");
147         return physical_devices[0];
148     }
149 
GetVkInstanceCreateInfoTestICD150     InstanceCreateInfo GetVkInstanceCreateInfo() {
151         InstanceCreateInfo info;
152         for (auto& layer : instance_layers) info.enabled_layers.push_back(layer.layerName.data());
153         for (auto& ext : instance_extensions) info.enabled_extensions.push_back(ext.extensionName.data());
154         return info;
155     }
156 
157     struct FindDevice {
158         bool found = false;
159         uint32_t phys_dev_index = 0;
160         uint32_t dev_index = 0;
161     };
162 
lookup_deviceTestICD163     FindDevice lookup_device(VkDevice device) {
164         FindDevice fd{};
165         for (uint32_t p = 0; p < physical_devices.size(); p++) {
166             auto const& phys_dev = physical_devices.at(p);
167             for (uint32_t d = 0; d < phys_dev.device_handles.size(); d++) {
168                 if (phys_dev.device_handles.at(d) == device) {
169                     fd.found = true;
170                     fd.phys_dev_index = p;
171                     fd.dev_index = d;
172                     return fd;
173                 }
174             }
175         }
176         return fd;
177     }
178 
179 #if defined(WIN32)
180     BUILDER_VALUE(TestICD, LUID, adapterLUID, {})
181 #endif  // defined(WIN32)
182 };
183 
184 using GetTestICDFunc = TestICD* (*)();
185 #define GET_TEST_ICD_FUNC_STR "get_test_icd_func"
186 
187 using GetNewTestICDFunc = TestICD* (*)();
188 #define RESET_ICD_FUNC_STR "reset_icd_func"
189