mirror of
https://gitee.com/openharmony/third_party_vulkan-loader
synced 2024-11-23 07:10:23 +00:00
0281b281d0
Signed-off-by: andrew0229 <zhangzhao62@huawei.com> Change-Id: Ifc4224db2c6ea7c159d3cabe8f075475d47a41a8
656 lines
32 KiB
C++
656 lines
32 KiB
C++
/*
|
|
* Copyright (c) 2021-2023 The Khronos Group Inc.
|
|
* Copyright (c) 2021-2023 Valve Corporation
|
|
* Copyright (c) 2021-2023 LunarG, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and/or associated documentation files (the "Materials"), to
|
|
* deal in the Materials without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Materials, and to permit persons to whom the Materials are
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice(s) and this permission notice shall be included in
|
|
* all copies or substantial portions of the Materials.
|
|
*
|
|
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
*
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
|
|
* USE OR OTHER DEALINGS IN THE MATERIALS.
|
|
*
|
|
* Author: Charles Giessen <charles@lunarg.com>
|
|
*/
|
|
|
|
/*
|
|
* The test_environment is what combines the icd, layer, and shim library into a single object that
|
|
* test fixtures can create and use. Responsible for loading the libraries and establishing the
|
|
* channels for tests to talk with the icd's and layers.
|
|
*/
|
|
#pragma once
|
|
|
|
// Must include gtest first to guard against Xlib colliding due to redefinitions of "None" and "Bool"
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(push)
|
|
/*
|
|
MSVC warnings 4251 and 4275 have to do with potential dll-interface mismatch
|
|
between library (gtest) and users. Since we build the gtest library
|
|
as part of the test build we know that the dll-interface will match and
|
|
can disable these warnings.
|
|
*/
|
|
#pragma warning(disable : 4251)
|
|
#pragma warning(disable : 4275)
|
|
#endif
|
|
|
|
// GTest and Xlib collide due to redefinitions of "None" and "Bool"
|
|
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
|
#pragma push_macro("None")
|
|
#pragma push_macro("Bool")
|
|
#undef None
|
|
#undef Bool
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
#if !defined(NOMINMAX)
|
|
#define NOMINMAX
|
|
#endif
|
|
#endif
|
|
|
|
// Use the NDK's header on Android
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "test_util.h"
|
|
|
|
#include "shim/shim.h"
|
|
|
|
#include "icd/physical_device.h"
|
|
#include "icd/test_icd.h"
|
|
|
|
#include "layer/test_layer.h"
|
|
|
|
// Useful defines
|
|
#if COMMON_UNIX_PLATFORMS
|
|
#define HOME_DIR "/home/fake_home"
|
|
#define USER_LOCAL_SHARE_DIR HOME_DIR "/.local/share"
|
|
#define ETC_DIR "/etc"
|
|
#endif
|
|
|
|
// handle checking
|
|
template <typename T>
|
|
void handle_assert_has_value(T const& handle) {
|
|
ASSERT_TRUE(handle != VK_NULL_HANDLE);
|
|
}
|
|
template <typename T>
|
|
void handle_assert_null(T const& handle) {
|
|
ASSERT_TRUE(handle == VK_NULL_HANDLE);
|
|
}
|
|
template <typename T>
|
|
void handle_assert_has_values(std::vector<T> const& handles) {
|
|
for (auto const& handle : handles) {
|
|
ASSERT_TRUE(handle != VK_NULL_HANDLE);
|
|
}
|
|
}
|
|
template <typename T>
|
|
void handle_assert_no_values(std::vector<T> const& handles) {
|
|
for (auto const& handle : handles) {
|
|
ASSERT_TRUE(handle == VK_NULL_HANDLE);
|
|
}
|
|
}
|
|
template <typename T>
|
|
void handle_assert_no_values(size_t length, T handles[]) {
|
|
for (size_t i = 0; i < length; i++) {
|
|
ASSERT_TRUE(handles[i] == VK_NULL_HANDLE);
|
|
}
|
|
}
|
|
template <typename T>
|
|
void handle_assert_equal(T const& left, T const& right) {
|
|
ASSERT_EQ(left, right);
|
|
}
|
|
template <typename T>
|
|
void handle_assert_equal(std::vector<T> const& left, std::vector<T> const& right) {
|
|
ASSERT_EQ(left.size(), right.size());
|
|
for (size_t i = 0; i < left.size(); i++) {
|
|
ASSERT_EQ(left[i], right[i]);
|
|
}
|
|
}
|
|
template <typename T>
|
|
void handle_assert_equal(size_t count, T left[], T right[]) {
|
|
for (size_t i = 0; i < count; i++) {
|
|
ASSERT_EQ(left[i], right[i]);
|
|
}
|
|
}
|
|
|
|
// VulkanFunctions - loads vulkan functions for tests to use
|
|
|
|
struct VulkanFunctions {
|
|
#if !defined(APPLE_STATIC_LOADER)
|
|
LibraryWrapper loader;
|
|
#endif
|
|
// Pre-Instance
|
|
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;
|
|
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = nullptr;
|
|
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties = nullptr;
|
|
PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = nullptr;
|
|
PFN_vkCreateInstance vkCreateInstance = nullptr;
|
|
|
|
// Instance
|
|
PFN_vkDestroyInstance vkDestroyInstance = nullptr;
|
|
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr;
|
|
PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups = nullptr;
|
|
PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures = nullptr;
|
|
PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2 = nullptr;
|
|
PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2 = nullptr;
|
|
PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2 = nullptr;
|
|
PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2 = nullptr;
|
|
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2 = nullptr;
|
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
|
|
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2 = nullptr;
|
|
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
|
|
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties = nullptr;
|
|
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties = nullptr;
|
|
PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties = nullptr;
|
|
|
|
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
|
|
PFN_vkCreateDevice vkCreateDevice = nullptr;
|
|
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
|
|
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
|
|
|
|
// WSI
|
|
PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT = nullptr;
|
|
PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR = nullptr;
|
|
PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR = nullptr;
|
|
PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR = nullptr;
|
|
PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR = nullptr;
|
|
PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR = nullptr;
|
|
PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR = nullptr;
|
|
PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR = nullptr;
|
|
PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR = nullptr;
|
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR = nullptr;
|
|
#endif // VK_USE_PLATFORM_ANDROID_KHR
|
|
#if defined(VK_USE_PLATFORM_DIRECTFB_EXT)
|
|
PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT = nullptr;
|
|
PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT = nullptr;
|
|
#endif // VK_USE_PLATFORM_DIRECTFB_EXT
|
|
#if defined(VK_USE_PLATFORM_FUCHSIA)
|
|
PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
|
|
#endif // VK_USE_PLATFORM_FUCHSIA
|
|
#if defined(VK_USE_PLATFORM_GGP)
|
|
PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP = nullptr;
|
|
#endif // VK_USE_PLATFORM_GGP
|
|
#if defined(VK_USE_PLATFORM_IOS_MVK)
|
|
PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK = nullptr;
|
|
#endif // VK_USE_PLATFORM_IOS_MVK
|
|
#if defined(VK_USE_PLATFORM_MACOS_MVK)
|
|
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = nullptr;
|
|
#endif // VK_USE_PLATFORM_MACOS_MVK
|
|
#if defined(VK_USE_PLATFORM_METAL_EXT)
|
|
PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT = nullptr;
|
|
#endif // VK_USE_PLATFORM_METAL_EXT
|
|
#if defined(VK_USE_PLATFORM_SCREEN_QNX)
|
|
PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX = nullptr;
|
|
PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX = nullptr;
|
|
#endif // VK_USE_PLATFORM_SCREEN_QNX
|
|
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = nullptr;
|
|
#endif // VK_USE_PLATFORM_WAYLAND_KHR
|
|
#if defined(VK_USE_PLATFORM_XCB_KHR)
|
|
PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = nullptr;
|
|
#endif // VK_USE_PLATFORM_XCB_KHR
|
|
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
|
PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = nullptr;
|
|
#endif // VK_USE_PLATFORM_XLIB_KHR
|
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
|
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = nullptr;
|
|
PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = nullptr;
|
|
#endif // VK_USE_PLATFORM_WIN32_KHR
|
|
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = nullptr;
|
|
|
|
// device functions
|
|
PFN_vkDestroyDevice vkDestroyDevice = nullptr;
|
|
PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
|
|
|
|
VulkanFunctions();
|
|
|
|
FromVoidStarFunc load(VkInstance inst, const char* func_name) const {
|
|
return FromVoidStarFunc(vkGetInstanceProcAddr(inst, func_name));
|
|
}
|
|
|
|
FromVoidStarFunc load(VkDevice device, const char* func_name) const {
|
|
return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
|
|
}
|
|
};
|
|
|
|
struct DeviceFunctions {
|
|
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
|
|
PFN_vkDestroyDevice vkDestroyDevice = nullptr;
|
|
PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
|
|
PFN_vkCreateCommandPool vkCreateCommandPool = nullptr;
|
|
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers = nullptr;
|
|
PFN_vkDestroyCommandPool vkDestroyCommandPool = nullptr;
|
|
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
|
|
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = nullptr;
|
|
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = nullptr;
|
|
|
|
DeviceFunctions() = default;
|
|
DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device);
|
|
|
|
FromVoidStarFunc load(VkDevice device, const char* func_name) const {
|
|
return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
|
|
}
|
|
};
|
|
|
|
// InstWrapper & DeviceWrapper - used to make creating instances & devices easier when writing tests
|
|
struct InstWrapper {
|
|
InstWrapper(VulkanFunctions& functions, VkAllocationCallbacks* callbacks = nullptr) noexcept;
|
|
InstWrapper(VulkanFunctions& functions, VkInstance inst, VkAllocationCallbacks* callbacks = nullptr) noexcept;
|
|
~InstWrapper() noexcept;
|
|
|
|
// Move-only object
|
|
InstWrapper(InstWrapper const&) = delete;
|
|
InstWrapper& operator=(InstWrapper const&) = delete;
|
|
InstWrapper(InstWrapper&& other) noexcept;
|
|
InstWrapper& operator=(InstWrapper&&) noexcept;
|
|
|
|
// Construct this VkInstance using googletest to assert if it succeeded
|
|
void CheckCreate(VkResult result_to_check = VK_SUCCESS);
|
|
void CheckCreateWithInfo(InstanceCreateInfo& create_info, VkResult result_to_check = VK_SUCCESS);
|
|
|
|
// Convenience
|
|
operator VkInstance() { return inst; }
|
|
VulkanFunctions* operator->() { return functions; }
|
|
|
|
FromVoidStarFunc load(const char* func_name) { return FromVoidStarFunc(functions->vkGetInstanceProcAddr(inst, func_name)); }
|
|
|
|
// Enumerate physical devices using googletest to assert if it succeeded
|
|
std::vector<VkPhysicalDevice> GetPhysDevs(VkResult result_to_check = VK_SUCCESS); // query all physical devices
|
|
std::vector<VkPhysicalDevice> GetPhysDevs(uint32_t phys_dev_count,
|
|
VkResult result_to_check = VK_SUCCESS); // query only phys_dev_count devices
|
|
// Enumerate a single physical device using googletest to assert if it succeeded
|
|
VkPhysicalDevice GetPhysDev(VkResult result_to_check = VK_SUCCESS);
|
|
|
|
// Get all the list of active layers through vkEnumerateDeviceLayerProperties
|
|
// Use count to specify the expected count
|
|
std::vector<VkLayerProperties> GetActiveLayers(VkPhysicalDevice phys_dev, uint32_t count);
|
|
|
|
// Get list of device extensions associated with a VkPhysicalDevice
|
|
// Use count to specify an expected count
|
|
std::vector<VkExtensionProperties> EnumerateDeviceExtensions(VkPhysicalDevice physical_device, uint32_t count);
|
|
// Same as EnumerateDeviceExtensions but for a specific layer
|
|
std::vector<VkExtensionProperties> EnumerateLayerDeviceExtensions(VkPhysicalDevice physical_device, const char* layer_name,
|
|
uint32_t expected_count);
|
|
|
|
VulkanFunctions* functions = nullptr;
|
|
VkInstance inst = VK_NULL_HANDLE;
|
|
VkAllocationCallbacks* callbacks = nullptr;
|
|
InstanceCreateInfo create_info{};
|
|
};
|
|
|
|
struct DeviceWrapper {
|
|
DeviceWrapper(InstWrapper& inst_wrapper, VkAllocationCallbacks* callbacks = nullptr) noexcept;
|
|
DeviceWrapper(VulkanFunctions& functions, VkDevice device, VkAllocationCallbacks* callbacks = nullptr) noexcept;
|
|
~DeviceWrapper() noexcept;
|
|
|
|
// Move-only object
|
|
DeviceWrapper(DeviceWrapper const&) = delete;
|
|
DeviceWrapper& operator=(DeviceWrapper const&) = delete;
|
|
DeviceWrapper(DeviceWrapper&&) noexcept;
|
|
DeviceWrapper& operator=(DeviceWrapper&&) noexcept;
|
|
|
|
// Construct this VkDevice using googletest to assert if it succeeded
|
|
void CheckCreate(VkPhysicalDevice physical_device, VkResult result_to_check = VK_SUCCESS);
|
|
|
|
// Convenience
|
|
operator VkDevice() { return dev; }
|
|
operator VkDevice() const { return dev; }
|
|
VulkanFunctions* operator->() { return functions; }
|
|
|
|
FromVoidStarFunc load(const char* func_name) { return FromVoidStarFunc(functions->vkGetDeviceProcAddr(dev, func_name)); }
|
|
|
|
VulkanFunctions* functions = nullptr;
|
|
VkDevice dev = VK_NULL_HANDLE;
|
|
VkAllocationCallbacks* callbacks = nullptr;
|
|
DeviceCreateInfo create_info{};
|
|
};
|
|
|
|
struct DebugUtilsLogger {
|
|
static VkBool32 VKAPI_PTR
|
|
DebugUtilsMessengerLoggerCallback([[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
[[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {
|
|
DebugUtilsLogger* debug = reinterpret_cast<DebugUtilsLogger*>(pUserData);
|
|
debug->returned_output += pCallbackData->pMessage;
|
|
debug->returned_output += '\n';
|
|
return VK_FALSE;
|
|
}
|
|
DebugUtilsLogger(VkDebugUtilsMessageSeverityFlagsEXT severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
|
returned_output.reserve(4096); // output can be very noisy, reserving should help prevent many small allocations
|
|
create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
create_info.pNext = nullptr;
|
|
create_info.messageSeverity = severity;
|
|
create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
|
create_info.pfnUserCallback = DebugUtilsMessengerLoggerCallback;
|
|
create_info.pUserData = this;
|
|
}
|
|
|
|
// Immoveable object
|
|
DebugUtilsLogger(DebugUtilsLogger const&) = delete;
|
|
DebugUtilsLogger& operator=(DebugUtilsLogger const&) = delete;
|
|
DebugUtilsLogger(DebugUtilsLogger&&) = delete;
|
|
DebugUtilsLogger& operator=(DebugUtilsLogger&&) = delete;
|
|
// Find a string in the log output
|
|
bool find(std::string const& search_text) const { return returned_output.find(search_text) != std::string::npos; }
|
|
|
|
// Look through the event log. If you find a line containing the prefix we're interested in, look for the end of
|
|
// line character, and then see if the postfix occurs in it as well.
|
|
bool find_prefix_then_postfix(const char* prefix, const char* postfix) const;
|
|
|
|
// Clear the log
|
|
void clear() { returned_output.clear(); }
|
|
VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return &create_info; }
|
|
VkDebugUtilsMessengerCreateInfoEXT create_info{};
|
|
std::string returned_output;
|
|
};
|
|
|
|
struct DebugUtilsWrapper {
|
|
DebugUtilsWrapper() noexcept {}
|
|
DebugUtilsWrapper(InstWrapper& inst_wrapper,
|
|
VkDebugUtilsMessageSeverityFlagsEXT severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
|
|
VkAllocationCallbacks* callbacks = nullptr)
|
|
: logger(severity), inst(inst_wrapper.inst), callbacks(callbacks) {
|
|
vkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
|
|
inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkCreateDebugUtilsMessengerEXT"));
|
|
vkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
|
|
inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkDestroyDebugUtilsMessengerEXT"));
|
|
};
|
|
~DebugUtilsWrapper() noexcept {
|
|
if (messenger) {
|
|
vkDestroyDebugUtilsMessengerEXT(inst, messenger, callbacks);
|
|
}
|
|
}
|
|
// Immoveable object
|
|
DebugUtilsWrapper(DebugUtilsWrapper const&) = delete;
|
|
DebugUtilsWrapper& operator=(DebugUtilsWrapper const&) = delete;
|
|
DebugUtilsWrapper(DebugUtilsWrapper&&) = delete;
|
|
DebugUtilsWrapper& operator=(DebugUtilsWrapper&&) = delete;
|
|
|
|
bool find(std::string const& search_text) { return logger.find(search_text); }
|
|
VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return logger.get(); }
|
|
|
|
DebugUtilsLogger logger;
|
|
VkInstance inst = VK_NULL_HANDLE;
|
|
VkAllocationCallbacks* callbacks = nullptr;
|
|
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
|
|
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
|
|
VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
|
|
};
|
|
|
|
VkResult CreateDebugUtilsMessenger(DebugUtilsWrapper& debug_utils);
|
|
|
|
// Helper that adds the debug utils extension name and sets the pNext chain up
|
|
// NOTE: Ignores existing pNext chains
|
|
void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsLogger& logger);
|
|
void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsWrapper& wrapper);
|
|
|
|
struct LoaderSettingsLayerConfiguration {
|
|
BUILDER_VALUE(LoaderSettingsLayerConfiguration, std::string, name, {})
|
|
BUILDER_VALUE(LoaderSettingsLayerConfiguration, std::string, path, {})
|
|
BUILDER_VALUE(LoaderSettingsLayerConfiguration, std::string, control, {})
|
|
BUILDER_VALUE(LoaderSettingsLayerConfiguration, bool, treat_as_implicit_manifest, false)
|
|
};
|
|
inline bool operator==(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) {
|
|
return a.name == b.name && a.path == b.path && a.control == b.control &&
|
|
a.treat_as_implicit_manifest == b.treat_as_implicit_manifest;
|
|
}
|
|
inline bool operator!=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(a == b); }
|
|
inline bool operator<(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) {
|
|
return a.name < b.name;
|
|
}
|
|
inline bool operator>(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return (b < a); }
|
|
inline bool operator<=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(b < a); }
|
|
inline bool operator>=(LoaderSettingsLayerConfiguration const& a, LoaderSettingsLayerConfiguration const& b) { return !(a < b); }
|
|
|
|
// Log files and their associated filter
|
|
struct LoaderLogConfiguration {
|
|
BUILDER_VECTOR(LoaderLogConfiguration, std::string, destinations, destination)
|
|
BUILDER_VECTOR(LoaderLogConfiguration, std::string, filters, filter)
|
|
};
|
|
struct AppSpecificSettings {
|
|
BUILDER_VECTOR(AppSpecificSettings, std::string, app_keys, app_key)
|
|
BUILDER_VECTOR(AppSpecificSettings, LoaderSettingsLayerConfiguration, layer_configurations, layer_configuration)
|
|
BUILDER_VECTOR(AppSpecificSettings, std::string, stderr_log, stderr_log_filter)
|
|
BUILDER_VECTOR(AppSpecificSettings, LoaderLogConfiguration, log_configurations, log_configuration)
|
|
};
|
|
|
|
struct LoaderSettings {
|
|
BUILDER_VALUE(LoaderSettings, ManifestVersion, file_format_version, {})
|
|
BUILDER_VECTOR(LoaderSettings, AppSpecificSettings, app_specific_settings, app_specific_setting);
|
|
};
|
|
|
|
struct FrameworkEnvironment; // forward declaration
|
|
|
|
struct PlatformShimWrapper {
|
|
PlatformShimWrapper(std::vector<fs::FolderManager>* folders, const char* log_filter) noexcept;
|
|
~PlatformShimWrapper() noexcept;
|
|
PlatformShimWrapper(PlatformShimWrapper const&) = delete;
|
|
PlatformShimWrapper& operator=(PlatformShimWrapper const&) = delete;
|
|
|
|
// Convenience
|
|
PlatformShim* operator->() { return platform_shim; }
|
|
|
|
LibraryWrapper shim_library;
|
|
PlatformShim* platform_shim = nullptr;
|
|
EnvVarWrapper loader_logging;
|
|
};
|
|
|
|
struct TestICDHandle {
|
|
TestICDHandle() noexcept;
|
|
TestICDHandle(fs::path const& icd_path) noexcept;
|
|
TestICD& reset_icd() noexcept;
|
|
TestICD& get_test_icd() noexcept;
|
|
fs::path get_icd_full_path() noexcept;
|
|
fs::path get_icd_manifest_path() noexcept;
|
|
fs::path get_shimmed_manifest_path() noexcept;
|
|
|
|
// Must use statically
|
|
LibraryWrapper icd_library;
|
|
GetTestICDFunc proc_addr_get_test_icd = nullptr;
|
|
GetNewTestICDFunc proc_addr_reset_icd = nullptr;
|
|
fs::path manifest_path; // path to the manifest file is on the actual filesystem (aka <build_folder>/tests/framework/<...>)
|
|
fs::path shimmed_manifest_path; // path to where the loader will find the manifest file (eg /usr/local/share/vulkan/<...>)
|
|
};
|
|
struct TestLayerHandle {
|
|
TestLayerHandle() noexcept;
|
|
TestLayerHandle(fs::path const& layer_path) noexcept;
|
|
TestLayer& reset_layer() noexcept;
|
|
TestLayer& get_test_layer() noexcept;
|
|
fs::path get_layer_full_path() noexcept;
|
|
fs::path get_layer_manifest_path() noexcept;
|
|
fs::path get_shimmed_manifest_path() noexcept;
|
|
|
|
// Must use statically
|
|
LibraryWrapper layer_library;
|
|
GetTestLayerFunc proc_addr_get_test_layer = nullptr;
|
|
GetNewTestLayerFunc proc_addr_reset_layer = nullptr;
|
|
fs::path manifest_path; // path to the manifest file is on the actual filesystem (aka <build_folder>/tests/framework/<...>)
|
|
fs::path shimmed_manifest_path; // path to where the loader will find the manifest file (eg /usr/local/share/vulkan/<...>)
|
|
};
|
|
|
|
// Controls whether to create a manifest and where to put it
|
|
enum class ManifestDiscoveryType {
|
|
generic, // put the manifest in the regular locations
|
|
unsecured_generic, // put the manifest in a user folder rather than system
|
|
none, // Do not write the manifest anywhere (for Direct Driver Loading)
|
|
null_dir, // put the manifest in the 'null_dir' which the loader does not search in (D3DKMT for instance)
|
|
env_var, // use the corresponding env-var for it
|
|
add_env_var, // use the corresponding add-env-var for it
|
|
override_folder, // add to a special folder for the override layer to use
|
|
windows_app_package, // let the app package search find it
|
|
macos_bundle, // place it in a location only accessible to macos bundles
|
|
};
|
|
|
|
enum class LibraryPathType {
|
|
absolute, // default for testing - the exact path of the binary
|
|
relative, // Relative to the manifest file
|
|
default_search_paths, // Dont add any path information to the library_path - force the use of the default search paths
|
|
};
|
|
|
|
struct TestICDDetails {
|
|
TestICDDetails(ManifestICD icd_manifest) noexcept : icd_manifest(icd_manifest) {}
|
|
TestICDDetails(fs::path icd_binary_path, uint32_t api_version = VK_API_VERSION_1_0) noexcept {
|
|
icd_manifest.set_lib_path(icd_binary_path.str()).set_api_version(api_version);
|
|
}
|
|
BUILDER_VALUE(TestICDDetails, ManifestICD, icd_manifest, {});
|
|
BUILDER_VALUE(TestICDDetails, std::string, json_name, "test_icd");
|
|
// Uses the json_name without modification - default is to append _1 in the json file to distinguish drivers
|
|
BUILDER_VALUE(TestICDDetails, bool, disable_icd_inc, false);
|
|
BUILDER_VALUE(TestICDDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
|
|
BUILDER_VALUE(TestICDDetails, bool, is_fake, false);
|
|
// If discovery type is env-var, is_dir controls whether to use the path to the file or folder the manifest is in
|
|
BUILDER_VALUE(TestICDDetails, bool, is_dir, false);
|
|
BUILDER_VALUE(TestICDDetails, LibraryPathType, library_path_type, LibraryPathType::absolute);
|
|
};
|
|
|
|
struct TestLayerDetails {
|
|
TestLayerDetails(ManifestLayer layer_manifest, const std::string& json_name) noexcept
|
|
: layer_manifest(layer_manifest), json_name(json_name) {}
|
|
BUILDER_VALUE(TestLayerDetails, ManifestLayer, layer_manifest, {});
|
|
BUILDER_VALUE(TestLayerDetails, std::string, json_name, "test_layer");
|
|
BUILDER_VALUE(TestLayerDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
|
|
BUILDER_VALUE(TestLayerDetails, bool, is_fake, false);
|
|
// If discovery type is env-var, is_dir controls whether to use the path to the file or folder the manifest is in
|
|
BUILDER_VALUE(TestLayerDetails, bool, is_dir, true);
|
|
BUILDER_VALUE(TestLayerDetails, LibraryPathType, library_path_type, LibraryPathType::absolute);
|
|
};
|
|
|
|
// Locations manifests can go in the test framework
|
|
// If this enum is added to - the contructor of FrameworkEnvironment also needs to be updated with the new enum value
|
|
enum class ManifestLocation {
|
|
null = 0,
|
|
driver = 1,
|
|
driver_env_var = 2,
|
|
explicit_layer = 3,
|
|
explicit_layer_env_var = 4,
|
|
explicit_layer_add_env_var = 5,
|
|
implicit_layer = 6,
|
|
override_layer = 7,
|
|
windows_app_package = 8,
|
|
macos_bundle = 9,
|
|
unsecured_location = 10,
|
|
settings_location = 11,
|
|
};
|
|
|
|
struct FrameworkSettings {
|
|
BUILDER_VALUE(FrameworkSettings, const char*, log_filter, "all");
|
|
BUILDER_VALUE(FrameworkSettings, bool, enable_default_search_paths, true);
|
|
BUILDER_VALUE(FrameworkSettings, LoaderSettings, loader_settings, {});
|
|
BUILDER_VALUE(FrameworkSettings, bool, secure_loader_settings, false);
|
|
};
|
|
|
|
struct FrameworkEnvironment {
|
|
FrameworkEnvironment() noexcept; // default is to enable VK_LOADER_DEBUG=all and enable the default search paths
|
|
FrameworkEnvironment(const FrameworkSettings& settings) noexcept;
|
|
~FrameworkEnvironment();
|
|
// Delete copy constructors - this class should never move after being created
|
|
FrameworkEnvironment(const FrameworkEnvironment&) = delete;
|
|
FrameworkEnvironment& operator=(const FrameworkEnvironment&) = delete;
|
|
|
|
TestICD& add_icd(TestICDDetails icd_details) noexcept;
|
|
void add_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
|
|
void add_implicit_layer(TestLayerDetails layer_details) noexcept;
|
|
void add_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
|
|
void add_explicit_layer(TestLayerDetails layer_details) noexcept;
|
|
void add_fake_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
|
|
void add_fake_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
|
|
|
|
// resets the current settings with the values contained in loader_settings
|
|
void write_settings_file(std::string const& file_contents);
|
|
// apply any changes made to FrameworkEnvironment's loader_settings member
|
|
void update_loader_settings(const LoaderSettings& loader_settings) noexcept;
|
|
void remove_loader_settings();
|
|
|
|
TestICD& get_test_icd(size_t index = 0) noexcept;
|
|
TestICD& reset_icd(size_t index = 0) noexcept;
|
|
fs::path get_test_icd_path(size_t index = 0) noexcept;
|
|
fs::path get_icd_manifest_path(size_t index = 0) noexcept;
|
|
fs::path get_shimmed_icd_manifest_path(size_t index = 0) noexcept;
|
|
|
|
TestLayer& get_test_layer(size_t index = 0) noexcept;
|
|
TestLayer& reset_layer(size_t index = 0) noexcept;
|
|
fs::path get_test_layer_path(size_t index = 0) noexcept;
|
|
fs::path get_layer_manifest_path(size_t index = 0) noexcept;
|
|
fs::path get_shimmed_layer_manifest_path(size_t index = 0) noexcept;
|
|
|
|
fs::FolderManager& get_folder(ManifestLocation location) noexcept;
|
|
fs::FolderManager const& get_folder(ManifestLocation location) const noexcept;
|
|
#if defined(__APPLE__)
|
|
// Set the path of the app bundle to the appropriate test framework bundle
|
|
void setup_macos_bundle() noexcept;
|
|
#endif
|
|
|
|
FrameworkSettings settings;
|
|
|
|
// Query the global extensions
|
|
// Optional: use layer_name to query the extensions of a specific layer
|
|
std::vector<VkExtensionProperties> GetInstanceExtensions(uint32_t count, const char* layer_name = nullptr);
|
|
// Query the available layers
|
|
std::vector<VkLayerProperties> GetLayerProperties(uint32_t count);
|
|
|
|
PlatformShimWrapper platform_shim;
|
|
std::vector<fs::FolderManager> folders;
|
|
|
|
DebugUtilsLogger debug_log;
|
|
VulkanFunctions vulkan_functions;
|
|
|
|
std::vector<TestICDHandle> icds;
|
|
std::vector<TestLayerHandle> layers;
|
|
|
|
EnvVarWrapper env_var_vk_icd_filenames{"VK_DRIVER_FILES"};
|
|
EnvVarWrapper add_env_var_vk_icd_filenames{"VK_ADD_DRIVER_FILES"};
|
|
EnvVarWrapper env_var_vk_layer_paths{"VK_LAYER_PATH"};
|
|
EnvVarWrapper add_env_var_vk_layer_paths{"VK_ADD_LAYER_PATH"};
|
|
|
|
LoaderSettings loader_settings; // the current settings written to disk
|
|
private:
|
|
void add_layer_impl(TestLayerDetails layer_details, ManifestCategory category);
|
|
};
|
|
|
|
// Create a surface using a platform specific API
|
|
// api_selection: optionally provide a VK_USE_PLATFORM_XXX string to select which API to create a surface with.
|
|
// defaults to Metal on macOS and XCB on linux if not provided
|
|
// Returns an VkResult with the result of surface creation
|
|
// returns VK_ERROR_EXTENSION_NOT_PRESENT if it fails to load the surface creation function
|
|
VkResult create_surface(InstWrapper& inst, VkSurfaceKHR& out_surface, const char* api_selection = nullptr);
|
|
// Alternate parameter list for allocation callback tests
|
|
VkResult create_surface(VulkanFunctions* functions, VkInstance inst, VkSurfaceKHR& surface, const char* api_selection = nullptr);
|