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
83template <typename T>
84void handle_assert_has_value(T const& handle) {
85    ASSERT_TRUE(handle != VK_NULL_HANDLE);
86}
87template <typename T>
88void handle_assert_null(T const& handle) {
89    ASSERT_TRUE(handle == VK_NULL_HANDLE);
90}
91template <typename T>
92void handle_assert_has_values(std::vector<T> const& handles) {
93    for (auto const& handle : handles) {
94        ASSERT_TRUE(handle != VK_NULL_HANDLE);
95    }
96}
97template <typename T>
98void handle_assert_no_values(std::vector<T> const& handles) {
99    for (auto const& handle : handles) {
100        ASSERT_TRUE(handle == VK_NULL_HANDLE);
101    }
102}
103template <typename T>
104void 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}
109template <typename T>
110void handle_assert_equal(T const& left, T const& right) {
111    ASSERT_EQ(left, right);
112}
113template <typename T>
114void 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}
120template <typename T>
121void 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
129struct 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
240    FromVoidStarFunc load(VkInstance inst, const char* func_name) const {
241        return FromVoidStarFunc(vkGetInstanceProcAddr(inst, func_name));
242    }
243
244    FromVoidStarFunc load(VkDevice device, const char* func_name) const {
245        return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
246    }
247};
248
249struct 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
263    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
269struct 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
285    operator VkInstance() { return inst; }
286    VulkanFunctions* operator->() { return functions; }
287
288    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
314struct 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
329    operator VkDevice() { return dev; }
330    operator VkDevice() const { return dev; }
331    VulkanFunctions* operator->() { return functions; }
332
333    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
341struct DebugUtilsLogger {
342    static VkBool32 VKAPI_PTR
343    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    }
351    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
371    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
378    void clear() { returned_output.clear(); }
379    VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return &create_info; }
380    VkDebugUtilsMessengerCreateInfoEXT create_info{};
381    std::string returned_output;
382};
383
384struct DebugUtilsWrapper {
385    DebugUtilsWrapper() noexcept {}
386    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
407    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
418VkResult 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
422void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsLogger& logger);
423void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsWrapper& wrapper);
424
425struct 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};
431inline 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}
435inline bool operator!=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(a == b); }
436inline bool operator<(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) {
437    return a.name < b.name;
438}
439inline bool operator>(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return (b < a); }
440inline bool operator<=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(b < a); }
441inline bool operator>=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(a < b); }
442
443// Log files and their associated filter
444struct LoaderLogConfiguration {
445    BUILDER_VECTOR(LoaderLogConfiguration, std::string, destinations, destination)
446    BUILDER_VECTOR(LoaderLogConfiguration, std::string, filters, filter)
447};
448struct 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
455struct LoaderSettings {
456    BUILDER_VALUE(LoaderSettings, ManifestVersion, file_format_version, {})
457    BUILDER_VECTOR(LoaderSettings, AppSpecificSettings, app_specific_settings, app_specific_setting);
458};
459
460struct FrameworkEnvironment;  // forward declaration
461
462struct 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
469    PlatformShim* operator->() { return platform_shim; }
470
471    LibraryWrapper shim_library;
472    PlatformShim* platform_shim = nullptr;
473    EnvVarWrapper loader_logging;
474};
475
476struct 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};
492struct 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
510enum 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
522enum 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
528struct 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
544struct TestLayerDetails {
545    TestLayerDetails(ManifestLayer layer_manifest, const std::string& json_name) noexcept
546        : 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
558enum 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
573struct 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
580struct 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
653VkResult create_surface(InstWrapper& inst, VkSurfaceKHR& out_surface, const char* api_selection = nullptr);
654// Alternate parameter list for allocation callback tests
655VkResult create_surface(VulkanFunctions* functions, VkInstance inst, VkSurfaceKHR& surface, const char* api_selection = nullptr);
656