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 #include "test_environment.h"
29 
get_loader_path()30 fs::path get_loader_path() {
31     auto loader_path = fs::path(FRAMEWORK_VULKAN_LIBRARY_PATH);
32     auto env_var_res = get_env_var("VK_LOADER_TEST_LOADER_PATH", false);
33     if (!env_var_res.empty()) {
34         loader_path = fs::path(env_var_res);
35     }
36     return loader_path;
37 }
38 
init_vulkan_functions(VulkanFunctions& funcs)39 void init_vulkan_functions(VulkanFunctions& funcs) {
40 #if defined(APPLE_STATIC_LOADER)
41 #define GPA(name) name
42 #else
43 #define GPA(name) funcs.loader.get_symbol(#name)
44 #endif
45 
46     // clang-format off
47     funcs.vkGetInstanceProcAddr = GPA(vkGetInstanceProcAddr);
48     funcs.vkEnumerateInstanceExtensionProperties = GPA(vkEnumerateInstanceExtensionProperties);
49     funcs.vkEnumerateInstanceLayerProperties = GPA(vkEnumerateInstanceLayerProperties);
50     funcs.vkEnumerateInstanceVersion = GPA(vkEnumerateInstanceVersion);
51     funcs.vkCreateInstance = GPA(vkCreateInstance);
52     funcs.vkDestroyInstance = GPA(vkDestroyInstance);
53     funcs.vkEnumeratePhysicalDevices = GPA(vkEnumeratePhysicalDevices);
54     funcs.vkEnumeratePhysicalDeviceGroups = GPA(vkEnumeratePhysicalDeviceGroups);
55     funcs.vkGetPhysicalDeviceFeatures = GPA(vkGetPhysicalDeviceFeatures);
56     funcs.vkGetPhysicalDeviceFeatures2 = GPA(vkGetPhysicalDeviceFeatures2);
57     funcs.vkGetPhysicalDeviceFormatProperties = GPA(vkGetPhysicalDeviceFormatProperties);
58     funcs.vkGetPhysicalDeviceFormatProperties2 = GPA(vkGetPhysicalDeviceFormatProperties2);
59     funcs.vkGetPhysicalDeviceImageFormatProperties = GPA(vkGetPhysicalDeviceImageFormatProperties);
60     funcs.vkGetPhysicalDeviceImageFormatProperties2 = GPA(vkGetPhysicalDeviceImageFormatProperties2);
61     funcs.vkGetPhysicalDeviceSparseImageFormatProperties = GPA(vkGetPhysicalDeviceSparseImageFormatProperties);
62     funcs.vkGetPhysicalDeviceSparseImageFormatProperties2 = GPA(vkGetPhysicalDeviceSparseImageFormatProperties2);
63     funcs.vkGetPhysicalDeviceProperties = GPA(vkGetPhysicalDeviceProperties);
64     funcs.vkGetPhysicalDeviceProperties2 = GPA(vkGetPhysicalDeviceProperties2);
65     funcs.vkGetPhysicalDeviceQueueFamilyProperties = GPA(vkGetPhysicalDeviceQueueFamilyProperties);
66     funcs.vkGetPhysicalDeviceQueueFamilyProperties2 = GPA(vkGetPhysicalDeviceQueueFamilyProperties2);
67     funcs.vkGetPhysicalDeviceMemoryProperties = GPA(vkGetPhysicalDeviceMemoryProperties);
68     funcs.vkGetPhysicalDeviceMemoryProperties2 = GPA(vkGetPhysicalDeviceMemoryProperties2);
69     funcs.vkGetPhysicalDeviceSurfaceSupportKHR = GPA(vkGetPhysicalDeviceSurfaceSupportKHR);
70     funcs.vkGetPhysicalDeviceSurfaceFormatsKHR = GPA(vkGetPhysicalDeviceSurfaceFormatsKHR);
71     funcs.vkGetPhysicalDeviceSurfacePresentModesKHR = GPA(vkGetPhysicalDeviceSurfacePresentModesKHR);
72     funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR = GPA(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
73     funcs.vkEnumerateDeviceExtensionProperties = GPA(vkEnumerateDeviceExtensionProperties);
74     funcs.vkEnumerateDeviceLayerProperties = GPA(vkEnumerateDeviceLayerProperties);
75     funcs.vkGetPhysicalDeviceExternalBufferProperties = GPA(vkGetPhysicalDeviceExternalBufferProperties);
76     funcs.vkGetPhysicalDeviceExternalFenceProperties = GPA(vkGetPhysicalDeviceExternalFenceProperties);
77     funcs.vkGetPhysicalDeviceExternalSemaphoreProperties = GPA(vkGetPhysicalDeviceExternalSemaphoreProperties);
78 
79     funcs.vkDestroySurfaceKHR = GPA(vkDestroySurfaceKHR);
80     funcs.vkGetDeviceProcAddr = GPA(vkGetDeviceProcAddr);
81     funcs.vkCreateDevice = GPA(vkCreateDevice);
82 
83     funcs.vkCreateHeadlessSurfaceEXT = GPA(vkCreateHeadlessSurfaceEXT);
84     funcs.vkCreateDisplayPlaneSurfaceKHR = GPA(vkCreateDisplayPlaneSurfaceKHR);
85     funcs.vkGetPhysicalDeviceDisplayPropertiesKHR = GPA(vkGetPhysicalDeviceDisplayPropertiesKHR);
86     funcs.vkGetPhysicalDeviceDisplayPlanePropertiesKHR = GPA(vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
87     funcs.vkGetDisplayPlaneSupportedDisplaysKHR = GPA(vkGetDisplayPlaneSupportedDisplaysKHR);
88     funcs.vkGetDisplayModePropertiesKHR = GPA(vkGetDisplayModePropertiesKHR);
89     funcs.vkCreateDisplayModeKHR = GPA(vkCreateDisplayModeKHR);
90     funcs.vkGetDisplayPlaneCapabilitiesKHR = GPA(vkGetDisplayPlaneCapabilitiesKHR);
91     funcs.vkGetPhysicalDevicePresentRectanglesKHR = GPA(vkGetPhysicalDevicePresentRectanglesKHR);
92     funcs.vkGetPhysicalDeviceDisplayProperties2KHR = GPA(vkGetPhysicalDeviceDisplayProperties2KHR);
93     funcs.vkGetPhysicalDeviceDisplayPlaneProperties2KHR = GPA(vkGetPhysicalDeviceDisplayPlaneProperties2KHR);
94     funcs.vkGetDisplayModeProperties2KHR = GPA(vkGetDisplayModeProperties2KHR);
95     funcs.vkGetDisplayPlaneCapabilities2KHR = GPA(vkGetDisplayPlaneCapabilities2KHR);
96     funcs.vkGetPhysicalDeviceSurfaceCapabilities2KHR = GPA(vkGetPhysicalDeviceSurfaceCapabilities2KHR);
97     funcs.vkGetPhysicalDeviceSurfaceFormats2KHR = GPA(vkGetPhysicalDeviceSurfaceFormats2KHR);
98 
99 #if defined(VK_USE_PLATFORM_ANDROID_KHR)
100     funcs.vkCreateAndroidSurfaceKHR = GPA(vkCreateAndroidSurfaceKHR);
101 #endif  // VK_USE_PLATFORM_ANDROID_KHR
102 #if defined(VK_USE_PLATFORM_DIRECTFB_EXT)
103     funcs.vkCreateDirectFBSurfaceEXT = GPA(vkCreateDirectFBSurfaceEXT);
104     funcs.vkGetPhysicalDeviceDirectFBPresentationSupportEXT = GPA(vkGetPhysicalDeviceDirectFBPresentationSupportEXT);
105 #endif  // VK_USE_PLATFORM_DIRECTFB_EXT
106 #if defined(VK_USE_PLATFORM_FUCHSIA)
107     funcs.vkCreateImagePipeSurfaceFUCHSIA = GPA(vkCreateImagePipeSurfaceFUCHSIA);
108 #endif  // VK_USE_PLATFORM_FUCHSIA
109 #if defined(VK_USE_PLATFORM_GGP)
110     funcs.vkCreateStreamDescriptorSurfaceGGP = GPA(vkCreateStreamDescriptorSurfaceGGP);
111 #endif  // VK_USE_PLATFORM_GGP
112 #if defined(VK_USE_PLATFORM_IOS_MVK)
113     funcs.vkCreateIOSSurfaceMVK = GPA(vkCreateIOSSurfaceMVK);
114 #endif  // VK_USE_PLATFORM_IOS_MVK
115 #if defined(VK_USE_PLATFORM_MACOS_MVK)
116     funcs.vkCreateMacOSSurfaceMVK = GPA(vkCreateMacOSSurfaceMVK);
117 #endif  // VK_USE_PLATFORM_MACOS_MVK
118 #if defined(VK_USE_PLATFORM_METAL_EXT)
119     funcs.vkCreateMetalSurfaceEXT = GPA(vkCreateMetalSurfaceEXT);
120 #endif  // VK_USE_PLATFORM_METAL_EXT
121 #if defined(VK_USE_PLATFORM_SCREEN_QNX)
122     funcs.vkCreateScreenSurfaceQNX = GPA(vkCreateScreenSurfaceQNX);
123     funcs.vkGetPhysicalDeviceScreenPresentationSupportQNX = GPA(vkGetPhysicalDeviceScreenPresentationSupportQNX);
124 #endif  // VK_USE_PLATFORM_SCREEN_QNX
125 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
126     funcs.vkCreateWaylandSurfaceKHR = GPA(vkCreateWaylandSurfaceKHR);
127     funcs.vkGetPhysicalDeviceWaylandPresentationSupportKHR = GPA(vkGetPhysicalDeviceWaylandPresentationSupportKHR);
128 #endif  // VK_USE_PLATFORM_WAYLAND_KHR
129 #if defined(VK_USE_PLATFORM_XCB_KHR)
130     funcs.vkCreateXcbSurfaceKHR = GPA(vkCreateXcbSurfaceKHR);
131     funcs.vkGetPhysicalDeviceXcbPresentationSupportKHR = GPA(vkGetPhysicalDeviceXcbPresentationSupportKHR);
132 #endif  // VK_USE_PLATFORM_XCB_KHR
133 #if defined(VK_USE_PLATFORM_XLIB_KHR)
134     funcs.vkCreateXlibSurfaceKHR = GPA(vkCreateXlibSurfaceKHR);
135     funcs.vkGetPhysicalDeviceXlibPresentationSupportKHR = GPA(vkGetPhysicalDeviceXlibPresentationSupportKHR);
136 #endif  // VK_USE_PLATFORM_XLIB_KHR
137 #if defined(VK_USE_PLATFORM_WIN32_KHR)
138     funcs.vkCreateWin32SurfaceKHR = GPA(vkCreateWin32SurfaceKHR);
139     funcs.vkGetPhysicalDeviceWin32PresentationSupportKHR = GPA(vkGetPhysicalDeviceWin32PresentationSupportKHR);
140 #endif  // VK_USE_PLATFORM_WIN32_KHR
141 
142     funcs.vkDestroyDevice = GPA(vkDestroyDevice);
143     funcs.vkGetDeviceQueue = GPA(vkGetDeviceQueue);
144 #undef GPA
145     // clang-format on
146 }
147 
148 #if defined(APPLE_STATIC_LOADER)
VulkanFunctions()149 VulkanFunctions::VulkanFunctions() {
150 #else
151 VulkanFunctions::VulkanFunctions() : loader(get_loader_path()) {
152 #endif
153     init_vulkan_functions(*this);
154 }
155 
156 DeviceFunctions::DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device) {
157     vkGetDeviceProcAddr = vulkan_functions.vkGetDeviceProcAddr;
158     vkDestroyDevice = load(device, "vkDestroyDevice");
159     vkGetDeviceQueue = load(device, "vkGetDeviceQueue");
160     vkCreateCommandPool = load(device, "vkCreateCommandPool");
161     vkAllocateCommandBuffers = load(device, "vkAllocateCommandBuffers");
162     vkDestroyCommandPool = load(device, "vkDestroyCommandPool");
163     vkCreateSwapchainKHR = load(device, "vkCreateSwapchainKHR");
164     vkGetSwapchainImagesKHR = load(device, "vkGetSwapchainImagesKHR");
165     vkDestroySwapchainKHR = load(device, "vkDestroySwapchainKHR");
166 }
167 
168 InstWrapper::InstWrapper(VulkanFunctions& functions, VkAllocationCallbacks* callbacks) noexcept
169     : functions(&functions), callbacks(callbacks) {}
170 InstWrapper::InstWrapper(VulkanFunctions& functions, VkInstance inst, VkAllocationCallbacks* callbacks) noexcept
171     : functions(&functions), inst(inst), callbacks(callbacks) {}
172 InstWrapper::~InstWrapper() noexcept {
173     if (inst != VK_NULL_HANDLE) functions->vkDestroyInstance(inst, callbacks);
174 }
175 
176 InstWrapper::InstWrapper(InstWrapper&& other) noexcept {
177     functions = other.functions;
178     inst = other.inst;
179     callbacks = other.callbacks;
180     create_info = other.create_info;
181     other.inst = VK_NULL_HANDLE;
182 }
183 InstWrapper& InstWrapper::operator=(InstWrapper&& other) noexcept {
184     functions->vkDestroyInstance(inst, callbacks);
185     functions = other.functions;
186     inst = other.inst;
187     callbacks = other.callbacks;
188     create_info = other.create_info;
189     other.inst = VK_NULL_HANDLE;
190     return *this;
191 }
192 
193 void InstWrapper::CheckCreate(VkResult result_to_check) {
194     ASSERT_EQ(result_to_check, functions->vkCreateInstance(create_info.get(), callbacks, &inst));
195 }
196 
197 void InstWrapper::CheckCreateWithInfo(InstanceCreateInfo& create_info, VkResult result_to_check) {
198     ASSERT_EQ(result_to_check, functions->vkCreateInstance(create_info.get(), callbacks, &inst));
199 }
200 
201 std::vector<VkPhysicalDevice> InstWrapper::GetPhysDevs(uint32_t phys_dev_count, VkResult result_to_check) {
202     uint32_t physical_count = phys_dev_count;
203     std::vector<VkPhysicalDevice> physical_devices;
204     physical_devices.resize(phys_dev_count);
205     VkResult res = functions->vkEnumeratePhysicalDevices(inst, &physical_count, physical_devices.data());
206     EXPECT_EQ(result_to_check, res);
207     return physical_devices;
208 }
209 
210 std::vector<VkPhysicalDevice> InstWrapper::GetPhysDevs(VkResult result_to_check) {
211     uint32_t physical_count = 0;
212     VkResult res = functions->vkEnumeratePhysicalDevices(inst, &physical_count, nullptr);
213     EXPECT_EQ(result_to_check, res);
214     std::vector<VkPhysicalDevice> physical_devices;
215     physical_devices.resize(physical_count);
216     res = functions->vkEnumeratePhysicalDevices(inst, &physical_count, physical_devices.data());
217     EXPECT_EQ(result_to_check, res);
218     return physical_devices;
219 }
220 
221 VkPhysicalDevice InstWrapper::GetPhysDev(VkResult result_to_check) {
222     uint32_t physical_count = 1;
223     VkPhysicalDevice physical_device = VK_NULL_HANDLE;
224     VkResult res = this->functions->vkEnumeratePhysicalDevices(inst, &physical_count, &physical_device);
225     EXPECT_EQ(result_to_check, res);
226     return physical_device;
227 }
228 
229 std::vector<VkLayerProperties> InstWrapper::GetActiveLayers(VkPhysicalDevice phys_dev, uint32_t expected_count) {
230     uint32_t count = 0;
231     VkResult res = functions->vkEnumerateDeviceLayerProperties(phys_dev, &count, nullptr);
232     EXPECT_EQ(VK_SUCCESS, res);
233     EXPECT_EQ(count, expected_count);
234     std::vector<VkLayerProperties> layer_props{count};
235     res = functions->vkEnumerateDeviceLayerProperties(phys_dev, &count, layer_props.data());
236     EXPECT_EQ(VK_SUCCESS, res);
237     EXPECT_EQ(count, expected_count);
238     return layer_props;
239 }
240 
241 std::vector<VkExtensionProperties> InstWrapper::EnumerateDeviceExtensions(VkPhysicalDevice physical_device,
242                                                                           uint32_t expected_count) {
243     uint32_t count = 0;
244     VkResult res = functions->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &count, nullptr);
245     EXPECT_EQ(VK_SUCCESS, res);
246     EXPECT_EQ(count, expected_count);
247     std::vector<VkExtensionProperties> extensions{count};
248     res = functions->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &count, extensions.data());
249     EXPECT_EQ(VK_SUCCESS, res);
250     EXPECT_EQ(count, expected_count);
251     return extensions;
252 }
253 
254 std::vector<VkExtensionProperties> InstWrapper::EnumerateLayerDeviceExtensions(VkPhysicalDevice physical_device,
255                                                                                const char* layer_name, uint32_t expected_count) {
256     uint32_t count = 0;
257     VkResult res = functions->vkEnumerateDeviceExtensionProperties(physical_device, layer_name, &count, nullptr);
258     EXPECT_EQ(VK_SUCCESS, res);
259     EXPECT_EQ(count, expected_count);
260     std::vector<VkExtensionProperties> extensions{count};
261     res = functions->vkEnumerateDeviceExtensionProperties(physical_device, layer_name, &count, extensions.data());
262     EXPECT_EQ(VK_SUCCESS, res);
263     EXPECT_EQ(count, expected_count);
264     return extensions;
265 }
266 
267 DeviceWrapper::DeviceWrapper(InstWrapper& inst_wrapper, VkAllocationCallbacks* callbacks) noexcept
268     : functions(inst_wrapper.functions), callbacks(callbacks){};
269 DeviceWrapper::DeviceWrapper(VulkanFunctions& functions, VkDevice device, VkAllocationCallbacks* callbacks) noexcept
270     : functions(&functions), dev(device), callbacks(callbacks){};
271 DeviceWrapper::~DeviceWrapper() noexcept { functions->vkDestroyDevice(dev, callbacks); }
272 
273 DeviceWrapper::DeviceWrapper(DeviceWrapper&& other) noexcept {
274     functions = other.functions;
275     dev = other.dev;
276     callbacks = other.callbacks;
277     create_info = other.create_info;
278     other.dev = VK_NULL_HANDLE;
279 }
280 DeviceWrapper& DeviceWrapper::operator=(DeviceWrapper&& other) noexcept {
281     functions->vkDestroyDevice(dev, callbacks);
282     functions = other.functions;
283     dev = other.dev;
284     callbacks = other.callbacks;
285     create_info = other.create_info;
286     other.dev = VK_NULL_HANDLE;
287     return *this;
288 }
289 
290 void DeviceWrapper::CheckCreate(VkPhysicalDevice phys_dev, VkResult result_to_check) {
291     ASSERT_EQ(result_to_check, functions->vkCreateDevice(phys_dev, create_info.get(), callbacks, &dev));
292 }
293 
294 VkResult CreateDebugUtilsMessenger(DebugUtilsWrapper& debug_utils) {
295     return debug_utils.vkCreateDebugUtilsMessengerEXT(debug_utils.inst, debug_utils.get(), debug_utils.callbacks,
296                                                       &debug_utils.messenger);
297 }
298 
299 void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsLogger& logger) {
300     create_info.add_extension("VK_EXT_debug_utils");
301     create_info.instance_info.pNext = logger.get();
302 }
303 void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsWrapper& wrapper) {
304     create_info.add_extension("VK_EXT_debug_utils");
305     create_info.instance_info.pNext = wrapper.get();
306 }
307 
308 // Look through the event log. If you find a line containing the prefix we're interested in, look for the end of
309 // line character, and then see if the postfix occurs in it as well.
310 bool DebugUtilsLogger::find_prefix_then_postfix(const char* prefix, const char* postfix) const {
311     size_t new_start = 0;
312     size_t postfix_index = 0;
313     size_t next_eol = 0;
314     while ((new_start = returned_output.find(prefix, new_start)) != std::string::npos) {
315         next_eol = returned_output.find("\n", new_start);
316         if ((postfix_index = returned_output.find(postfix, new_start)) != std::string::npos) {
317             if (postfix_index < next_eol) {
318                 return true;
319             }
320         }
321         new_start = next_eol + 1;
322     }
323     return false;
324 }
325 
326 bool FindPrefixPostfixStringOnLine(DebugUtilsLogger const& env_log, const char* prefix, const char* postfix) {
327     return env_log.find_prefix_then_postfix(prefix, postfix);
328 }
329 
330 PlatformShimWrapper::PlatformShimWrapper(std::vector<fs::FolderManager>* folders, const char* log_filter) noexcept
331     : loader_logging{"VK_LOADER_DEBUG"} {
332 #if defined(WIN32) || defined(__APPLE__)
333     shim_library = LibraryWrapper(SHIM_LIBRARY_NAME);
334     PFN_get_platform_shim get_platform_shim_func = shim_library.get_symbol(GET_PLATFORM_SHIM_STR);
335     assert(get_platform_shim_func != NULL && "Must be able to get \"platform_shim\"");
336     platform_shim = get_platform_shim_func(folders);
337 #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__GNU__)
338     platform_shim = get_platform_shim(folders);
339 #endif
340     platform_shim->reset();
341 
342     if (log_filter) {
343         loader_logging.set_new_value(log_filter);
344     }
345 }
346 
347 PlatformShimWrapper::~PlatformShimWrapper() noexcept { platform_shim->reset(); }
348 
349 TestICDHandle::TestICDHandle() noexcept {}
350 TestICDHandle::TestICDHandle(fs::path const& icd_path) noexcept : icd_library(icd_path) {
351     proc_addr_get_test_icd = icd_library.get_symbol(GET_TEST_ICD_FUNC_STR);
352     proc_addr_reset_icd = icd_library.get_symbol(RESET_ICD_FUNC_STR);
353 }
354 TestICD& TestICDHandle::get_test_icd() noexcept {
355     assert(proc_addr_get_test_icd != NULL && "symbol must be loaded before use");
356     return *proc_addr_get_test_icd();
357 }
358 TestICD& TestICDHandle::reset_icd() noexcept {
359     assert(proc_addr_reset_icd != NULL && "symbol must be loaded before use");
360     return *proc_addr_reset_icd();
361 }
362 fs::path TestICDHandle::get_icd_full_path() noexcept { return icd_library.lib_path; }
363 fs::path TestICDHandle::get_icd_manifest_path() noexcept { return manifest_path; }
364 fs::path TestICDHandle::get_shimmed_manifest_path() noexcept { return shimmed_manifest_path; }
365 
366 TestLayerHandle::TestLayerHandle() noexcept {}
367 TestLayerHandle::TestLayerHandle(fs::path const& layer_path) noexcept : layer_library(layer_path) {
368     proc_addr_get_test_layer = layer_library.get_symbol(GET_TEST_LAYER_FUNC_STR);
369     proc_addr_reset_layer = layer_library.get_symbol(RESET_LAYER_FUNC_STR);
370 }
371 TestLayer& TestLayerHandle::get_test_layer() noexcept {
372     assert(proc_addr_get_test_layer != NULL && "symbol must be loaded before use");
373     return *proc_addr_get_test_layer();
374 }
375 TestLayer& TestLayerHandle::reset_layer() noexcept {
376     assert(proc_addr_reset_layer != NULL && "symbol must be loaded before use");
377     return *proc_addr_reset_layer();
378 }
379 fs::path TestLayerHandle::get_layer_full_path() noexcept { return layer_library.lib_path; }
380 fs::path TestLayerHandle::get_layer_manifest_path() noexcept { return manifest_path; }
381 fs::path TestLayerHandle::get_shimmed_manifest_path() noexcept { return shimmed_manifest_path; }
382 
383 FrameworkEnvironment::FrameworkEnvironment() noexcept : FrameworkEnvironment(FrameworkSettings{}) {}
384 FrameworkEnvironment::FrameworkEnvironment(FrameworkSettings const& settings) noexcept
385     : settings(settings), platform_shim(&folders, settings.log_filter) {
386     // This order is important, it matches the enum ManifestLocation, used to index the folders vector
387     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("null_dir"));
388     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("icd_manifests"));
389     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("icd_env_vars_manifests"));
390     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_layer_manifests"));
391     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_env_var_layer_folder"));
392     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_add_env_var_layer_folder"));
393     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("implicit_layer_manifests"));
394     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("override_layer_manifests"));
395     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("app_package_manifests"));
396     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("macos_bundle"));
397     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("unsecured_location"));
398     folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("settings_location"));
399 
400     platform_shim->redirect_all_paths(get_folder(ManifestLocation::null).location());
401     if (settings.enable_default_search_paths) {
402         platform_shim->set_fake_path(ManifestCategory::icd, get_folder(ManifestLocation::driver).location());
403         platform_shim->set_fake_path(ManifestCategory::explicit_layer, get_folder(ManifestLocation::explicit_layer).location());
404         platform_shim->set_fake_path(ManifestCategory::implicit_layer, get_folder(ManifestLocation::implicit_layer).location());
405 #if COMMON_UNIX_PLATFORMS
406         auto home = get_env_var("HOME");
407         auto unsecured_location = get_folder(ManifestLocation::unsecured_location).location();
408         platform_shim->redirect_path(home + "/.local/share/vulkan/icd.d", unsecured_location);
409         platform_shim->redirect_path(home + "/.local/share/vulkan/implicit_layer.d", unsecured_location);
410         platform_shim->redirect_path(home + "/.local/share/vulkan/explicit_layer.d", unsecured_location);
411 #endif
412     }
413 #if COMMON_UNIX_PLATFORMS
414     if (settings.secure_loader_settings) {
415         platform_shim->redirect_path("/etc/vulkan/loader_settings.d", get_folder(ManifestLocation::settings_location).location());
416     } else {
417         platform_shim->redirect_path(get_env_var("HOME") + "/.local/share/vulkan/loader_settings.d",
418                                      get_folder(ManifestLocation::settings_location).location());
419     }
420 #endif
421 
422 #if defined(__APPLE__)
423     // Necessary since bundles look in sub folders for manifests, not the test framework folder itself
424     auto bundle_location = get_folder(ManifestLocation::macos_bundle).location();
425     platform_shim->redirect_path(bundle_location / "vulkan/icd.d", bundle_location);
426     platform_shim->redirect_path(bundle_location / "vulkan/explicit_layer.d", bundle_location);
427     platform_shim->redirect_path(bundle_location / "vulkan/implicit_layer.d", bundle_location);
428 #endif
429     // only set the settings file if there are elements in the app_specific_settings vector
430     if (!settings.loader_settings.app_specific_settings.empty()) {
431         update_loader_settings(settings.loader_settings);
432     }
433 }
434 
435 FrameworkEnvironment::~FrameworkEnvironment() {
436     // This is necessary to prevent the folder manager from using dead memory during destruction.
437     // What happens is that each folder manager tries to cleanup itself. Except, folders that were never called did not have their
438     // DirEntry array's filled out. So when that folder calls delete_folder, which calls readdir, the shim tries to order the files.
439     // Except, the list of files is in a object that is currently being destroyed.
440     platform_shim->is_during_destruction = true;
441 }
442 
443 TestICD& FrameworkEnvironment::add_icd(TestICDDetails icd_details) noexcept {
444     size_t cur_icd_index = icds.size();
445     fs::FolderManager* folder = &get_folder(ManifestLocation::driver);
446     if (icd_details.discovery_type == ManifestDiscoveryType::env_var ||
447         icd_details.discovery_type == ManifestDiscoveryType::add_env_var) {
448         folder = &get_folder(ManifestLocation::driver_env_var);
449     }
450     if (icd_details.discovery_type == ManifestDiscoveryType::windows_app_package) {
451         folder = &get_folder(ManifestLocation::windows_app_package);
452     }
453     if (icd_details.discovery_type == ManifestDiscoveryType::macos_bundle) {
454         folder = &get_folder(ManifestLocation::macos_bundle);
455     }
456     if (icd_details.discovery_type == ManifestDiscoveryType::unsecured_generic) {
457         folder = &get_folder(ManifestLocation::unsecured_location);
458     }
459     if (icd_details.discovery_type == ManifestDiscoveryType::null_dir ||
460         icd_details.discovery_type == ManifestDiscoveryType::none) {
461         folder = &get_folder(ManifestLocation::null);
462     }
463     if (!icd_details.is_fake) {
464         fs::path new_driver_name = fs::path(icd_details.icd_manifest.lib_path).stem() + "_" + std::to_string(cur_icd_index) +
465                                    fs::path(icd_details.icd_manifest.lib_path).extension();
466 
467         auto new_driver_location = folder->copy_file(icd_details.icd_manifest.lib_path, new_driver_name.str());
468 
469 #if COMMON_UNIX_PLATFORMS
470         if (icd_details.library_path_type == LibraryPathType::default_search_paths) {
471             platform_shim->redirect_dlopen_name(new_driver_name, new_driver_location);
472         } else if (icd_details.library_path_type == LibraryPathType::relative) {
473             platform_shim->redirect_dlopen_name(fs::path(SYSCONFDIR) / "vulkan" / "icd.d" / "." / new_driver_name,
474                                                 new_driver_location);
475         }
476 #endif
477 #if defined(WIN32)
478         if (icd_details.library_path_type == LibraryPathType::default_search_paths) {
479             SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS);
480             AddDllDirectory(conver_str_to_wstr(new_driver_location.parent_path().str()).c_str());
481         }
482 #endif
483         icds.push_back(TestICDHandle(new_driver_location));
484         icds.back().reset_icd();
485         if (icd_details.library_path_type == LibraryPathType::relative) {
486             icd_details.icd_manifest.lib_path = fs::path(".") / new_driver_name;
487         } else if (icd_details.library_path_type == LibraryPathType::default_search_paths) {
488             icd_details.icd_manifest.lib_path = new_driver_name.str();
489         } else {
490             icd_details.icd_manifest.lib_path = new_driver_location.str();
491         }
492     }
493     if (icd_details.discovery_type != ManifestDiscoveryType::none) {
494         std::string full_json_name = icd_details.json_name;
495         if (!icd_details.disable_icd_inc) {
496             full_json_name += "_" + std::to_string(cur_icd_index);
497         }
498         full_json_name += ".json";
499         icds.back().manifest_path = folder->write_manifest(full_json_name, icd_details.icd_manifest.get_manifest_str());
500         icds.back().shimmed_manifest_path = icds.back().manifest_path;
501         switch (icd_details.discovery_type) {
502             default:
503             case (ManifestDiscoveryType::generic):
504                 platform_shim->add_manifest(ManifestCategory::icd, icds.back().manifest_path);
505 #if COMMON_UNIX_PLATFORMS
506                 icds.back().shimmed_manifest_path =
507                     platform_shim->query_default_redirect_path(ManifestCategory::icd) / full_json_name;
508 #endif
509                 break;
510             case (ManifestDiscoveryType::env_var):
511                 if (icd_details.is_dir) {
512                     env_var_vk_icd_filenames.add_to_list(folder->location().str());
513                 } else {
514                     env_var_vk_icd_filenames.add_to_list((folder->location() / full_json_name).str());
515                 }
516                 platform_shim->add_known_path(folder->location());
517                 break;
518             case (ManifestDiscoveryType::add_env_var):
519                 if (icd_details.is_dir) {
520                     add_env_var_vk_icd_filenames.add_to_list(folder->location().str());
521                 } else {
522                     add_env_var_vk_icd_filenames.add_to_list((folder->location() / full_json_name).str());
523                 }
524                 platform_shim->add_known_path(folder->location());
525                 break;
526             case (ManifestDiscoveryType::macos_bundle):
527                 platform_shim->add_manifest(ManifestCategory::icd, icds.back().manifest_path);
528                 break;
529             case (ManifestDiscoveryType::unsecured_generic):
530                 platform_shim->add_unsecured_manifest(ManifestCategory::icd, icds.back().manifest_path);
531                 break;
532             case (ManifestDiscoveryType::null_dir):
533                 break;
534 #if defined(_WIN32)
535             case (ManifestDiscoveryType::windows_app_package):
536                 platform_shim->set_app_package_path(folder->location());
537                 break;
538 #endif
539         }
540     }
541     return icds.back().get_test_icd();
542 }
543 
544 void FrameworkEnvironment::add_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept {
545     add_layer_impl(TestLayerDetails{layer_manifest, json_name}, ManifestCategory::implicit_layer);
546 }
547 void FrameworkEnvironment::add_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept {
548     add_layer_impl(TestLayerDetails{layer_manifest, json_name}, ManifestCategory::explicit_layer);
549 }
550 void FrameworkEnvironment::add_fake_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept {
551     add_layer_impl(TestLayerDetails{layer_manifest, json_name}.set_is_fake(true), ManifestCategory::implicit_layer);
552 }
553 void FrameworkEnvironment::add_fake_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept {
554     add_layer_impl(TestLayerDetails{layer_manifest, json_name}.set_is_fake(true), ManifestCategory::explicit_layer);
555 }
556 void FrameworkEnvironment::add_implicit_layer(TestLayerDetails layer_details) noexcept {
557     add_layer_impl(layer_details, ManifestCategory::implicit_layer);
558 }
559 void FrameworkEnvironment::add_explicit_layer(TestLayerDetails layer_details) noexcept {
560     add_layer_impl(layer_details, ManifestCategory::explicit_layer);
561 }
562 
563 void FrameworkEnvironment::add_layer_impl(TestLayerDetails layer_details, ManifestCategory category) {
564     fs::FolderManager* fs_ptr = &get_folder(ManifestLocation::explicit_layer);
565     switch (layer_details.discovery_type) {
566         default:
567         case (ManifestDiscoveryType::generic):
568             if (category == ManifestCategory::implicit_layer) fs_ptr = &get_folder(ManifestLocation::implicit_layer);
569             break;
570         case (ManifestDiscoveryType::env_var):
571             fs_ptr = &get_folder(ManifestLocation::explicit_layer_env_var);
572             if (layer_details.is_dir) {
573                 env_var_vk_layer_paths.add_to_list(fs_ptr->location().str());
574             } else {
575                 env_var_vk_layer_paths.add_to_list((fs_ptr->location() / layer_details.json_name).str());
576             }
577             platform_shim->add_known_path(fs_ptr->location());
578             break;
579         case (ManifestDiscoveryType::add_env_var):
580             fs_ptr = &get_folder(ManifestLocation::explicit_layer_add_env_var);
581             if (layer_details.is_dir) {
582                 add_env_var_vk_layer_paths.add_to_list(fs_ptr->location().str());
583             } else {
584                 add_env_var_vk_layer_paths.add_to_list((fs_ptr->location() / layer_details.json_name).str());
585             }
586             platform_shim->add_known_path(fs_ptr->location());
587             break;
588         case (ManifestDiscoveryType::override_folder):
589             fs_ptr = &get_folder(ManifestLocation::override_layer);
590             break;
591         case (ManifestDiscoveryType::macos_bundle):
592             fs_ptr = &(get_folder(ManifestLocation::macos_bundle));
593             break;
594         case (ManifestDiscoveryType::unsecured_generic):
595             fs_ptr = &(get_folder(ManifestLocation::unsecured_location));
596             break;
597         case (ManifestDiscoveryType::none):
598         case (ManifestDiscoveryType::null_dir):
599             fs_ptr = &(get_folder(ManifestLocation::null));
600             break;
601     }
602     auto& folder = *fs_ptr;
603     size_t new_layers_start = layers.size();
604     for (auto& layer : layer_details.layer_manifest.layers) {
605         if (!layer.lib_path.str().empty()) {
606             fs::path layer_binary_name =
607                 layer.lib_path.filename().stem() + "_" + std::to_string(layers.size()) + layer.lib_path.filename().extension();
608 
609             auto new_layer_location = folder.copy_file(layer.lib_path, layer_binary_name.str());
610 
611 #if COMMON_UNIX_PLATFORMS
612             if (layer_details.library_path_type == LibraryPathType::default_search_paths) {
613                 platform_shim->redirect_dlopen_name(layer_binary_name, new_layer_location);
614             }
615             if (layer_details.library_path_type == LibraryPathType::relative) {
616                 platform_shim->redirect_dlopen_name(
617                     fs::path(SYSCONFDIR) / "vulkan" / category_path_name(category) / "." / layer_binary_name, new_layer_location);
618             }
619 #endif
620 #if defined(WIN32)
621             if (layer_details.library_path_type == LibraryPathType::default_search_paths) {
622                 SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS);
623                 AddDllDirectory(conver_str_to_wstr(new_layer_location.parent_path().str()).c_str());
624             }
625 #endif
626 
627             // Don't load the layer binary if using any of the wrap objects layers, since it doesn't export the same interface
628             // functions
629             if (!layer_details.is_fake &&
630                 layer.lib_path.stem().str().find(fs::path(TEST_LAYER_WRAP_OBJECTS).stem().str()) == std::string::npos) {
631                 layers.push_back(TestLayerHandle(new_layer_location));
632                 layers.back().reset_layer();
633             }
634             if (layer_details.library_path_type == LibraryPathType::relative) {
635                 layer.lib_path = fs::path(".") / layer_binary_name;
636             } else if (layer_details.library_path_type == LibraryPathType::default_search_paths) {
637                 layer.lib_path = layer_binary_name;
638             } else {
639                 layer.lib_path = new_layer_location;
640             }
641         }
642     }
643     if (layer_details.discovery_type != ManifestDiscoveryType::none) {
644         // Write a manifest file to a folder as long as the discovery type isn't none
645         auto layer_manifest_loc = folder.write_manifest(layer_details.json_name, layer_details.layer_manifest.get_manifest_str());
646         // only add the manifest to the registry if its a generic location (as if it was installed) - both system and user local
647         if (layer_details.discovery_type == ManifestDiscoveryType::generic) {
648             platform_shim->add_manifest(category, layer_manifest_loc);
649         }
650         if (layer_details.discovery_type == ManifestDiscoveryType::unsecured_generic) {
651             platform_shim->add_unsecured_manifest(category, layer_manifest_loc);
652         }
653         for (size_t i = new_layers_start; i < layers.size(); i++) {
654             layers.at(i).manifest_path = layer_manifest_loc;
655             layers.at(i).shimmed_manifest_path = layer_manifest_loc;
656 #if COMMON_UNIX_PLATFORMS
657             if (layer_details.discovery_type == ManifestDiscoveryType::generic) {
658                 layers.at(i).shimmed_manifest_path = platform_shim->query_default_redirect_path(category) / layer_details.json_name;
659             }
660 #endif
661         }
662     }
663 }
664 
665 std::string get_loader_settings_file_contents(const LoaderSettings& loader_settings) noexcept {
666     JsonWriter writer;
667     writer.StartObject();
668     writer.AddKeyedString("file_format_version", loader_settings.file_format_version.get_version_str());
669     bool one_setting_file = true;
670     if (loader_settings.app_specific_settings.size() > 1) {
671         writer.StartKeyedArray("settings_array");
672         one_setting_file = false;
673     }
674     for (const auto& setting : loader_settings.app_specific_settings) {
675         if (one_setting_file) {
676             writer.StartKeyedObject("settings");
677         } else {
678             writer.StartObject();
679         }
680         if (!setting.app_keys.empty()) {
681             writer.StartKeyedArray("app_keys");
682             for (const auto& app_key : setting.app_keys) {
683                 writer.AddString(app_key);
684             }
685             writer.EndArray();
686         }
687         if (!setting.layer_configurations.empty()) {
688             writer.StartKeyedArray("layers");
689             for (const auto& config : setting.layer_configurations) {
690                 writer.StartObject();
691                 writer.AddKeyedString("name", config.name);
692                 writer.AddKeyedString("path", fs::fixup_backslashes_in_path(config.path));
693                 writer.AddKeyedString("control", config.control);
694                 writer.AddKeyedBool("treat_as_implicit_manifest", config.treat_as_implicit_manifest);
695                 writer.EndObject();
696             }
697             writer.EndArray();
698         }
699         if (!setting.stderr_log.empty()) {
700             writer.StartKeyedArray("stderr_log");
701             for (const auto& filter : setting.stderr_log) {
702                 writer.AddString(filter);
703             }
704             writer.EndArray();
705         }
706         if (!setting.log_configurations.empty()) {
707             writer.StartKeyedArray("log_locations");
708             for (const auto& config : setting.log_configurations) {
709                 writer.StartObject();
710                 writer.StartKeyedArray("destinations");
711                 for (const auto& dest : config.destinations) {
712                     writer.AddString(dest);
713                 }
714                 writer.EndArray();
715                 writer.StartKeyedArray("filter");
716                 for (const auto& filter : config.filters) {
717                     writer.AddString(filter);
718                 }
719                 writer.EndArray();
720                 writer.EndObject();
721             }
722             writer.EndArray();
723         }
724         writer.EndObject();
725     }
726     if (!one_setting_file) {
727         writer.EndArray();
728     }
729 
730     writer.EndObject();
731     return writer.output;
732 }
733 void FrameworkEnvironment::write_settings_file(std::string const& file_contents) {
734     auto out_path = get_folder(ManifestLocation::settings_location).write_manifest("vk_loader_settings.json", file_contents);
735 #if defined(WIN32)
736     platform_shim->hkey_current_user_settings.clear();
737     platform_shim->hkey_local_machine_settings.clear();
738 #endif
739     if (settings.secure_loader_settings)
740         platform_shim->add_manifest(ManifestCategory::settings, out_path);
741     else
742         platform_shim->add_unsecured_manifest(ManifestCategory::settings, out_path);
743 }
744 void FrameworkEnvironment::update_loader_settings(const LoaderSettings& settings) noexcept {
745     write_settings_file(get_loader_settings_file_contents(settings));
746 }
747 void FrameworkEnvironment::remove_loader_settings() {
748     get_folder(ManifestLocation::settings_location).remove("vk_loader_settings.json");
749 }
750 
751 TestICD& FrameworkEnvironment::get_test_icd(size_t index) noexcept { return icds[index].get_test_icd(); }
752 TestICD& FrameworkEnvironment::reset_icd(size_t index) noexcept { return icds[index].reset_icd(); }
753 fs::path FrameworkEnvironment::get_test_icd_path(size_t index) noexcept { return icds[index].get_icd_full_path(); }
754 fs::path FrameworkEnvironment::get_icd_manifest_path(size_t index) noexcept { return icds[index].get_icd_manifest_path(); }
755 fs::path FrameworkEnvironment::get_shimmed_icd_manifest_path(size_t index) noexcept {
756     return icds[index].get_shimmed_manifest_path();
757 }
758 
759 TestLayer& FrameworkEnvironment::get_test_layer(size_t index) noexcept { return layers[index].get_test_layer(); }
760 TestLayer& FrameworkEnvironment::reset_layer(size_t index) noexcept { return layers[index].reset_layer(); }
761 fs::path FrameworkEnvironment::get_test_layer_path(size_t index) noexcept { return layers[index].get_layer_full_path(); }
762 fs::path FrameworkEnvironment::get_layer_manifest_path(size_t index) noexcept { return layers[index].get_layer_manifest_path(); }
763 fs::path FrameworkEnvironment::get_shimmed_layer_manifest_path(size_t index) noexcept {
764     return layers[index].get_shimmed_manifest_path();
765 }
766 
767 fs::FolderManager& FrameworkEnvironment::get_folder(ManifestLocation location) noexcept {
768     // index it directly using the enum location since they will always be in that order
769     return folders.at(static_cast<size_t>(location));
770 }
771 fs::FolderManager const& FrameworkEnvironment::get_folder(ManifestLocation location) const noexcept {
772     return folders.at(static_cast<size_t>(location));
773 }
774 #if defined(__APPLE__)
775 void FrameworkEnvironment::setup_macos_bundle() noexcept {
776     platform_shim->bundle_contents = get_folder(ManifestLocation::macos_bundle).location().str();
777 }
778 #endif
779 
780 std::vector<VkExtensionProperties> FrameworkEnvironment::GetInstanceExtensions(uint32_t expected_count, const char* layer_name) {
781     uint32_t count = 0;
782     VkResult res = vulkan_functions.vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr);
783     EXPECT_EQ(VK_SUCCESS, res);
784     EXPECT_EQ(count, expected_count);
785     std::vector<VkExtensionProperties> extension_props{count};
786     res = vulkan_functions.vkEnumerateInstanceExtensionProperties(layer_name, &count, extension_props.data());
787     EXPECT_EQ(VK_SUCCESS, res);
788     EXPECT_EQ(count, expected_count);
789     return extension_props;
790 }
791 std::vector<VkLayerProperties> FrameworkEnvironment::GetLayerProperties(uint32_t expected_count) {
792     uint32_t count = 0;
793     VkResult res = vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr);
794     EXPECT_EQ(VK_SUCCESS, res);
795     EXPECT_EQ(count, expected_count);
796     std::vector<VkLayerProperties> layer_props{count};
797     res = vulkan_functions.vkEnumerateInstanceLayerProperties(&count, layer_props.data());
798     EXPECT_EQ(VK_SUCCESS, res);
799     EXPECT_EQ(count, expected_count);
800     return layer_props;
801 }
802 
803 template <typename CreationFunc, typename CreateInfo>
804 VkResult create_surface_helper(VulkanFunctions* functions, VkInstance inst, VkSurfaceKHR& surface, const char* load_func_name) {
805     CreationFunc pfn_CreateSurface = functions->load(inst, load_func_name);
806     if (!pfn_CreateSurface) return VK_ERROR_EXTENSION_NOT_PRESENT;
807     CreateInfo surf_create_info{};
808     return pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface);
809 }
810 VkResult create_surface(VulkanFunctions* functions, VkInstance inst, VkSurfaceKHR& surface,
811                         [[maybe_unused]] const char* api_selection) {
812 #if defined(VK_USE_PLATFORM_ANDROID_KHR)
813     return create_surface_helper<PFN_vkCreateAndroidSurfaceKHR, VkAndroidSurfaceCreateInfoKHR>(functions, inst, surface,
814                                                                                                "vkCreateAndroidSurfaceKHR");
815 #elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
816     return create_surface_helper<PFN_vkCreateDirectFBSurfaceEXT, VkDirectFBSurfaceCreateInfoEXT>(functions, inst, surface,
817                                                                                                  "vkCreateDirectFBSurfaceEXT");
818 #elif defined(VK_USE_PLATFORM_FUCHSIA)
819     return create_surface_helper<PFN_vkCreateImagePipeSurfaceFUCHSIA, VkImagePipeSurfaceCreateInfoFUCHSIA>(
820         functions, inst, surface, "vkCreateImagePipeSurfaceFUCHSIA");
821 #elif defined(VK_USE_PLATFORM_GGP)
822     return create_surface_helper<PFN__vkCreateStreamDescriptorSurfaceGGP, VkStreamDescriptorSurfaceCreateInfoGGP>(
823         functions, inst, surface, "vkCreateStreamDescriptorSurfaceGGP");
824 #elif defined(VK_USE_PLATFORM_IOS_MVK)
825     return create_surface_helper<PFN_vkCreateIOSSurfaceMVK, VkIOSSurfaceCreateInfoMVK>(functions, inst, surface,
826                                                                                        "vkCreateIOSSurfaceMVK");
827 #elif defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)
828 #if defined(VK_USE_PLATFORM_MACOS_MVK)
829     if (api_selection != nullptr && string_eq(api_selection, "VK_USE_PLATFORM_MACOS_MVK"))
830         return create_surface_helper<PFN_vkCreateMacOSSurfaceMVK, VkMacOSSurfaceCreateInfoMVK>(functions, inst, surface,
831                                                                                                "vkCreateMacOSSurfaceMVK");
832 #endif
833 #if defined(VK_USE_PLATFORM_METAL_EXT)
834     if (api_selection == nullptr || (api_selection != nullptr && string_eq(api_selection, "VK_USE_PLATFORM_METAL_EXT")))
835         return create_surface_helper<PFN_vkCreateMetalSurfaceEXT, VkMetalSurfaceCreateInfoEXT>(functions, inst, surface,
836                                                                                                "vkCreateMetalSurfaceEXT");
837 #endif
838     return VK_ERROR_NOT_PERMITTED_KHR;
839 #elif defined(VK_USE_PLATFORM_SCREEN_QNX)
840     return create_surface_helper<PFN_vkCreateScreenSurfaceQNX, VkScreenSurfaceCreateInfoQNX>(functions, inst, surface,
841                                                                                              "vkCreateScreenSurfaceQNX");
842 #elif defined(VK_USE_PLATFORM_VI_NN)
843     return create_surface_helper<PFN_vkCreateViSurfaceNN, VkViSurfaceCreateInfoNN>(functions, inst, surface, "vkCreateViSurfaceNN");
844 #elif defined(VK_USE_PLATFORM_WIN32_KHR)
845     return create_surface_helper<PFN_vkCreateWin32SurfaceKHR, VkWin32SurfaceCreateInfoKHR>(functions, inst, surface,
846                                                                                            "vkCreateWin32SurfaceKHR");
847 #elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
848 #if defined(VK_USE_PLATFORM_XLIB_KHR)
849     if (string_eq(api_selection, "VK_USE_PLATFORM_XLIB_KHR"))
850         return create_surface_helper<PFN_vkCreateXlibSurfaceKHR, VkXlibSurfaceCreateInfoKHR>(functions, inst, surface,
851                                                                                              "vkCreateXlibSurfaceKHR");
852 #endif
853 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
854     if (string_eq(api_selection, "VK_USE_PLATFORM_WAYLAND_KHR"))
855         return create_surface_helper<PFN_vkCreateWaylandSurfaceKHR, VkWaylandSurfaceCreateInfoKHR>(functions, inst, surface,
856                                                                                                    "vkCreateWaylandSurfaceKHR");
857 #endif
858 #if defined(VK_USE_PLATFORM_XCB_KHR)
859     if (api_selection == nullptr || string_eq(api_selection, "VK_USE_PLATFORM_XCB_KHR"))
860         return create_surface_helper<PFN_vkCreateXcbSurfaceKHR, VkXcbSurfaceCreateInfoKHR>(functions, inst, surface,
861                                                                                            "vkCreateXcbSurfaceKHR");
862 #endif
863     return VK_ERROR_NOT_PERMITTED_KHR;
864 #else
865     return create_surface_helper<PFN_vkCreateDisplayPlaneSurfaceKHR, VkDisplaySurfaceCreateInfoKHR>(
866         functions, inst, surface, "vkCreateDisplayPlaneSurfaceKHR");
867 #endif
868 }
869 VkResult create_surface(InstWrapper& inst, VkSurfaceKHR& surface, const char* api_selection) {
870     return create_surface(inst.functions, inst.inst, surface, api_selection);
871 }
872 
873 extern "C" {
874 void __ubsan_on_report() { FAIL() << "Encountered an undefined behavior sanitizer error"; }
875 void __asan_on_error() { FAIL() << "Encountered an address sanitizer error"; }
876 void __tsan_on_report() { FAIL() << "Encountered a thread sanitizer error"; }
877 }  // extern "C"
878