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
30fs::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
39void 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)
149VulkanFunctions::VulkanFunctions() {
150#else
151VulkanFunctions::VulkanFunctions() : loader(get_loader_path()) {
152#endif
153    init_vulkan_functions(*this);
154}
155
156DeviceFunctions::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
168InstWrapper::InstWrapper(VulkanFunctions& functions, VkAllocationCallbacks* callbacks) noexcept
169    : functions(&functions), callbacks(callbacks) {}
170InstWrapper::InstWrapper(VulkanFunctions& functions, VkInstance inst, VkAllocationCallbacks* callbacks) noexcept
171    : functions(&functions), inst(inst), callbacks(callbacks) {}
172InstWrapper::~InstWrapper() noexcept {
173    if (inst != VK_NULL_HANDLE) functions->vkDestroyInstance(inst, callbacks);
174}
175
176InstWrapper::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}
183InstWrapper& 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
193void InstWrapper::CheckCreate(VkResult result_to_check) {
194    ASSERT_EQ(result_to_check, functions->vkCreateInstance(create_info.get(), callbacks, &inst));
195}
196
197void InstWrapper::CheckCreateWithInfo(InstanceCreateInfo& create_info, VkResult result_to_check) {
198    ASSERT_EQ(result_to_check, functions->vkCreateInstance(create_info.get(), callbacks, &inst));
199}
200
201std::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
210std::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
221VkPhysicalDevice 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
229std::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
241std::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
254std::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
267DeviceWrapper::DeviceWrapper(InstWrapper& inst_wrapper, VkAllocationCallbacks* callbacks) noexcept
268    : functions(inst_wrapper.functions), callbacks(callbacks){};
269DeviceWrapper::DeviceWrapper(VulkanFunctions& functions, VkDevice device, VkAllocationCallbacks* callbacks) noexcept
270    : functions(&functions), dev(device), callbacks(callbacks){};
271DeviceWrapper::~DeviceWrapper() noexcept { functions->vkDestroyDevice(dev, callbacks); }
272
273DeviceWrapper::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}
280DeviceWrapper& 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
290void 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
294VkResult CreateDebugUtilsMessenger(DebugUtilsWrapper& debug_utils) {
295    return debug_utils.vkCreateDebugUtilsMessengerEXT(debug_utils.inst, debug_utils.get(), debug_utils.callbacks,
296                                                      &debug_utils.messenger);
297}
298
299void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsLogger& logger) {
300    create_info.add_extension("VK_EXT_debug_utils");
301    create_info.instance_info.pNext = logger.get();
302}
303void 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.
310bool 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
326bool FindPrefixPostfixStringOnLine(DebugUtilsLogger const& env_log, const char* prefix, const char* postfix) {
327    return env_log.find_prefix_then_postfix(prefix, postfix);
328}
329
330PlatformShimWrapper::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
347PlatformShimWrapper::~PlatformShimWrapper() noexcept { platform_shim->reset(); }
348
349TestICDHandle::TestICDHandle() noexcept {}
350TestICDHandle::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}
354TestICD& 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}
358TestICD& TestICDHandle::reset_icd() noexcept {
359    assert(proc_addr_reset_icd != NULL && "symbol must be loaded before use");
360    return *proc_addr_reset_icd();
361}
362fs::path TestICDHandle::get_icd_full_path() noexcept { return icd_library.lib_path; }
363fs::path TestICDHandle::get_icd_manifest_path() noexcept { return manifest_path; }
364fs::path TestICDHandle::get_shimmed_manifest_path() noexcept { return shimmed_manifest_path; }
365
366TestLayerHandle::TestLayerHandle() noexcept {}
367TestLayerHandle::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}
371TestLayer& 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}
375TestLayer& TestLayerHandle::reset_layer() noexcept {
376    assert(proc_addr_reset_layer != NULL && "symbol must be loaded before use");
377    return *proc_addr_reset_layer();
378}
379fs::path TestLayerHandle::get_layer_full_path() noexcept { return layer_library.lib_path; }
380fs::path TestLayerHandle::get_layer_manifest_path() noexcept { return manifest_path; }
381fs::path TestLayerHandle::get_shimmed_manifest_path() noexcept { return shimmed_manifest_path; }
382
383FrameworkEnvironment::FrameworkEnvironment() noexcept : FrameworkEnvironment(FrameworkSettings{}) {}
384FrameworkEnvironment::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
435FrameworkEnvironment::~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
443TestICD& 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
544void 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}
547void 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}
550void 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}
553void 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}
556void FrameworkEnvironment::add_implicit_layer(TestLayerDetails layer_details) noexcept {
557    add_layer_impl(layer_details, ManifestCategory::implicit_layer);
558}
559void FrameworkEnvironment::add_explicit_layer(TestLayerDetails layer_details) noexcept {
560    add_layer_impl(layer_details, ManifestCategory::explicit_layer);
561}
562
563void 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
665std::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}
733void 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}
744void FrameworkEnvironment::update_loader_settings(const LoaderSettings& settings) noexcept {
745    write_settings_file(get_loader_settings_file_contents(settings));
746}
747void FrameworkEnvironment::remove_loader_settings() {
748    get_folder(ManifestLocation::settings_location).remove("vk_loader_settings.json");
749}
750
751TestICD& FrameworkEnvironment::get_test_icd(size_t index) noexcept { return icds[index].get_test_icd(); }
752TestICD& FrameworkEnvironment::reset_icd(size_t index) noexcept { return icds[index].reset_icd(); }
753fs::path FrameworkEnvironment::get_test_icd_path(size_t index) noexcept { return icds[index].get_icd_full_path(); }
754fs::path FrameworkEnvironment::get_icd_manifest_path(size_t index) noexcept { return icds[index].get_icd_manifest_path(); }
755fs::path FrameworkEnvironment::get_shimmed_icd_manifest_path(size_t index) noexcept {
756    return icds[index].get_shimmed_manifest_path();
757}
758
759TestLayer& FrameworkEnvironment::get_test_layer(size_t index) noexcept { return layers[index].get_test_layer(); }
760TestLayer& FrameworkEnvironment::reset_layer(size_t index) noexcept { return layers[index].reset_layer(); }
761fs::path FrameworkEnvironment::get_test_layer_path(size_t index) noexcept { return layers[index].get_layer_full_path(); }
762fs::path FrameworkEnvironment::get_layer_manifest_path(size_t index) noexcept { return layers[index].get_layer_manifest_path(); }
763fs::path FrameworkEnvironment::get_shimmed_layer_manifest_path(size_t index) noexcept {
764    return layers[index].get_shimmed_manifest_path();
765}
766
767fs::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}
771fs::FolderManager const& FrameworkEnvironment::get_folder(ManifestLocation location) const noexcept {
772    return folders.at(static_cast<size_t>(location));
773}
774#if defined(__APPLE__)
775void FrameworkEnvironment::setup_macos_bundle() noexcept {
776    platform_shim->bundle_contents = get_folder(ManifestLocation::macos_bundle).location().str();
777}
778#endif
779
780std::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}
791std::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
803template <typename CreationFunc, typename CreateInfo>
804VkResult 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}
810VkResult 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}
869VkResult create_surface(InstWrapper& inst, VkSurfaceKHR& surface, const char* api_selection) {
870    return create_surface(inst.functions, inst.inst, surface, api_selection);
871}
872
873extern "C" {
874void __ubsan_on_report() { FAIL() << "Encountered an undefined behavior sanitizer error"; }
875void __asan_on_error() { FAIL() << "Encountered an address sanitizer error"; }
876void __tsan_on_report() { FAIL() << "Encountered a thread sanitizer error"; }
877}  // extern "C"
878