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