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