blob: d84f4f8a32255de80cff3327abe8d71f37009f62 [file] [log] [blame]
/*
* 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>
*/
#pragma once
#include <array>
#include <filesystem>
#include <ostream>
#include <unordered_map>
#include "util/dispatchable_handle.h"
#include "util/platform_wsi.h"
#include "util/functions.h"
#include "layer/layer_util.h"
enum class CalledICDGIPA { not_called, vk_icd_gipa, vk_gipa };
enum class CalledNegotiateInterface { not_called, vk_icd_negotiate, vk_icd_gipa_first };
enum class InterfaceVersionCheck {
not_called,
loader_version_too_old,
loader_version_too_new,
icd_version_too_new,
version_is_supported
};
// clang-format off
inline std::ostream& operator<<(std::ostream& os, const CalledICDGIPA& result) {
switch (result) {
case (CalledICDGIPA::not_called): return os << "CalledICDGIPA::not_called";
case (CalledICDGIPA::vk_icd_gipa): return os << "CalledICDGIPA::vk_icd_gipa";
case (CalledICDGIPA::vk_gipa): return os << "CalledICDGIPA::vk_gipa";
}
return os << static_cast<uint32_t>(result);
}
inline std::ostream& operator<<(std::ostream& os, const CalledNegotiateInterface& result) {
switch (result) {
case (CalledNegotiateInterface::not_called): return os << "CalledNegotiateInterface::not_called";
case (CalledNegotiateInterface::vk_icd_negotiate): return os << "CalledNegotiateInterface::vk_icd_negotiate";
case (CalledNegotiateInterface::vk_icd_gipa_first): return os << "CalledNegotiateInterface::vk_icd_gipa_first";
}
return os << static_cast<uint32_t>(result);
}
inline std::ostream& operator<<(std::ostream& os, const InterfaceVersionCheck& result) {
switch (result) {
case (InterfaceVersionCheck::not_called): return os << "InterfaceVersionCheck::not_called";
case (InterfaceVersionCheck::loader_version_too_old): return os << "InterfaceVersionCheck::loader_version_too_old";
case (InterfaceVersionCheck::loader_version_too_new): return os << "InterfaceVersionCheck::loader_version_too_new";
case (InterfaceVersionCheck::icd_version_too_new): return os << "InterfaceVersionCheck::icd_version_too_new";
case (InterfaceVersionCheck::version_is_supported): return os << "InterfaceVersionCheck::version_is_supported";
}
return os << static_cast<uint32_t>(result);
}
using VulkanUUID = std::array<uint8_t, VK_UUID_SIZE>;
// clang-format on
// Move only type because it holds a DispatchableHandle<VkPhysicalDevice>
struct PhysicalDevice {
PhysicalDevice() {}
PhysicalDevice(std::string name) : deviceName(name) {}
PhysicalDevice(const char* name) : deviceName(name) {}
DispatchableHandle<VkPhysicalDevice> vk_physical_device;
BUILDER_VALUE(std::string, deviceName)
BUILDER_VALUE(VulkanUUID, deviceUUID)
BUILDER_VALUE(VkPhysicalDeviceProperties, properties)
BUILDER_VALUE(VkPhysicalDeviceFeatures, features)
BUILDER_VALUE(VkPhysicalDeviceMemoryProperties, memory_properties)
BUILDER_VALUE(VkImageFormatProperties, image_format_properties)
BUILDER_VALUE(VkExternalMemoryProperties, external_memory_properties)
BUILDER_VALUE(VkExternalSemaphoreProperties, external_semaphore_properties)
BUILDER_VALUE(VkExternalFenceProperties, external_fence_properties)
BUILDER_VALUE(uint32_t, pci_bus)
BUILDER_VECTOR(MockQueueFamilyProperties, queue_family_properties, queue_family_properties)
BUILDER_VECTOR(VkFormatProperties, format_properties, format_properties)
BUILDER_VECTOR(VkSparseImageFormatProperties, sparse_image_format_properties, sparse_image_format_properties)
BUILDER_VECTOR(Extension, extensions, extension)
BUILDER_VALUE(VkSurfaceCapabilitiesKHR, surface_capabilities)
BUILDER_VECTOR(VkSurfaceFormatKHR, surface_formats, surface_format)
BUILDER_VECTOR(VkPresentModeKHR, surface_present_modes, surface_present_mode)
BUILDER_VALUE(VkSurfacePresentScalingCapabilitiesEXT, surface_present_scaling_capabilities)
// No good way to make this a builder value. Each std::vector<VkPresentModeKHR> corresponds to each surface_present_modes
// element
std::vector<std::vector<VkPresentModeKHR>> surface_present_mode_compatibility{};
BUILDER_VECTOR(VkDisplayPropertiesKHR, display_properties, display_properties)
BUILDER_VECTOR(VkDisplayPlanePropertiesKHR, display_plane_properties, display_plane_properties)
BUILDER_VECTOR(VkDisplayKHR, displays, displays)
BUILDER_VECTOR(VkDisplayModePropertiesKHR, display_mode_properties, display_mode_properties)
BUILDER_VALUE(VkDisplayModeKHR, display_mode)
BUILDER_VALUE(VkDisplayPlaneCapabilitiesKHR, display_plane_capabilities)
BUILDER_VALUE_WITH_DEFAULT(VkLayeredDriverUnderlyingApiMSFT, layered_driver_underlying_api,
VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT)
PhysicalDevice& set_api_version(uint32_t version) {
properties.apiVersion = version;
return *this;
}
PhysicalDevice&& finish() { return std::move(*this); }
// Defines the order this physical device appears in vkEnumeratePhysicalDevices
uint32_t iteration_order = 0;
// Objects created from this physical device
std::vector<VkDevice> device_handles;
std::vector<DeviceCreateInfo> device_create_infos;
std::vector<DispatchableHandle<VkQueue>> queue_handles;
// Unknown physical device functions. Add a `VulkanFunction` to this list which will be searched in
// vkGetInstanceProcAddr for custom_instance_functions and vk_icdGetPhysicalDeviceProcAddr for custom_physical_device_functions.
// To add unknown device functions, add it to the PhysicalDevice directly (in the known_device_functions member)
BUILDER_VECTOR(VulkanFunction, custom_physical_device_functions, custom_physical_device_function)
// List of function names which are 'known' to the physical device but have test defined implementations
// The purpose of this list is so that vkGetDeviceProcAddr returns 'a real function pointer' in tests
// without actually implementing any of the logic inside of it.
BUILDER_VECTOR(VulkanFunction, known_device_functions, device_function)
};
struct PhysicalDeviceGroup {
PhysicalDeviceGroup() {}
PhysicalDeviceGroup(PhysicalDevice const& physical_device) { physical_device_handles.push_back(&physical_device); }
PhysicalDeviceGroup(PhysicalDevice const* physical_device) { physical_device_handles.push_back(physical_device); }
PhysicalDeviceGroup(std::vector<PhysicalDevice*> const& physical_devices) {
physical_device_handles.insert(physical_device_handles.end(), physical_devices.begin(), physical_devices.end());
}
PhysicalDeviceGroup& use_physical_device(PhysicalDevice const* physical_device) {
physical_device_handles.push_back(physical_device);
return *this;
}
PhysicalDeviceGroup& use_physical_device(PhysicalDevice const& physical_device) {
physical_device_handles.push_back(&physical_device);
return *this;
}
std::vector<PhysicalDevice const*> physical_device_handles;
VkBool32 subset_allocation = false;
};
struct TestICD {
std::filesystem::path manifest_file_path;
BUILDER_VALUE_WITH_DEFAULT(bool, exposes_vk_icdNegotiateLoaderICDInterfaceVersion, true)
BUILDER_VALUE_WITH_DEFAULT(bool, exposes_vkEnumerateInstanceExtensionProperties, true)
BUILDER_VALUE_WITH_DEFAULT(bool, exposes_vkCreateInstance, true)
BUILDER_VALUE_WITH_DEFAULT(bool, exposes_vk_icdGetPhysicalDeviceProcAddr, true)
#if defined(WIN32)
BUILDER_VALUE_WITH_DEFAULT(bool, exposes_vk_icdEnumerateAdapterPhysicalDevices, true)
#endif
CalledICDGIPA called_vk_icd_gipa = CalledICDGIPA::not_called;
CalledNegotiateInterface called_negotiate_interface = CalledNegotiateInterface::not_called;
InterfaceVersionCheck interface_version_check = InterfaceVersionCheck::not_called;
BUILDER_VALUE_WITH_DEFAULT(uint32_t, min_icd_interface_version, 0)
BUILDER_VALUE_WITH_DEFAULT(uint32_t, max_icd_interface_version, 7)
uint32_t icd_interface_version_received = 0;
bool called_enumerate_adapter_physical_devices = false;
BUILDER_VALUE(bool, enable_icd_wsi);
bool is_using_icd_wsi = false;
TestICD& setup_WSI(const char* api_selection = nullptr) {
enable_icd_wsi = true;
add_instance_extensions({"VK_KHR_surface", get_platform_wsi_extension(api_selection)});
min_icd_interface_version = (3U < min_icd_interface_version) ? min_icd_interface_version : 3U;
return *this;
}
BUILDER_VALUE_WITH_DEFAULT(uint32_t, icd_api_version, VK_API_VERSION_1_0)
BUILDER_VECTOR(LayerDefinition, instance_layers, instance_layer)
BUILDER_VECTOR(Extension, instance_extensions, instance_extension)
std::vector<Extension> enabled_instance_extensions;
std::unordered_map<VkPhysicalDevice, PhysicalDevice> physical_devices;
TestICD& add_physical_device(PhysicalDevice&& physical_device) {
physical_device.iteration_order = physical_devices.size();
physical_devices.emplace(physical_device.vk_physical_device.handle, std::move(physical_device));
return *this;
}
PhysicalDevice& add_and_get_physical_device(PhysicalDevice&& physical_device) {
VkPhysicalDevice pd = physical_device.vk_physical_device.handle;
physical_device.iteration_order = physical_devices.size();
physical_devices.emplace(physical_device.vk_physical_device.handle, std::move(physical_device));
return physical_devices.at(pd);
}
PhysicalDevice& add_physical_device_at_index(size_t index, PhysicalDevice&& physical_device) {
VkPhysicalDevice pd = physical_device.vk_physical_device.handle;
physical_device.iteration_order = index;
for (auto& [handle, phys_dev] : physical_devices) {
if (phys_dev.iteration_order >= index) {
phys_dev.iteration_order++;
}
}
physical_devices.emplace(physical_device.vk_physical_device.handle, std::move(physical_device));
return physical_devices.at(pd);
}
BUILDER_VECTOR(PhysicalDeviceGroup, physical_device_groups, physical_device_group);
DispatchableHandle<VkInstance> instance_handle;
std::vector<DispatchableHandle<VkDevice>> device_handles;
std::vector<uint64_t> surface_handles;
std::vector<uint64_t> messenger_handles;
std::vector<uint64_t> callback_handles;
std::vector<uint64_t> swapchain_handles;
BUILDER_VALUE_WITH_DEFAULT(bool, can_query_vkEnumerateInstanceVersion, true);
BUILDER_VALUE_WITH_DEFAULT(bool, can_query_GetPhysicalDeviceFuncs, true);
// Unknown instance functions Add a `VulkanFunction` to this list which will be searched in
// vkGetInstanceProcAddr for custom_instance_functions and vk_icdGetPhysicalDeviceProcAddr for
// custom_physical_device_functions. To add unknown device functions, add it to the PhysicalDevice directly (in the
// known_device_functions member)
BUILDER_VECTOR(VulkanFunction, custom_instance_functions, custom_instance_function)
// Must explicitely state support for the tooling info extension, that way we can control if vkGetInstanceProcAddr returns a
// function pointer for vkGetPhysicalDeviceToolPropertiesEXT or vkGetPhysicalDeviceToolProperties (core version)
BUILDER_VALUE(bool, supports_tooling_info_ext);
BUILDER_VALUE(bool, supports_tooling_info_core);
// List of tooling properties that this driver 'supports'
BUILDER_VECTOR(VkPhysicalDeviceToolPropertiesEXT, tooling_properties, tooling_property)
std::vector<DispatchableHandle<VkCommandBuffer>> allocated_command_buffers;
VkInstanceCreateFlags passed_in_instance_create_flags{};
BUILDER_VALUE_WITH_DEFAULT(VkResult, enum_physical_devices_return_code, VK_SUCCESS);
BUILDER_VALUE_WITH_DEFAULT(VkResult, enum_adapter_physical_devices_return_code, VK_SUCCESS);
InstanceCreateInfo GetVkInstanceCreateInfo() {
InstanceCreateInfo info;
for (auto& layer : instance_layers) info.enabled_layers.push_back(layer.layerName.data());
for (auto& ext : instance_extensions) info.enabled_extensions.push_back(ext.extensionName.data());
return info;
}
// Speedup looking for physical devices by not having to iterate through the entire physical_device map to find a particular
// physical device
std::unordered_map<VkDevice, VkPhysicalDevice> device_to_physical_device_map;
#if defined(WIN32)
BUILDER_VALUE(LUID, adapterLUID)
#endif // defined(WIN32)
};
using GetTestICDFunc = TestICD* (*)();
#define GET_TEST_ICD_FUNC_STR "get_test_icd_func"
using GetNewTestICDFunc = TestICD* (*)();
#define RESET_ICD_FUNC_STR "reset_icd_func"