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 /*
29  * The test_environment is what combines the icd, layer, and shim library into a single object that
30  * test fixtures can create and use. Responsible for loading the libraries and establishing the
31  * channels for tests to talk with the icd's and layers.
32  */
33 #pragma once
34 
35 // Must include gtest first to guard against Xlib colliding due to redefinitions of "None" and "Bool"
36 
37 #if defined(_MSC_VER)
38 #pragma warning(push)
39 /*
40     MSVC warnings 4251 and 4275 have to do with potential dll-interface mismatch
41     between library (gtest) and users. Since we build the gtest library
42     as part of the test build we know that the dll-interface will match and
43     can disable these warnings.
44  */
45 #pragma warning(disable : 4251)
46 #pragma warning(disable : 4275)
47 #endif
48 
49 // GTest and Xlib collide due to redefinitions of "None" and "Bool"
50 #if defined(VK_USE_PLATFORM_XLIB_KHR)
51 #pragma push_macro("None")
52 #pragma push_macro("Bool")
53 #undef None
54 #undef Bool
55 #endif
56 
57 #if defined(_WIN32)
58 #if !defined(NOMINMAX)
59 #define NOMINMAX
60 #endif
61 #endif
62 
63 // Use the NDK's header on Android
64 #include "gtest/gtest.h"
65 
66 #include "test_util.h"
67 
68 #include "shim/shim.h"
69 
70 #include "icd/physical_device.h"
71 #include "icd/test_icd.h"
72 
73 #include "layer/test_layer.h"
74 
75 // Useful defines
76 #if COMMON_UNIX_PLATFORMS
77 #define HOME_DIR "/home/fake_home"
78 #define USER_LOCAL_SHARE_DIR HOME_DIR "/.local/share"
79 #define ETC_DIR "/etc"
80 #endif
81 
82 // handle checking
83 template <typename T>
handle_assert_has_value(T const& handle)84 void handle_assert_has_value(T const& handle) {
85     ASSERT_TRUE(handle != VK_NULL_HANDLE);
86 }
87 template <typename T>
handle_assert_null(T const& handle)88 void handle_assert_null(T const& handle) {
89     ASSERT_TRUE(handle == VK_NULL_HANDLE);
90 }
91 template <typename T>
handle_assert_has_values(std::vector<T> const& handles)92 void handle_assert_has_values(std::vector<T> const& handles) {
93     for (auto const& handle : handles) {
94         ASSERT_TRUE(handle != VK_NULL_HANDLE);
95     }
96 }
97 template <typename T>
handle_assert_no_values(std::vector<T> const& handles)98 void handle_assert_no_values(std::vector<T> const& handles) {
99     for (auto const& handle : handles) {
100         ASSERT_TRUE(handle == VK_NULL_HANDLE);
101     }
102 }
103 template <typename T>
handle_assert_no_values(size_t length, T handles[])104 void handle_assert_no_values(size_t length, T handles[]) {
105     for (size_t i = 0; i < length; i++) {
106         ASSERT_TRUE(handles[i] == VK_NULL_HANDLE);
107     }
108 }
109 template <typename T>
handle_assert_equal(T const& left, T const& right)110 void handle_assert_equal(T const& left, T const& right) {
111     ASSERT_EQ(left, right);
112 }
113 template <typename T>
handle_assert_equal(std::vector<T> const& left, std::vector<T> const& right)114 void handle_assert_equal(std::vector<T> const& left, std::vector<T> const& right) {
115     ASSERT_EQ(left.size(), right.size());
116     for (size_t i = 0; i < left.size(); i++) {
117         ASSERT_EQ(left[i], right[i]);
118     }
119 }
120 template <typename T>
handle_assert_equal(size_t count, T left[], T right[])121 void handle_assert_equal(size_t count, T left[], T right[]) {
122     for (size_t i = 0; i < count; i++) {
123         ASSERT_EQ(left[i], right[i]);
124     }
125 }
126 
127 // VulkanFunctions - loads vulkan functions for tests to use
128 
129 struct VulkanFunctions {
130 #if !defined(APPLE_STATIC_LOADER)
131     LibraryWrapper loader;
132 #endif
133     // Pre-Instance
134     PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;
135     PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = nullptr;
136     PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties = nullptr;
137     PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = nullptr;
138     PFN_vkCreateInstance vkCreateInstance = nullptr;
139 
140     // Instance
141     PFN_vkDestroyInstance vkDestroyInstance = nullptr;
142     PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr;
143     PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups = nullptr;
144     PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures = nullptr;
145     PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2 = nullptr;
146     PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties = nullptr;
147     PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2 = nullptr;
148     PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties = nullptr;
149     PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2 = nullptr;
150     PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties = nullptr;
151     PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2 = nullptr;
152     PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties = nullptr;
153     PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2 = nullptr;
154     PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
155     PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
156     PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = nullptr;
157     PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2 = nullptr;
158     PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
159     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
160     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
161     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
162     PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties = nullptr;
163     PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties = nullptr;
164     PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties = nullptr;
165     PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties = nullptr;
166     PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties = nullptr;
167 
168     PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
169     PFN_vkCreateDevice vkCreateDevice = nullptr;
170     PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
171     PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
172 
173     // WSI
174     PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT = nullptr;
175     PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR = nullptr;
176     PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR = nullptr;
177     PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR = nullptr;
178     PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR = nullptr;
179     PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR = nullptr;
180     PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR = nullptr;
181     PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR = nullptr;
182     PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR = nullptr;
183     PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR = nullptr;
184     PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR = nullptr;
185     PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR = nullptr;
186     PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR = nullptr;
187     PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR = nullptr;
188     PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR = nullptr;
189 
190 #if defined(VK_USE_PLATFORM_ANDROID_KHR)
191     PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR = nullptr;
192 #endif  // VK_USE_PLATFORM_ANDROID_KHR
193 #if defined(VK_USE_PLATFORM_DIRECTFB_EXT)
194     PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT = nullptr;
195     PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT = nullptr;
196 #endif  // VK_USE_PLATFORM_DIRECTFB_EXT
197 #if defined(VK_USE_PLATFORM_FUCHSIA)
198     PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
199 #endif  // VK_USE_PLATFORM_FUCHSIA
200 #if defined(VK_USE_PLATFORM_GGP)
201     PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP = nullptr;
202 #endif  // VK_USE_PLATFORM_GGP
203 #if defined(VK_USE_PLATFORM_IOS_MVK)
204     PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK = nullptr;
205 #endif  // VK_USE_PLATFORM_IOS_MVK
206 #if defined(VK_USE_PLATFORM_MACOS_MVK)
207     PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = nullptr;
208 #endif  // VK_USE_PLATFORM_MACOS_MVK
209 #if defined(VK_USE_PLATFORM_METAL_EXT)
210     PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT = nullptr;
211 #endif  // VK_USE_PLATFORM_METAL_EXT
212 #if defined(VK_USE_PLATFORM_SCREEN_QNX)
213     PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX = nullptr;
214     PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX = nullptr;
215 #endif  // VK_USE_PLATFORM_SCREEN_QNX
216 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
217     PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR = nullptr;
218     PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = nullptr;
219 #endif  // VK_USE_PLATFORM_WAYLAND_KHR
220 #if defined(VK_USE_PLATFORM_XCB_KHR)
221     PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR = nullptr;
222     PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = nullptr;
223 #endif  // VK_USE_PLATFORM_XCB_KHR
224 #if defined(VK_USE_PLATFORM_XLIB_KHR)
225     PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = nullptr;
226     PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = nullptr;
227 #endif  // VK_USE_PLATFORM_XLIB_KHR
228 #if defined(VK_USE_PLATFORM_WIN32_KHR)
229     PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = nullptr;
230     PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = nullptr;
231 #endif  // VK_USE_PLATFORM_WIN32_KHR
232     PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = nullptr;
233 
234     // device functions
235     PFN_vkDestroyDevice vkDestroyDevice = nullptr;
236     PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
237 
238     VulkanFunctions();
239 
loadVulkanFunctions240     FromVoidStarFunc load(VkInstance inst, const char* func_name) const {
241         return FromVoidStarFunc(vkGetInstanceProcAddr(inst, func_name));
242     }
243 
loadVulkanFunctions244     FromVoidStarFunc load(VkDevice device, const char* func_name) const {
245         return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
246     }
247 };
248 
249 struct DeviceFunctions {
250     PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
251     PFN_vkDestroyDevice vkDestroyDevice = nullptr;
252     PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
253     PFN_vkCreateCommandPool vkCreateCommandPool = nullptr;
254     PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers = nullptr;
255     PFN_vkDestroyCommandPool vkDestroyCommandPool = nullptr;
256     PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
257     PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = nullptr;
258     PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = nullptr;
259 
260     DeviceFunctions() = default;
261     DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device);
262 
loadDeviceFunctions263     FromVoidStarFunc load(VkDevice device, const char* func_name) const {
264         return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
265     }
266 };
267 
268 // InstWrapper & DeviceWrapper - used to make creating instances & devices easier when writing tests
269 struct InstWrapper {
270     InstWrapper(VulkanFunctions& functions, VkAllocationCallbacks* callbacks = nullptr) noexcept;
271     InstWrapper(VulkanFunctions& functions, VkInstance inst, VkAllocationCallbacks* callbacks = nullptr) noexcept;
272     ~InstWrapper() noexcept;
273 
274     // Move-only object
275     InstWrapper(InstWrapper const&) = delete;
276     InstWrapper& operator=(InstWrapper const&) = delete;
277     InstWrapper(InstWrapper&& other) noexcept;
278     InstWrapper& operator=(InstWrapper&&) noexcept;
279 
280     // Construct this VkInstance using googletest to assert if it succeeded
281     void CheckCreate(VkResult result_to_check = VK_SUCCESS);
282     void CheckCreateWithInfo(InstanceCreateInfo& create_info, VkResult result_to_check = VK_SUCCESS);
283 
284     // Convenience
operator VkInstanceInstWrapper285     operator VkInstance() { return inst; }
operator ->InstWrapper286     VulkanFunctions* operator->() { return functions; }
287 
loadInstWrapper288     FromVoidStarFunc load(const char* func_name) { return FromVoidStarFunc(functions->vkGetInstanceProcAddr(inst, func_name)); }
289 
290     // Enumerate physical devices using googletest to assert if it succeeded
291     std::vector<VkPhysicalDevice> GetPhysDevs(VkResult result_to_check = VK_SUCCESS);  // query all physical devices
292     std::vector<VkPhysicalDevice> GetPhysDevs(uint32_t phys_dev_count,
293                                               VkResult result_to_check = VK_SUCCESS);  // query only phys_dev_count devices
294     // Enumerate a single physical device using googletest to assert if it succeeded
295     VkPhysicalDevice GetPhysDev(VkResult result_to_check = VK_SUCCESS);
296 
297     // Get all the list of active layers through vkEnumerateDeviceLayerProperties
298     // Use count to specify the expected count
299     std::vector<VkLayerProperties> GetActiveLayers(VkPhysicalDevice phys_dev, uint32_t count);
300 
301     // Get list of device extensions associated with a VkPhysicalDevice
302     // Use count to specify an expected count
303     std::vector<VkExtensionProperties> EnumerateDeviceExtensions(VkPhysicalDevice physical_device, uint32_t count);
304     // Same as EnumerateDeviceExtensions but for a specific layer
305     std::vector<VkExtensionProperties> EnumerateLayerDeviceExtensions(VkPhysicalDevice physical_device, const char* layer_name,
306                                                                       uint32_t expected_count);
307 
308     VulkanFunctions* functions = nullptr;
309     VkInstance inst = VK_NULL_HANDLE;
310     VkAllocationCallbacks* callbacks = nullptr;
311     InstanceCreateInfo create_info{};
312 };
313 
314 struct DeviceWrapper {
315     DeviceWrapper(InstWrapper& inst_wrapper, VkAllocationCallbacks* callbacks = nullptr) noexcept;
316     DeviceWrapper(VulkanFunctions& functions, VkDevice device, VkAllocationCallbacks* callbacks = nullptr) noexcept;
317     ~DeviceWrapper() noexcept;
318 
319     // Move-only object
320     DeviceWrapper(DeviceWrapper const&) = delete;
321     DeviceWrapper& operator=(DeviceWrapper const&) = delete;
322     DeviceWrapper(DeviceWrapper&&) noexcept;
323     DeviceWrapper& operator=(DeviceWrapper&&) noexcept;
324 
325     // Construct this VkDevice using googletest to assert if it succeeded
326     void CheckCreate(VkPhysicalDevice physical_device, VkResult result_to_check = VK_SUCCESS);
327 
328     // Convenience
operator VkDeviceDeviceWrapper329     operator VkDevice() { return dev; }
operator VkDeviceDeviceWrapper330     operator VkDevice() const { return dev; }
operator ->DeviceWrapper331     VulkanFunctions* operator->() { return functions; }
332 
loadDeviceWrapper333     FromVoidStarFunc load(const char* func_name) { return FromVoidStarFunc(functions->vkGetDeviceProcAddr(dev, func_name)); }
334 
335     VulkanFunctions* functions = nullptr;
336     VkDevice dev = VK_NULL_HANDLE;
337     VkAllocationCallbacks* callbacks = nullptr;
338     DeviceCreateInfo create_info{};
339 };
340 
341 struct DebugUtilsLogger {
342     static VkBool32 VKAPI_PTR
DebugUtilsMessengerLoggerCallbackDebugUtilsLogger343     DebugUtilsMessengerLoggerCallback([[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
344                                       [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT messageTypes,
345                                       const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {
346         DebugUtilsLogger* debug = reinterpret_cast<DebugUtilsLogger*>(pUserData);
347         debug->returned_output += pCallbackData->pMessage;
348         debug->returned_output += '\n';
349         return VK_FALSE;
350     }
DebugUtilsLoggerDebugUtilsLogger351     DebugUtilsLogger(VkDebugUtilsMessageSeverityFlagsEXT severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
352                                                                     VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
353                                                                     VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
354                                                                     VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
355         returned_output.reserve(4096);  // output can be very noisy, reserving should help prevent many small allocations
356         create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
357         create_info.pNext = nullptr;
358         create_info.messageSeverity = severity;
359         create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
360                                   VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
361         create_info.pfnUserCallback = DebugUtilsMessengerLoggerCallback;
362         create_info.pUserData = this;
363     }
364 
365     // Immoveable object
366     DebugUtilsLogger(DebugUtilsLogger const&) = delete;
367     DebugUtilsLogger& operator=(DebugUtilsLogger const&) = delete;
368     DebugUtilsLogger(DebugUtilsLogger&&) = delete;
369     DebugUtilsLogger& operator=(DebugUtilsLogger&&) = delete;
370     // Find a string in the log output
findDebugUtilsLogger371     bool find(std::string const& search_text) const { return returned_output.find(search_text) != std::string::npos; }
372 
373     // Look through the event log. If you find a line containing the prefix we're interested in, look for the end of
374     // line character, and then see if the postfix occurs in it as well.
375     bool find_prefix_then_postfix(const char* prefix, const char* postfix) const;
376 
377     // Clear the log
clearDebugUtilsLogger378     void clear() { returned_output.clear(); }
379     VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return &create_info; }
380     VkDebugUtilsMessengerCreateInfoEXT create_info{};
381     std::string returned_output;
382 };
383 
384 struct DebugUtilsWrapper {
385     DebugUtilsWrapper() noexcept {}
DebugUtilsWrapperDebugUtilsWrapper386     DebugUtilsWrapper(InstWrapper& inst_wrapper,
387                       VkDebugUtilsMessageSeverityFlagsEXT severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
388                                                                      VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
389                       VkAllocationCallbacks* callbacks = nullptr)
390         : logger(severity), inst(inst_wrapper.inst), callbacks(callbacks) {
391         vkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
392             inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkCreateDebugUtilsMessengerEXT"));
393         vkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
394             inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkDestroyDebugUtilsMessengerEXT"));
395     };
396     ~DebugUtilsWrapper() noexcept {
397         if (messenger) {
398             vkDestroyDebugUtilsMessengerEXT(inst, messenger, callbacks);
399         }
400     }
401     // Immoveable object
402     DebugUtilsWrapper(DebugUtilsWrapper const&) = delete;
403     DebugUtilsWrapper& operator=(DebugUtilsWrapper const&) = delete;
404     DebugUtilsWrapper(DebugUtilsWrapper&&) = delete;
405     DebugUtilsWrapper& operator=(DebugUtilsWrapper&&) = delete;
406 
findDebugUtilsWrapper407     bool find(std::string const& search_text) { return logger.find(search_text); }
408     VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return logger.get(); }
409 
410     DebugUtilsLogger logger;
411     VkInstance inst = VK_NULL_HANDLE;
412     VkAllocationCallbacks* callbacks = nullptr;
413     PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
414     PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
415     VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
416 };
417 
418 VkResult CreateDebugUtilsMessenger(DebugUtilsWrapper& debug_utils);
419 
420 // Helper that adds the debug utils extension name and sets the pNext chain up
421 // NOTE: Ignores existing pNext chains
422 void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsLogger& logger);
423 void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsWrapper& wrapper);
424 
425 struct LoaderSettingsLayerConfiguration {
426     BUILDER_VALUE(LoaderSettingsLayerConfiguration, std::string, name, {})
427     BUILDER_VALUE(LoaderSettingsLayerConfiguration, std::string, path, {})
428     BUILDER_VALUE(LoaderSettingsLayerConfiguration, std::string, control, {})
429     BUILDER_VALUE(LoaderSettingsLayerConfiguration, bool, treat_as_implicit_manifest, false)
430 };
operator ==(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b)431 inline bool operator==(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) {
432     return a.name == b.name && a.path == b.path && a.control == b.control &&
433            a.treat_as_implicit_manifest == b.treat_as_implicit_manifest;
434 }
operator !=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b)435 inline bool operator!=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(a == b); }
operator <(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b)436 inline bool operator<(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) {
437     return a.name < b.name;
438 }
operator >(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b)439 inline bool operator>(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return (b < a); }
operator <=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b)440 inline bool operator<=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(b < a); }
operator >=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b)441 inline bool operator>=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(a < b); }
442 
443 // Log files and their associated filter
444 struct LoaderLogConfiguration {
445     BUILDER_VECTOR(LoaderLogConfiguration, std::string, destinations, destination)
446     BUILDER_VECTOR(LoaderLogConfiguration, std::string, filters, filter)
447 };
448 struct AppSpecificSettings {
449     BUILDER_VECTOR(AppSpecificSettings, std::string, app_keys, app_key)
450     BUILDER_VECTOR(AppSpecificSettings, LoaderSettingsLayerConfiguration, layer_configurations, layer_configuration)
451     BUILDER_VECTOR(AppSpecificSettings, std::string, stderr_log, stderr_log_filter)
452     BUILDER_VECTOR(AppSpecificSettings, LoaderLogConfiguration, log_configurations, log_configuration)
453 };
454 
455 struct LoaderSettings {
456     BUILDER_VALUE(LoaderSettings, ManifestVersion, file_format_version, {})
457     BUILDER_VECTOR(LoaderSettings, AppSpecificSettings, app_specific_settings, app_specific_setting);
458 };
459 
460 struct FrameworkEnvironment;  // forward declaration
461 
462 struct PlatformShimWrapper {
463     PlatformShimWrapper(std::vector<fs::FolderManager>* folders, const char* log_filter) noexcept;
464     ~PlatformShimWrapper() noexcept;
465     PlatformShimWrapper(PlatformShimWrapper const&) = delete;
466     PlatformShimWrapper& operator=(PlatformShimWrapper const&) = delete;
467 
468     // Convenience
operator ->PlatformShimWrapper469     PlatformShim* operator->() { return platform_shim; }
470 
471     LibraryWrapper shim_library;
472     PlatformShim* platform_shim = nullptr;
473     EnvVarWrapper loader_logging;
474 };
475 
476 struct TestICDHandle {
477     TestICDHandle() noexcept;
478     TestICDHandle(fs::path const& icd_path) noexcept;
479     TestICD& reset_icd() noexcept;
480     TestICD& get_test_icd() noexcept;
481     fs::path get_icd_full_path() noexcept;
482     fs::path get_icd_manifest_path() noexcept;
483     fs::path get_shimmed_manifest_path() noexcept;
484 
485     // Must use statically
486     LibraryWrapper icd_library;
487     GetTestICDFunc proc_addr_get_test_icd = nullptr;
488     GetNewTestICDFunc proc_addr_reset_icd = nullptr;
489     fs::path manifest_path;  // path to the manifest file is on the actual filesystem (aka <build_folder>/tests/framework/<...>)
490     fs::path shimmed_manifest_path;  // path to where the loader will find the manifest file (eg /usr/local/share/vulkan/<...>)
491 };
492 struct TestLayerHandle {
493     TestLayerHandle() noexcept;
494     TestLayerHandle(fs::path const& layer_path) noexcept;
495     TestLayer& reset_layer() noexcept;
496     TestLayer& get_test_layer() noexcept;
497     fs::path get_layer_full_path() noexcept;
498     fs::path get_layer_manifest_path() noexcept;
499     fs::path get_shimmed_manifest_path() noexcept;
500 
501     // Must use statically
502     LibraryWrapper layer_library;
503     GetTestLayerFunc proc_addr_get_test_layer = nullptr;
504     GetNewTestLayerFunc proc_addr_reset_layer = nullptr;
505     fs::path manifest_path;  // path to the manifest file is on the actual filesystem (aka <build_folder>/tests/framework/<...>)
506     fs::path shimmed_manifest_path;  // path to where the loader will find the manifest file (eg /usr/local/share/vulkan/<...>)
507 };
508 
509 // Controls whether to create a manifest and where to put it
510 enum class ManifestDiscoveryType {
511     generic,              // put the manifest in the regular locations
512     unsecured_generic,    // put the manifest in a user folder rather than system
513     none,                 // Do not write the manifest anywhere (for Direct Driver Loading)
514     null_dir,             // put the manifest in the 'null_dir' which the loader does not search in (D3DKMT for instance)
515     env_var,              // use the corresponding env-var for it
516     add_env_var,          // use the corresponding add-env-var for it
517     override_folder,      // add to a special folder for the override layer to use
518     windows_app_package,  // let the app package search find it
519     macos_bundle,         // place it in a location only accessible to macos bundles
520 };
521 
522 enum class LibraryPathType {
523     absolute,              // default for testing - the exact path of the binary
524     relative,              // Relative to the manifest file
525     default_search_paths,  // Dont add any path information to the library_path - force the use of the default search paths
526 };
527 
528 struct TestICDDetails {
529     TestICDDetails(ManifestICD icd_manifest) noexcept : icd_manifest(icd_manifest) {}
530     TestICDDetails(fs::path icd_binary_path, uint32_t api_version = VK_API_VERSION_1_0) noexcept {
531         icd_manifest.set_lib_path(icd_binary_path.str()).set_api_version(api_version);
532     }
533     BUILDER_VALUE(TestICDDetails, ManifestICD, icd_manifest, {});
534     BUILDER_VALUE(TestICDDetails, std::string, json_name, "test_icd");
535     // Uses the json_name without modification - default is to append _1 in the json file to distinguish drivers
536     BUILDER_VALUE(TestICDDetails, bool, disable_icd_inc, false);
537     BUILDER_VALUE(TestICDDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
538     BUILDER_VALUE(TestICDDetails, bool, is_fake, false);
539     // If discovery type is env-var, is_dir controls whether to use the path to the file or folder the manifest is in
540     BUILDER_VALUE(TestICDDetails, bool, is_dir, false);
541     BUILDER_VALUE(TestICDDetails, LibraryPathType, library_path_type, LibraryPathType::absolute);
542 };
543 
544 struct TestLayerDetails {
545     TestLayerDetails(ManifestLayer layer_manifest, const std::string& json_name) noexcept
json_nameTestLayerDetails546         : layer_manifest(layer_manifest), json_name(json_name) {}
547     BUILDER_VALUE(TestLayerDetails, ManifestLayer, layer_manifest, {});
548     BUILDER_VALUE(TestLayerDetails, std::string, json_name, "test_layer");
549     BUILDER_VALUE(TestLayerDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
550     BUILDER_VALUE(TestLayerDetails, bool, is_fake, false);
551     // If discovery type is env-var, is_dir controls whether to use the path to the file or folder the manifest is in
552     BUILDER_VALUE(TestLayerDetails, bool, is_dir, true);
553     BUILDER_VALUE(TestLayerDetails, LibraryPathType, library_path_type, LibraryPathType::absolute);
554 };
555 
556 // Locations manifests can go in the test framework
557 // If this enum is added to - the contructor of FrameworkEnvironment also needs to be updated with the new enum value
558 enum class ManifestLocation {
559     null = 0,
560     driver = 1,
561     driver_env_var = 2,
562     explicit_layer = 3,
563     explicit_layer_env_var = 4,
564     explicit_layer_add_env_var = 5,
565     implicit_layer = 6,
566     override_layer = 7,
567     windows_app_package = 8,
568     macos_bundle = 9,
569     unsecured_location = 10,
570     settings_location = 11,
571 };
572 
573 struct FrameworkSettings {
574     BUILDER_VALUE(FrameworkSettings, const char*, log_filter, "all");
575     BUILDER_VALUE(FrameworkSettings, bool, enable_default_search_paths, true);
576     BUILDER_VALUE(FrameworkSettings, LoaderSettings, loader_settings, {});
577     BUILDER_VALUE(FrameworkSettings, bool, secure_loader_settings, false);
578 };
579 
580 struct FrameworkEnvironment {
581     FrameworkEnvironment() noexcept;  // default is to enable VK_LOADER_DEBUG=all and enable the default search paths
582     FrameworkEnvironment(const FrameworkSettings& settings) noexcept;
583     ~FrameworkEnvironment();
584     // Delete copy constructors - this class should never move after being created
585     FrameworkEnvironment(const FrameworkEnvironment&) = delete;
586     FrameworkEnvironment& operator=(const FrameworkEnvironment&) = delete;
587 
588     TestICD& add_icd(TestICDDetails icd_details) noexcept;
589     void add_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
590     void add_implicit_layer(TestLayerDetails layer_details) noexcept;
591     void add_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
592     void add_explicit_layer(TestLayerDetails layer_details) noexcept;
593     void add_fake_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
594     void add_fake_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
595 
596     // resets the current settings with the values contained in loader_settings
597     void write_settings_file(std::string const& file_contents);
598     // apply any changes made to FrameworkEnvironment's loader_settings member
599     void update_loader_settings(const LoaderSettings& loader_settings) noexcept;
600     void remove_loader_settings();
601 
602     TestICD& get_test_icd(size_t index = 0) noexcept;
603     TestICD& reset_icd(size_t index = 0) noexcept;
604     fs::path get_test_icd_path(size_t index = 0) noexcept;
605     fs::path get_icd_manifest_path(size_t index = 0) noexcept;
606     fs::path get_shimmed_icd_manifest_path(size_t index = 0) noexcept;
607 
608     TestLayer& get_test_layer(size_t index = 0) noexcept;
609     TestLayer& reset_layer(size_t index = 0) noexcept;
610     fs::path get_test_layer_path(size_t index = 0) noexcept;
611     fs::path get_layer_manifest_path(size_t index = 0) noexcept;
612     fs::path get_shimmed_layer_manifest_path(size_t index = 0) noexcept;
613 
614     fs::FolderManager& get_folder(ManifestLocation location) noexcept;
615     fs::FolderManager const& get_folder(ManifestLocation location) const noexcept;
616 #if defined(__APPLE__)
617     // Set the path of the app bundle to the appropriate test framework bundle
618     void setup_macos_bundle() noexcept;
619 #endif
620 
621     FrameworkSettings settings;
622 
623     // Query the global extensions
624     // Optional: use layer_name to query the extensions of a specific layer
625     std::vector<VkExtensionProperties> GetInstanceExtensions(uint32_t count, const char* layer_name = nullptr);
626     // Query the available layers
627     std::vector<VkLayerProperties> GetLayerProperties(uint32_t count);
628 
629     PlatformShimWrapper platform_shim;
630     std::vector<fs::FolderManager> folders;
631 
632     DebugUtilsLogger debug_log;
633     VulkanFunctions vulkan_functions;
634 
635     std::vector<TestICDHandle> icds;
636     std::vector<TestLayerHandle> layers;
637 
638     EnvVarWrapper env_var_vk_icd_filenames{"VK_DRIVER_FILES"};
639     EnvVarWrapper add_env_var_vk_icd_filenames{"VK_ADD_DRIVER_FILES"};
640     EnvVarWrapper env_var_vk_layer_paths{"VK_LAYER_PATH"};
641     EnvVarWrapper add_env_var_vk_layer_paths{"VK_ADD_LAYER_PATH"};
642 
643     LoaderSettings loader_settings;  // the current settings written to disk
644    private:
645     void add_layer_impl(TestLayerDetails layer_details, ManifestCategory category);
646 };
647 
648 // Create a surface using a platform specific API
649 // api_selection: optionally provide a VK_USE_PLATFORM_XXX string to select which API to create a surface with.
650 //    defaults to Metal on macOS and XCB on linux if not provided
651 // Returns an VkResult with the result of surface creation
652 // returns VK_ERROR_EXTENSION_NOT_PRESENT if it fails to load the surface creation function
653 VkResult create_surface(InstWrapper& inst, VkSurfaceKHR& out_surface, const char* api_selection = nullptr);
654 // Alternate parameter list for allocation callback tests
655 VkResult create_surface(VulkanFunctions* functions, VkInstance inst, VkSurfaceKHR& surface, const char* api_selection = nullptr);
656