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