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