blob: 366936fa5318cb987eaa34d44fcaa3935e2af193 [file] [log] [blame]
/*
* Copyright (c) 2021-2023 The Khronos Group Inc.
* Copyright (c) 2021-2023 Valve Corporation
* Copyright (c) 2021-2023 LunarG, Inc.
* Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2023-2023 RasterGrid Kft.
*
* 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>
*/
#include "test_environment.h"
// Test case origin
// LX = lunar exchange
// LVLGH = loader and validation github
// LVLGL = loader and validation gitlab
// VL = Vulkan Loader github
// VVL = Vulkan Validation Layers github
TEST(CreateInstance, BasicRun) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
}
// LX435
TEST(CreateInstance, ConstInstanceInfo) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
VkInstance inst = VK_NULL_HANDLE;
VkInstanceCreateInfo const info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, nullptr, 0, nullptr, 0, nullptr, 0, nullptr};
ASSERT_EQ(env.vulkan_functions.vkCreateInstance(&info, VK_NULL_HANDLE, &inst), VK_SUCCESS);
// Must clean up
env.vulkan_functions.vkDestroyInstance(inst, nullptr);
}
// VUID-vkDestroyInstance-instance-parameter, VUID-vkDestroyInstance-pAllocator-parameter
TEST(CreateInstance, DestroyInstanceNullHandle) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
env.vulkan_functions.vkDestroyInstance(VK_NULL_HANDLE, nullptr);
}
// VUID-vkDestroyDevice-device-parameter, VUID-vkDestroyDevice-pAllocator-parameter
TEST(CreateInstance, DestroyDeviceNullHandle) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
env.vulkan_functions.vkDestroyDevice(VK_NULL_HANDLE, nullptr);
}
// VUID-vkCreateInstance-ppEnabledExtensionNames-01388
TEST(CreateInstance, ExtensionNotPresent) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
{
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_extension("VK_EXT_validation_features"); // test icd won't report this as supported
inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
}
{
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_extension("Non_existant_extension"); // unknown instance extension
inst.CheckCreate(VK_ERROR_EXTENSION_NOT_PRESENT);
}
}
TEST(CreateInstance, LayerNotPresent) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer("VK_NON_EXISTANT_LAYER");
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
}
TEST(CreateInstance, LayerPresent) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2}).add_physical_device({});
const char* layer_name = "TestLayer";
env.add_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"test_layer.json");
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name);
inst.CheckCreate();
}
TEST(CreateInstance, RelativePaths) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2}.set_library_path_type(LibraryPathType::relative)).add_physical_device({});
const char* layer_name = "VK_LAYER_TestLayer";
env.add_explicit_layer(
TestLayerDetails{ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"test_layer.json"}
.set_library_path_type(LibraryPathType::relative));
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name);
inst.CheckCreate();
auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
ASSERT_TRUE(string_eq(layers.at(0).layerName, layer_name));
}
TEST(CreateInstance, ApiVersionBelow1_0) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
DebugUtilsLogger debug_log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
FillDebugUtilsCreateDetails(inst.create_info, debug_log);
inst.create_info.api_version = 1;
inst.CheckCreate();
ASSERT_TRUE(
debug_log.find("VkInstanceCreateInfo::pApplicationInfo::apiVersion has value of 1 which is not permitted. If apiVersion is "
"not 0, then it must be "
"greater than or equal to the value of VK_API_VERSION_1_0 [VUID-VkApplicationInfo-apiVersion]"));
}
TEST(CreateInstance, ConsecutiveCreate) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
for (uint32_t i = 0; i < 100; i++) {
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
}
}
TEST(CreateInstance, ConsecutiveCreateWithoutDestruction) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
std::vector<InstWrapper> instances;
for (uint32_t i = 0; i < 100; i++) {
instances.emplace_back(env.vulkan_functions);
instances.back().CheckCreate();
}
}
TEST(NoDrivers, CreateInstance) {
FrameworkEnvironment env{};
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
}
TEST(EnumerateInstanceLayerProperties, UsageChecks) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
const char* layer_name_1 = "TestLayer1";
const char* layer_name_2 = "TestLayer1";
env.add_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name_1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"test_layer_1.json");
env.add_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name_2).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"test_layer_2.json");
{ // OnePass
VkLayerProperties layer_props[2] = {};
uint32_t layer_count = 2;
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props));
ASSERT_EQ(layer_count, 2U);
auto layers = env.GetLayerProperties(2);
ASSERT_TRUE(string_eq(layer_name_1, layer_props[0].layerName));
ASSERT_TRUE(string_eq(layer_name_2, layer_props[1].layerName));
}
{ // OnePass
uint32_t layer_count = 0;
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, nullptr));
ASSERT_EQ(layer_count, 2U);
VkLayerProperties layer_props[2] = {};
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props));
ASSERT_EQ(layer_count, 2U);
ASSERT_TRUE(string_eq(layer_name_1, layer_props[0].layerName));
ASSERT_TRUE(string_eq(layer_name_2, layer_props[1].layerName));
}
{ // PropertyCountLessThanAvailable
VkLayerProperties layer_props{};
uint32_t layer_count = 1;
ASSERT_EQ(VK_INCOMPLETE, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, &layer_props));
ASSERT_TRUE(string_eq(layer_name_1, layer_props.layerName));
}
}
TEST(EnumerateInstanceExtensionProperties, UsageChecks) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
Extension first_ext{"VK_EXT_validation_features"}; // known instance extensions
Extension second_ext{"VK_EXT_headless_surface"};
env.reset_icd().add_instance_extensions({first_ext, second_ext});
{ // One Pass
uint32_t extension_count = 6;
std::array<VkExtensionProperties, 6> extensions;
ASSERT_EQ(VK_SUCCESS,
env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data()));
ASSERT_EQ(extension_count, 6U); // default extensions + our two extensions
EXPECT_TRUE(string_eq(extensions.at(0).extensionName, first_ext.extensionName.c_str()));
EXPECT_TRUE(string_eq(extensions.at(1).extensionName, second_ext.extensionName.c_str()));
EXPECT_TRUE(string_eq(extensions.at(2).extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(3).extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(4).extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(5).extensionName, VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME));
}
{ // Two Pass
auto extensions = env.GetInstanceExtensions(6);
// loader always adds the debug report & debug utils extensions
EXPECT_TRUE(string_eq(extensions.at(0).extensionName, first_ext.extensionName.c_str()));
EXPECT_TRUE(string_eq(extensions.at(1).extensionName, second_ext.extensionName.c_str()));
EXPECT_TRUE(string_eq(extensions.at(2).extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(3).extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(4).extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(5).extensionName, VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME));
}
}
TEST(EnumerateInstanceExtensionProperties, PropertyCountLessThanAvailable) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
uint32_t extension_count = 0;
std::array<VkExtensionProperties, 4> extensions;
{ // use nullptr for null string
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr));
ASSERT_EQ(extension_count, 4U); // return debug report & debug utils & portability enumeration & direct driver loading
extension_count = 1; // artificially remove one extension
ASSERT_EQ(VK_INCOMPLETE,
env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data()));
ASSERT_EQ(extension_count, 1U);
// loader always adds the debug report & debug utils extensions
ASSERT_TRUE(string_eq(extensions[0].extensionName, "VK_EXT_debug_report"));
}
{ // use "" for null string
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties("", &extension_count, nullptr));
ASSERT_EQ(extension_count, 4U); // return debug report & debug utils & portability enumeration & direct driver loading
extension_count = 1; // artificially remove one extension
ASSERT_EQ(VK_INCOMPLETE,
env.vulkan_functions.vkEnumerateInstanceExtensionProperties("", &extension_count, extensions.data()));
ASSERT_EQ(extension_count, 1U);
// loader always adds the debug report & debug utils extensions
ASSERT_TRUE(string_eq(extensions[0].extensionName, "VK_EXT_debug_report"));
}
}
TEST(EnumerateInstanceExtensionProperties, FilterUnkownInstanceExtensions) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
Extension first_ext{"FirstTestExtension"}; // unknown instance extensions
Extension second_ext{"SecondTestExtension"};
env.reset_icd().add_instance_extensions({first_ext, second_ext});
{
auto extensions = env.GetInstanceExtensions(4);
// loader always adds the debug report & debug utils extensions
EXPECT_TRUE(string_eq(extensions.at(0).extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(1).extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(2).extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(3).extensionName, VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME));
}
{ // Disable unknown instance extension filtering
EnvVarWrapper disable_inst_ext_filter_env_var{"VK_LOADER_DISABLE_INST_EXT_FILTER", "1"};
auto extensions = env.GetInstanceExtensions(6);
EXPECT_TRUE(string_eq(extensions.at(0).extensionName, first_ext.extensionName.c_str()));
EXPECT_TRUE(string_eq(extensions.at(1).extensionName, second_ext.extensionName.c_str()));
EXPECT_TRUE(string_eq(extensions.at(2).extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(3).extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(4).extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME));
EXPECT_TRUE(string_eq(extensions.at(5).extensionName, VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME));
}
}
TEST(EnumerateDeviceLayerProperties, LayersMatch) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name = "TestLayer";
env.add_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"test_layer.json");
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name);
inst.CheckCreate();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
{ // LayersMatch
auto layer_props = inst.GetActiveLayers(phys_dev, 1);
ASSERT_TRUE(string_eq(layer_props.at(0).layerName, layer_name));
}
{ // Property count less than available
VkLayerProperties layer_props;
uint32_t layer_count = 0;
ASSERT_EQ(VK_INCOMPLETE, env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &layer_count, &layer_props));
ASSERT_EQ(layer_count, 0U);
}
}
TEST(EnumerateDeviceExtensionProperties, DeviceExtensionEnumerated) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
std::array<Extension, 2> device_extensions = {Extension{"MyExtension0", 4}, Extension{"MyExtension1", 7}};
for (auto& ext : device_extensions) {
driver.physical_devices.front().extensions.push_back(ext);
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
uint32_t driver_count = 1;
VkPhysicalDevice physical_device;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
uint32_t extension_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count, nullptr));
ASSERT_EQ(extension_count, device_extensions.size());
std::array<VkExtensionProperties, 2> enumerated_device_exts;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count,
enumerated_device_exts.data()));
ASSERT_EQ(extension_count, device_extensions.size());
ASSERT_TRUE(device_extensions[0].extensionName == enumerated_device_exts[0].extensionName);
ASSERT_TRUE(device_extensions[0].specVersion == enumerated_device_exts[0].specVersion);
}
TEST(EnumerateDeviceExtensionProperties, PropertyCountLessThanAvailable) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
std::array<Extension, 2> device_extensions = {Extension{"MyExtension0", 4}, Extension{"MyExtension1", 7}};
for (auto& ext : device_extensions) {
driver.physical_devices.front().extensions.push_back(ext);
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
uint32_t driver_count = 1;
VkPhysicalDevice physical_device;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
uint32_t extension_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, "", &extension_count, nullptr));
ASSERT_EQ(extension_count, device_extensions.size());
extension_count -= 1;
std::array<VkExtensionProperties, 2> enumerated_device_exts;
ASSERT_EQ(VK_INCOMPLETE,
inst->vkEnumerateDeviceExtensionProperties(physical_device, "", &extension_count, enumerated_device_exts.data()));
ASSERT_EQ(extension_count, device_extensions.size() - 1);
ASSERT_TRUE(device_extensions[0].extensionName == enumerated_device_exts[0].extensionName);
ASSERT_TRUE(device_extensions[0].specVersion == enumerated_device_exts[0].specVersion);
}
TEST(EnumerateDeviceExtensionProperties, ZeroPhysicalDeviceExtensions) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0));
inst.CheckCreate(VK_SUCCESS);
auto phys_dev = inst.GetPhysDev();
DeviceWrapper dev{inst};
dev.CheckCreate(phys_dev);
uint32_t ext_count = 0;
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateDeviceExtensionProperties(phys_dev, nullptr, &ext_count, nullptr));
ASSERT_EQ(ext_count, 0U);
VkExtensionProperties ext_props{};
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateDeviceExtensionProperties(phys_dev, nullptr, &ext_count, &ext_props));
ASSERT_EQ(ext_count, 0U);
}
void exercise_EnumerateDeviceExtensionProperties(InstWrapper& inst, VkPhysicalDevice physical_device,
std::vector<Extension>& exts_to_expect) {
{ // "expected enumeration pattern"
uint32_t extension_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count, nullptr));
ASSERT_EQ(extension_count, exts_to_expect.size());
std::vector<VkExtensionProperties> enumerated_device_exts{extension_count};
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count,
enumerated_device_exts.data()));
ASSERT_EQ(extension_count, exts_to_expect.size());
for (uint32_t i = 0; i < exts_to_expect.size(); i++) {
ASSERT_TRUE(exts_to_expect[i].extensionName == enumerated_device_exts[i].extensionName);
ASSERT_EQ(exts_to_expect[i].specVersion, enumerated_device_exts[i].specVersion);
}
}
{ // "Single call pattern"
uint32_t extension_count = static_cast<uint32_t>(exts_to_expect.size());
std::vector<VkExtensionProperties> enumerated_device_exts{extension_count};
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count,
enumerated_device_exts.data()));
ASSERT_EQ(extension_count, exts_to_expect.size());
enumerated_device_exts.resize(extension_count);
ASSERT_EQ(extension_count, exts_to_expect.size());
for (uint32_t i = 0; i < exts_to_expect.size(); i++) {
ASSERT_TRUE(exts_to_expect[i].extensionName == enumerated_device_exts[i].extensionName);
ASSERT_EQ(exts_to_expect[i].specVersion, enumerated_device_exts[i].specVersion);
}
}
{ // pPropertiesCount == NULL
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, nullptr, nullptr));
}
{ // 2nd call pass in way more than in reality
uint32_t extension_count = std::numeric_limits<uint32_t>::max();
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count, nullptr));
ASSERT_EQ(extension_count, exts_to_expect.size());
// reset size to a not earthshatteringly large number of extensions
extension_count = static_cast<uint32_t>(exts_to_expect.size()) * 4;
std::vector<VkExtensionProperties> enumerated_device_exts{extension_count};
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count,
enumerated_device_exts.data()));
ASSERT_EQ(extension_count, exts_to_expect.size());
for (uint32_t i = 0; i < exts_to_expect.size(); i++) {
ASSERT_TRUE(exts_to_expect[i].extensionName == enumerated_device_exts[i].extensionName);
ASSERT_EQ(exts_to_expect[i].specVersion, enumerated_device_exts[i].specVersion);
}
}
{ // 2nd call pass in not enough, go through all possible values from 0 to exts_to_expect.size()
uint32_t extension_count = std::numeric_limits<uint32_t>::max();
ASSERT_EQ(VK_SUCCESS, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count, nullptr));
ASSERT_EQ(extension_count, exts_to_expect.size());
std::vector<VkExtensionProperties> enumerated_device_exts{extension_count};
for (uint32_t i = 0; i < exts_to_expect.size() - 1; i++) {
extension_count = i;
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count,
enumerated_device_exts.data()));
ASSERT_EQ(extension_count, i);
for (uint32_t j = 0; j < i; j++) {
ASSERT_TRUE(exts_to_expect[j].extensionName == enumerated_device_exts[j].extensionName);
ASSERT_EQ(exts_to_expect[j].specVersion, enumerated_device_exts[j].specVersion);
}
}
}
}
TEST(EnumerateDeviceExtensionProperties, ImplicitLayerPresentNoExtensions) {
FrameworkEnvironment env{};
std::vector<Extension> exts = {Extension{"MyDriverExtension0", 4}, Extension{"MyDriverExtension1", 7},
Extension{"MyDriverExtension2", 6}, Extension{"MyDriverExtension3", 10}};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
.add_physical_device("physical_device_0")
.physical_devices.at(0)
.add_extensions(exts);
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name("implicit_layer_name")
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ME")),
"implicit_test_layer.json");
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
exercise_EnumerateDeviceExtensionProperties(inst, inst.GetPhysDev(), exts);
}
TEST(EnumerateDeviceExtensionProperties, ImplicitLayerPresentWithExtensions) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
std::vector<Extension> exts;
std::vector<ManifestLayer::LayerDescription::Extension> layer_exts;
for (uint32_t i = 0; i < 6; i++) {
exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
layer_exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
}
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name("implicit_layer_name")
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ME")
.add_device_extensions({layer_exts})),
"implicit_test_layer.json");
auto& layer = env.get_test_layer();
layer.device_extensions = exts;
driver.physical_devices.front().extensions.emplace_back("MyDriverExtension0", 4);
driver.physical_devices.front().extensions.emplace_back("MyDriverExtension1", 7);
exts.insert(exts.begin(), driver.physical_devices.front().extensions.begin(), driver.physical_devices.front().extensions.end());
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
VkPhysicalDevice physical_device = inst.GetPhysDev();
exercise_EnumerateDeviceExtensionProperties(inst, physical_device, exts);
}
TEST(EnumerateDeviceExtensionProperties, ImplicitLayerPresentWithLotsOfExtensions) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
std::vector<Extension> exts;
std::vector<ManifestLayer::LayerDescription::Extension> layer_exts;
for (uint32_t i = 0; i < 26; i++) {
exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
layer_exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
}
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name("implicit_layer_name")
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ME")
.add_device_extensions({layer_exts})),
"implicit_test_layer.json");
auto& layer = env.get_test_layer();
layer.device_extensions = exts;
driver.physical_devices.front().extensions.emplace_back("MyDriverExtension0", 4);
driver.physical_devices.front().extensions.emplace_back("MyDriverExtension1", 7);
driver.physical_devices.front().extensions.emplace_back("MyDriverExtension2", 6);
driver.physical_devices.front().extensions.emplace_back("MyDriverExtension3", 9);
exts.insert(exts.begin(), driver.physical_devices.front().extensions.begin(), driver.physical_devices.front().extensions.end());
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
VkPhysicalDevice physical_device = inst.GetPhysDev();
exercise_EnumerateDeviceExtensionProperties(inst, physical_device, exts);
}
TEST(EnumerateDeviceExtensionProperties, NoDriverExtensionsImplicitLayerPresentWithExtensions) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
std::vector<Extension> exts;
std::vector<ManifestLayer::LayerDescription::Extension> layer_exts;
for (uint32_t i = 0; i < 6; i++) {
exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
layer_exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
}
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name("implicit_layer_name")
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ME")
.add_device_extensions({layer_exts})),
"implicit_test_layer.json");
auto& layer = env.get_test_layer();
layer.device_extensions = exts;
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
VkPhysicalDevice physical_device = inst.GetPhysDev();
exercise_EnumerateDeviceExtensionProperties(inst, physical_device, exts);
}
TEST(EnumerateDeviceExtensionProperties, NoDriverExtensionsImplicitLayerPresentWithLotsOfExtensions) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
std::vector<Extension> exts;
std::vector<ManifestLayer::LayerDescription::Extension> layer_exts;
for (uint32_t i = 0; i < 6; i++) {
exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
layer_exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
}
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name("implicit_layer_name")
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ME")
.add_device_extensions({layer_exts})),
"implicit_test_layer.json");
auto& layer = env.get_test_layer();
layer.device_extensions = exts;
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
VkPhysicalDevice physical_device = inst.GetPhysDev();
exercise_EnumerateDeviceExtensionProperties(inst, physical_device, exts);
}
TEST(EnumerateDeviceExtensionProperties, ImplicitLayerPresentWithDuplicateExtensions) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
std::vector<Extension> exts;
std::vector<ManifestLayer::LayerDescription::Extension> layer_exts;
for (uint32_t i = 0; i < 26; i++) {
exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
layer_exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
}
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name("implicit_layer_name")
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ME")
.add_device_extensions({layer_exts})),
"implicit_test_layer.json");
auto& layer = env.get_test_layer();
layer.device_extensions = exts;
driver.physical_devices.front().extensions.emplace_back("MyDriverExtension0", 4);
driver.physical_devices.front().extensions.emplace_back("MyDriverExtension1", 7);
driver.physical_devices.front().extensions.insert(driver.physical_devices.front().extensions.end(), exts.begin(), exts.end());
exts.emplace_back("MyDriverExtension0", 4);
exts.emplace_back("MyDriverExtension1", 7);
driver.physical_devices.front().extensions = exts;
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
VkPhysicalDevice physical_device = inst.GetPhysDev();
exercise_EnumerateDeviceExtensionProperties(inst, physical_device, exts);
}
TEST(EnumerateDeviceExtensionProperties, ImplicitLayerPresentWithOnlyDuplicateExtensions) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
std::vector<Extension> exts;
std::vector<ManifestLayer::LayerDescription::Extension> layer_exts;
for (uint32_t i = 0; i < 26; i++) {
exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
layer_exts.emplace_back(std::string("LayerExtNumba") + std::to_string(i), i + 10);
}
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name("implicit_layer_name")
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ME")
.add_device_extensions({layer_exts})),
"implicit_test_layer.json");
auto& layer = env.get_test_layer();
layer.device_extensions = exts;
driver.physical_devices.front().extensions = exts;
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
VkPhysicalDevice physical_device = inst.GetPhysDev();
exercise_EnumerateDeviceExtensionProperties(inst, physical_device, exts);
}
TEST(EnumeratePhysicalDevices, OneCall) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
driver.add_physical_device("physical_device_0");
driver.add_physical_device("physical_device_1");
driver.add_physical_device("physical_device_2");
driver.add_physical_device("physical_device_3");
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = static_cast<uint32_t>(driver.physical_devices.size());
std::vector<VkPhysicalDevice> physical_device_handles = std::vector<VkPhysicalDevice>(physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data()));
ASSERT_EQ(physical_count, returned_physical_count);
}
TEST(EnumeratePhysicalDevices, TwoCall) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
.set_min_icd_interface_version(5)
.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
const uint32_t real_device_count = 2;
for (uint32_t i = 0; i < real_device_count; i++) {
driver.add_physical_device(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().extensions.push_back({VK_EXT_PCI_BUS_INFO_EXTENSION_NAME, 0});
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
ASSERT_EQ(physical_count, returned_physical_count);
std::array<VkPhysicalDevice, real_device_count> physical_device_handles;
ASSERT_EQ(VK_SUCCESS,
env.vulkan_functions.vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, physical_device_handles.data()));
ASSERT_EQ(physical_count, returned_physical_count);
}
TEST(EnumeratePhysicalDevices, MatchOneAndTwoCallNumbers) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
.set_min_icd_interface_version(5)
.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
const uint32_t real_device_count = 3;
for (uint32_t i = 0; i < real_device_count; i++) {
driver.add_physical_device(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().extensions.push_back({VK_EXT_PCI_BUS_INFO_EXTENSION_NAME, 0});
}
InstWrapper inst1{env.vulkan_functions};
inst1.CheckCreate();
uint32_t physical_count_one_call = static_cast<uint32_t>(driver.physical_devices.size());
std::array<VkPhysicalDevice, real_device_count> physical_device_handles_one_call;
ASSERT_EQ(VK_SUCCESS,
inst1->vkEnumeratePhysicalDevices(inst1, &physical_count_one_call, physical_device_handles_one_call.data()));
ASSERT_EQ(real_device_count, physical_count_one_call);
InstWrapper inst2{env.vulkan_functions};
inst2.CheckCreate();
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = 0;
ASSERT_EQ(VK_SUCCESS, inst2->vkEnumeratePhysicalDevices(inst2, &returned_physical_count, nullptr));
ASSERT_EQ(physical_count, returned_physical_count);
std::array<VkPhysicalDevice, real_device_count> physical_device_handles;
ASSERT_EQ(VK_SUCCESS, inst2->vkEnumeratePhysicalDevices(inst2, &returned_physical_count, physical_device_handles.data()));
ASSERT_EQ(real_device_count, returned_physical_count);
ASSERT_EQ(physical_count_one_call, returned_physical_count);
}
TEST(EnumeratePhysicalDevices, TwoCallIncomplete) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
.set_min_icd_interface_version(5)
.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
const uint32_t real_device_count = 2;
for (uint32_t i = 0; i < real_device_count; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().extensions.push_back({VK_EXT_PCI_BUS_INFO_EXTENSION_NAME, 0});
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
uint32_t physical_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &physical_count, nullptr));
ASSERT_EQ(physical_count, driver.physical_devices.size());
std::array<VkPhysicalDevice, real_device_count> physical;
auto temp_ptr = std::unique_ptr<int>(new int());
physical[0] = reinterpret_cast<VkPhysicalDevice>(temp_ptr.get());
physical[1] = reinterpret_cast<VkPhysicalDevice>(temp_ptr.get());
// Use zero for the device count so we can get the VK_INCOMPLETE message and verify nothing was written into physical
physical_count = 0;
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &physical_count, physical.data()));
ASSERT_EQ(physical_count, 0U);
ASSERT_EQ(static_cast<void*>(physical[0]), static_cast<void*>(temp_ptr.get()));
ASSERT_EQ(static_cast<void*>(physical[1]), static_cast<void*>(temp_ptr.get()));
// Remove one from the physical device count so we can get the VK_INCOMPLETE message
physical_count = 1;
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &physical_count, physical.data()));
ASSERT_EQ(physical_count, 1U);
ASSERT_EQ(static_cast<void*>(physical[1]), static_cast<void*>(temp_ptr.get()));
physical_count = 2;
std::array<VkPhysicalDevice, real_device_count> physical_2;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &physical_count, physical_2.data()));
// Verify that the first physical device shows up in the list of the second ones
ASSERT_TRUE(std::find(physical_2.begin(), physical_2.end(), physical[0]) != physical_2.end());
}
TEST(EnumeratePhysicalDevices, ZeroPhysicalDevices) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0));
inst.CheckCreate(VK_SUCCESS);
uint32_t count = 0;
ASSERT_EQ(VK_ERROR_INITIALIZATION_FAILED, env.vulkan_functions.vkEnumeratePhysicalDevices(inst, &count, nullptr));
ASSERT_EQ(count, 0U);
}
TEST(EnumeratePhysicalDevices, ZeroPhysicalDevicesAfterCreateInstance) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1)).set_min_icd_interface_version(5);
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(VK_API_VERSION_1_1);
inst.CheckCreate();
driver.physical_devices.clear();
uint32_t physical_device_count = 1000; // not zero starting value
VkPhysicalDevice physical_device{};
EXPECT_EQ(VK_ERROR_INITIALIZATION_FAILED, inst->vkEnumeratePhysicalDevices(inst, &physical_device_count, nullptr));
EXPECT_EQ(VK_ERROR_INITIALIZATION_FAILED, inst->vkEnumeratePhysicalDevices(inst, &physical_device_count, &physical_device));
uint32_t physical_device_group_count = 1000; // not zero starting value
VkPhysicalDeviceGroupProperties physical_device_group_properties{};
EXPECT_EQ(VK_ERROR_INITIALIZATION_FAILED, inst->vkEnumeratePhysicalDeviceGroups(inst, &physical_device_group_count, nullptr));
EXPECT_EQ(VK_ERROR_INITIALIZATION_FAILED,
inst->vkEnumeratePhysicalDeviceGroups(inst, &physical_device_group_count, &physical_device_group_properties));
}
TEST(EnumeratePhysicalDevices, CallTwiceNormal) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
for (size_t i = 0; i < 4; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
// Call twice in a row and make sure nothing bad happened
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = static_cast<uint32_t>(driver.physical_devices.size());
std::vector<VkPhysicalDevice> physical_device_handles_1 = std::vector<VkPhysicalDevice>(physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_1.data()));
ASSERT_EQ(physical_count, returned_physical_count);
std::vector<VkPhysicalDevice> physical_device_handles_2 = std::vector<VkPhysicalDevice>(physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_2.data()));
ASSERT_EQ(physical_count, returned_physical_count);
// Make sure devices are same between the two
for (uint32_t count = 0; count < driver.physical_devices.size(); ++count) {
ASSERT_EQ(physical_device_handles_1[count], physical_device_handles_2[count]);
}
}
TEST(EnumeratePhysicalDevices, CallTwiceIncompleteOnceNormal) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
for (size_t i = 0; i < 8; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
// Query 3, then 5, then all
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = 3;
std::vector<VkPhysicalDevice> physical_device_handles_1 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_1.data()));
ASSERT_EQ(3U, returned_physical_count);
returned_physical_count = 5;
std::vector<VkPhysicalDevice> physical_device_handles_2 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_2.data()));
ASSERT_EQ(5U, returned_physical_count);
returned_physical_count = physical_count;
std::vector<VkPhysicalDevice> physical_device_handles_3 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_3.data()));
ASSERT_EQ(physical_count, returned_physical_count);
// Make sure devices are same between the three
for (uint32_t count = 0; count < driver.physical_devices.size(); ++count) {
if (count < physical_device_handles_1.size()) {
ASSERT_EQ(physical_device_handles_1[count], physical_device_handles_3[count]);
}
if (count < physical_device_handles_2.size()) {
ASSERT_EQ(physical_device_handles_2[count], physical_device_handles_3[count]);
}
}
}
TEST(EnumeratePhysicalDevices, CallThriceSuccessReduce) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
for (size_t i = 0; i < 8; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
// Query all at first, then 5, then 3
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = physical_count;
std::vector<VkPhysicalDevice> physical_device_handles_1 = std::vector<VkPhysicalDevice>(physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_1.data()));
ASSERT_EQ(physical_count, returned_physical_count);
returned_physical_count = 5;
std::vector<VkPhysicalDevice> physical_device_handles_2 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_2.data()));
ASSERT_EQ(5U, returned_physical_count);
returned_physical_count = 3;
std::vector<VkPhysicalDevice> physical_device_handles_3 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_3.data()));
ASSERT_EQ(3U, returned_physical_count);
// Make sure devices are same between the three
for (uint32_t count = 0; count < driver.physical_devices.size(); ++count) {
if (count < physical_device_handles_2.size()) {
ASSERT_EQ(physical_device_handles_2[count], physical_device_handles_1[count]);
}
if (count < physical_device_handles_3.size()) {
ASSERT_EQ(physical_device_handles_3[count], physical_device_handles_1[count]);
}
}
}
TEST(EnumeratePhysicalDevices, CallThriceAddInBetween) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
driver.physical_devices.emplace_back("physical_device_0");
driver.physical_devices.emplace_back("physical_device_1");
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = physical_count;
std::vector<VkPhysicalDevice> physical_device_handles_1 = std::vector<VkPhysicalDevice>(physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_1.data()));
ASSERT_EQ(physical_count, returned_physical_count);
driver.physical_devices.emplace_back("physical_device_2");
driver.physical_devices.emplace_back("physical_device_3");
std::vector<VkPhysicalDevice> physical_device_handles_2 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_2.data()));
ASSERT_EQ(physical_count, returned_physical_count);
physical_count = static_cast<uint32_t>(driver.physical_devices.size());
returned_physical_count = physical_count;
std::vector<VkPhysicalDevice> physical_device_handles_3 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_3.data()));
ASSERT_EQ(physical_count, returned_physical_count);
// Make sure devices are same between the three
for (uint32_t count = 0; count < physical_device_handles_3.size(); ++count) {
if (count < physical_device_handles_1.size()) {
ASSERT_EQ(physical_device_handles_1[count], physical_device_handles_3[count]);
}
if (count < physical_device_handles_2.size()) {
ASSERT_EQ(physical_device_handles_2[count], physical_device_handles_3[count]);
}
}
}
TEST(EnumeratePhysicalDevices, CallThriceRemoveInBetween) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
for (size_t i = 0; i < 4; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = physical_count;
std::vector<VkPhysicalDevice> physical_device_handles_1 = std::vector<VkPhysicalDevice>(physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_1.data()));
ASSERT_EQ(physical_count, returned_physical_count);
// Delete the 2nd physical device
driver.physical_devices.erase(std::next(driver.physical_devices.begin()));
physical_count = static_cast<uint32_t>(driver.physical_devices.size());
std::vector<VkPhysicalDevice> physical_device_handles_2 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_2.data()));
ASSERT_EQ(physical_count, returned_physical_count);
physical_device_handles_2.resize(returned_physical_count);
returned_physical_count = physical_count;
std::vector<VkPhysicalDevice> physical_device_handles_3 = std::vector<VkPhysicalDevice>(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles_3.data()));
ASSERT_EQ(physical_count, returned_physical_count);
// Make sure one has 1 more device that two or three
ASSERT_EQ(physical_device_handles_1.size(), physical_device_handles_2.size() + 1);
ASSERT_EQ(physical_device_handles_1.size(), physical_device_handles_3.size() + 1);
// Make sure the devices in two and three are all found in one
uint32_t two_found = 0;
uint32_t three_found = 0;
for (uint32_t count = 0; count < physical_device_handles_1.size(); ++count) {
for (uint32_t int_count = 0; int_count < physical_device_handles_2.size(); ++int_count) {
if (physical_device_handles_2[int_count] == physical_device_handles_1[count]) {
two_found++;
break;
}
}
for (uint32_t int_count = 0; int_count < physical_device_handles_3.size(); ++int_count) {
if (physical_device_handles_3[int_count] == physical_device_handles_1[count]) {
three_found++;
break;
}
}
}
ASSERT_EQ(two_found, returned_physical_count);
ASSERT_EQ(three_found, returned_physical_count);
}
TEST(EnumeratePhysicalDevices, MultipleAddRemoves) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5);
for (size_t i = 0; i < 4; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
}
std::array<std::vector<VkPhysicalDevice>, 8> physical_dev_handles;
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
uint32_t physical_count = static_cast<uint32_t>(driver.physical_devices.size());
uint32_t returned_physical_count = physical_count;
physical_dev_handles[0].resize(physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_dev_handles[0].data()));
ASSERT_EQ(physical_count, returned_physical_count);
// Delete the 2nd physical device (0, 2, 3)
driver.physical_devices.erase(std::next(driver.physical_devices.begin()));
// Query using old number from last call (4), but it should only return 3
physical_count = static_cast<uint32_t>(driver.physical_devices.size());
physical_dev_handles[1].resize(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_dev_handles[1].data()));
ASSERT_EQ(physical_count, returned_physical_count);
physical_dev_handles[1].resize(returned_physical_count);
// Add two new physical devices to the front (A, B, 0, 2, 3)
driver.physical_devices.emplace(driver.physical_devices.begin(), "physical_device_B");
driver.physical_devices.emplace(driver.physical_devices.begin(), "physical_device_A");
// Query using old number from last call (3), but it should be 5
physical_count = static_cast<uint32_t>(driver.physical_devices.size());
physical_dev_handles[2].resize(returned_physical_count);
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_dev_handles[2].data()));
ASSERT_EQ(physical_count - 2, returned_physical_count);
physical_dev_handles[2].resize(returned_physical_count);
// Query again to get all 5
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, nullptr));
physical_dev_handles[3].resize(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_dev_handles[3].data()));
ASSERT_EQ(physical_count, returned_physical_count);
// Delete last two physical devices (A, B, 0, 2)
driver.physical_devices.pop_back();
// Query using old number from last call (5), but it should be 4
physical_count = static_cast<uint32_t>(driver.physical_devices.size());
physical_dev_handles[4].resize(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_dev_handles[4].data()));
ASSERT_EQ(physical_count, returned_physical_count);
physical_dev_handles[4].resize(returned_physical_count);
// Adjust size and query again, should be the same
physical_dev_handles[5].resize(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_dev_handles[5].data()));
// Insert a new physical device (A, B, C, 0, 2)
driver.physical_devices.insert(driver.physical_devices.begin() + 2, "physical_device_C");
// Query using old number from last call (4), but it should be 5
physical_count = static_cast<uint32_t>(driver.physical_devices.size());
physical_dev_handles[6].resize(returned_physical_count);
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_dev_handles[6].data()));
ASSERT_EQ(physical_count - 1, returned_physical_count);
// Query again to get all 5
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, nullptr));
physical_dev_handles[7].resize(returned_physical_count);
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_dev_handles[7].data()));
// Check final results
// One [4] - 0, 1, 2, 3
// Two [3] - 0, 2, 3
// Three [3] - A, B, 0
// Four [5] - A, B, 0, 2, 3
// Five [4] - A, B, 0, 2
// Six [4] - A, B, 0, 2
// Seven [4] - A, B, C, 0
// Eight [5] - A, B, C, 0, 2
ASSERT_EQ(4U, physical_dev_handles[0].size());
ASSERT_EQ(3U, physical_dev_handles[1].size());
ASSERT_EQ(3U, physical_dev_handles[2].size());
ASSERT_EQ(5U, physical_dev_handles[3].size());
ASSERT_EQ(4U, physical_dev_handles[4].size());
ASSERT_EQ(4U, physical_dev_handles[5].size());
ASSERT_EQ(4U, physical_dev_handles[6].size());
ASSERT_EQ(5U, physical_dev_handles[7].size());
// Make sure the devices in two and three are all found in one
uint32_t found_items[8]{};
for (uint32_t handle = 1; handle < 8; ++handle) {
for (uint32_t count = 0; count < physical_dev_handles[0].size(); ++count) {
for (uint32_t int_count = 0; int_count < physical_dev_handles[handle].size(); ++int_count) {
if (physical_dev_handles[handle][int_count] == physical_dev_handles[0][count]) {
found_items[handle]++;
break;
}
}
}
}
// Items matching from first call (must be >= since handle re-use does occur)
ASSERT_EQ(found_items[1], 3U);
ASSERT_GE(found_items[2], 1U);
ASSERT_GE(found_items[3], 3U);
ASSERT_GE(found_items[4], 2U);
ASSERT_GE(found_items[5], 2U);
ASSERT_GE(found_items[6], 1U);
ASSERT_GE(found_items[7], 2U);
memset(found_items, 0, 8 * sizeof(uint32_t));
for (uint32_t handle = 0; handle < 7; ++handle) {
for (uint32_t count = 0; count < physical_dev_handles[7].size(); ++count) {
for (uint32_t int_count = 0; int_count < physical_dev_handles[handle].size(); ++int_count) {
if (physical_dev_handles[handle][int_count] == physical_dev_handles[7][count]) {
found_items[handle]++;
break;
}
}
}
}
// Items matching from last call (must be >= since handle re-use does occur)
ASSERT_GE(found_items[0], 2U);
ASSERT_GE(found_items[1], 2U);
ASSERT_GE(found_items[2], 3U);
ASSERT_GE(found_items[3], 4U);
ASSERT_GE(found_items[4], 4U);
ASSERT_GE(found_items[5], 4U);
ASSERT_GE(found_items[6], 4U);
}
TEST(EnumeratePhysicalDevices, OneDriverWithWrongErrorCodes) {
FrameworkEnvironment env;
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(VK_API_VERSION_1_1);
inst.CheckCreate();
{
env.get_test_icd().set_enum_physical_devices_return_code(VK_ERROR_INITIALIZATION_FAILED);
uint32_t returned_physical_count = 0;
EXPECT_EQ(VK_ERROR_INITIALIZATION_FAILED,
env.vulkan_functions.vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
EXPECT_EQ(returned_physical_count, 0);
}
{
env.get_test_icd().set_enum_physical_devices_return_code(VK_ERROR_INCOMPATIBLE_DRIVER);
uint32_t returned_physical_count = 0;
EXPECT_EQ(VK_ERROR_INITIALIZATION_FAILED,
env.vulkan_functions.vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
EXPECT_EQ(returned_physical_count, 0);
}
{
env.get_test_icd().set_enum_physical_devices_return_code(VK_ERROR_SURFACE_LOST_KHR);
uint32_t returned_physical_count = 0;
EXPECT_EQ(VK_ERROR_INITIALIZATION_FAILED,
env.vulkan_functions.vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
EXPECT_EQ(returned_physical_count, 0);
}
}
TEST(EnumeratePhysicalDevices, TwoDriversOneWithWrongErrorCodes) {
FrameworkEnvironment env;
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
TestICD& icd1 = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(VK_API_VERSION_1_1);
inst.CheckCreate();
{
icd1.set_enum_physical_devices_return_code(VK_ERROR_INITIALIZATION_FAILED);
uint32_t returned_physical_count = 0;
EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
EXPECT_EQ(returned_physical_count, 1);
}
{
icd1.set_enum_physical_devices_return_code(VK_ERROR_INCOMPATIBLE_DRIVER);
uint32_t returned_physical_count = 0;
EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
EXPECT_EQ(returned_physical_count, 1);
}
{
icd1.set_enum_physical_devices_return_code(VK_ERROR_SURFACE_LOST_KHR);
uint32_t returned_physical_count = 0;
EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
EXPECT_EQ(returned_physical_count, 1);
}
}
TEST(CreateDevice, ExtensionNotPresent) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
DeviceWrapper dev{inst};
dev.create_info.add_extension("NotPresent");
dev.CheckCreate(phys_dev, VK_ERROR_EXTENSION_NOT_PRESENT);
}
// LX535 / MI-76: Device layers are deprecated.
// Ensure that no errors occur if a bogus device layer list is passed to vkCreateDevice.
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#extendingvulkan-layers-devicelayerdeprecation
TEST(CreateDevice, LayersNotPresent) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
DeviceWrapper dev{inst};
dev.create_info.add_layer("NotPresent");
dev.CheckCreate(phys_dev);
}
// Device layers are deprecated.
// Ensure that no error occur if instance and device are created with the same list of layers.
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#extendingvulkan-layers-devicelayerdeprecation
TEST(CreateDevice, MatchInstanceAndDeviceLayers) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name = "TestLayer";
env.add_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"test_layer.json");
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name);
inst.CheckCreate();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
DeviceWrapper dev{inst};
dev.create_info.add_layer(layer_name);
dev.CheckCreate(phys_dev);
}
// Device layers are deprecated.
// Ensure that a message is generated when instance and device are created with different list of layers.
// At best , the user can list only instance layers in the device layer list
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#extendingvulkan-layers-devicelayerdeprecation
TEST(CreateDevice, UnmatchInstanceAndDeviceLayers) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name = "TestLayer";
env.add_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"test_layer.json");
DebugUtilsLogger debug_log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
FillDebugUtilsCreateDetails(inst.create_info, debug_log);
inst.CheckCreate();
DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT};
CreateDebugUtilsMessenger(log);
VkPhysicalDevice phys_dev = inst.GetPhysDev();
DeviceWrapper dev{inst};
dev.create_info.add_layer(layer_name);
dev.CheckCreate(phys_dev);
ASSERT_TRUE(
log.find("loader_create_device_chain: Using deprecated and ignored 'ppEnabledLayerNames' member of 'VkDeviceCreateInfo' "
"when creating a Vulkan device."));
}
// Device layers are deprecated.
// Ensure that when VkInstanceCreateInfo is deleted, the check of the instance layer lists is running correctly during VkDevice
// creation
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#extendingvulkan-layers-devicelayerdeprecation
TEST(CreateDevice, CheckCopyOfInstanceLayerNames) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name = "TestLayer";
env.add_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"test_layer.json");
InstWrapper inst{env.vulkan_functions};
{
// We intentionally create a local InstanceCreateInfo that goes out of scope at the } so that when dev.CheckCreate is called
// the layer name pointers are no longer valid
InstanceCreateInfo create_info{};
create_info.add_layer(layer_name);
inst.CheckCreateWithInfo(create_info);
}
VkPhysicalDevice phys_dev = inst.GetPhysDev();
DeviceWrapper dev{inst};
dev.create_info.add_layer(layer_name);
dev.CheckCreate(phys_dev);
}
TEST(CreateDevice, ConsecutiveCreate) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
for (uint32_t i = 0; i < 100; i++) {
driver.physical_devices.emplace_back("physical_device_0");
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
auto phys_devs = inst.GetPhysDevs(100);
for (uint32_t i = 0; i < 100; i++) {
DeviceWrapper dev{inst};
dev.CheckCreate(phys_devs[i]);
}
}
TEST(CreateDevice, ConsecutiveCreateWithoutDestruction) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
for (uint32_t i = 0; i < 100; i++) {
driver.physical_devices.emplace_back("physical_device_0");
}
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
auto phys_devs = inst.GetPhysDevs(100);
std::vector<DeviceWrapper> devices;
for (uint32_t i = 0; i < 100; i++) {
devices.emplace_back(inst);
DeviceWrapper& dev = devices.back();
dev.CheckCreate(phys_devs[i]);
}
}
TEST(TryLoadWrongBinaries, WrongICD) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
env.add_icd(TestICDDetails(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE).set_is_fake(true));
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.CheckCreate();
#if _WIN32 || _WIN64
ASSERT_TRUE(log.find("Failed to open dynamic library"));
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__GNU__) || defined(__QNX__)
#if defined(__x86_64__) || __ppc64__ || __aarch64__
ASSERT_TRUE(log.find("wrong ELF class: ELFCLASS32"));
#else
ASSERT_TRUE(log.find("wrong ELF class: ELFCLASS64"));
#endif
#endif
uint32_t driver_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, nullptr));
ASSERT_EQ(driver_count, 1U);
}
TEST(TryLoadWrongBinaries, WrongExplicit) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name = "DummyLayerExplicit";
env.add_fake_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)),
"dummy_test_layer.json");
auto layer_props = env.GetLayerProperties(1);
ASSERT_TRUE(string_eq(layer_name, layer_props[0].layerName));
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name);
FillDebugUtilsCreateDetails(inst.create_info, log);
// Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
// Should get an error message for the explicit layer
#if !defined(__APPLE__)
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" was wrong bit-type!")));
#else // __APPLE__
// Apple only throws a wrong library type of error
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" failed to load!")));
#endif // __APPLE__
}
TEST(TryLoadWrongBinaries, WrongImplicit) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name = "DummyLayerImplicit0";
env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(layer_name)
.set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)
.set_disable_environment("DISABLE_ENV")),
"dummy_test_layer.json");
auto layer_props = env.GetLayerProperties(1);
ASSERT_TRUE(string_eq(layer_name, layer_props[0].layerName));
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
FillDebugUtilsCreateDetails(inst.create_info, log);
// We don't want to return VK_ERROR_LAYER_NOT_PRESENT for missing implicit layers because it's not the
// application asking for them.
inst.CheckCreate(VK_SUCCESS);
#if !defined(__APPLE__)
// Should get an info message for the bad implicit layer
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" was wrong bit-type.")));
#else // __APPLE__
// Apple only throws a wrong library type of error
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" failed to load.")));
#endif // __APPLE__
}
TEST(TryLoadWrongBinaries, WrongExplicitAndImplicit) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name_0 = "DummyLayerExplicit";
env.add_fake_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name_0).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)),
"dummy_test_layer_0.json");
const char* layer_name_1 = "DummyLayerImplicit";
env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(layer_name_1)
.set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)
.set_disable_environment("DISABLE_ENV")),
"dummy_test_layer_1.json");
auto layer_props = env.GetLayerProperties(2);
ASSERT_TRUE(check_permutation({layer_name_0, layer_name_1}, layer_props));
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name_0);
FillDebugUtilsCreateDetails(inst.create_info, log);
// Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
#if !defined(__APPLE__)
// Should get error messages for both (the explicit is second and we don't want the implicit to return before the explicit
// triggers a failure during vkCreateInstance)
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" was wrong bit-type!")));
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" was wrong bit-type.")));
#else // __APPLE__
// Apple only throws a wrong library type of error
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" failed to load!")));
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" failed to load.")));
#endif // __APPLE__
}
TEST(TryLoadWrongBinaries, WrongExplicitAndImplicitErrorOnly) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name_0 = "DummyLayerExplicit";
env.add_fake_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name_0).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)),
"dummy_test_layer_0.json");
const char* layer_name_1 = "DummyLayerImplicit";
env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(layer_name_1)
.set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)
.set_disable_environment("DISABLE_ENV")),
"dummy_test_layer_1.json");
auto layer_props = env.GetLayerProperties(2);
ASSERT_TRUE(check_permutation({layer_name_0, layer_name_1}, layer_props));
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name_0);
FillDebugUtilsCreateDetails(inst.create_info, log);
// Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
#if !defined(__APPLE__)
// Should not get an error messages for either
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" was wrong bit-type!")));
ASSERT_FALSE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" was wrong bit-type.")));
#else // __APPLE__
// Apple only throws a wrong library type of error
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" failed to load!")));
ASSERT_FALSE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" failed to load.")));
#endif // __APPLE__
}
TEST(TryLoadWrongBinaries, BadExplicit) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name = "DummyLayerExplicit";
env.add_fake_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_BAD)),
"dummy_test_layer.json");
auto layer_props = env.GetLayerProperties(1);
ASSERT_TRUE(string_eq(layer_name, layer_props[0].layerName));
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name);
FillDebugUtilsCreateDetails(inst.create_info, log);
// Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
// Should get an error message for the bad explicit
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" failed to load!")));
}
TEST(TryLoadWrongBinaries, BadImplicit) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name = "DummyLayerImplicit0";
env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(layer_name)
.set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_BAD)
.set_disable_environment("DISABLE_ENV")),
"dummy_test_layer.json");
auto layer_props = env.GetLayerProperties(1);
ASSERT_TRUE(string_eq(layer_name, layer_props[0].layerName));
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
FillDebugUtilsCreateDetails(inst.create_info, log);
// We don't want to return VK_ERROR_LAYER_NOT_PRESENT for missing implicit layers because it's not the
// application asking for them.
inst.CheckCreate(VK_SUCCESS);
// Should get an info message for the bad implicit
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" failed to load.")));
}
TEST(TryLoadWrongBinaries, BadExplicitAndImplicit) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
const char* layer_name_0 = "DummyLayerExplicit";
env.add_fake_explicit_layer(
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(layer_name_0).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_BAD)),
"dummy_test_layer_0.json");
const char* layer_name_1 = "DummyLayerImplicit0";
env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(layer_name_1)
.set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_BAD)
.set_disable_environment("DISABLE_ENV")),
"dummy_test_layer_1.json");
auto layer_props = env.GetLayerProperties(2);
ASSERT_TRUE(check_permutation({layer_name_0, layer_name_1}, layer_props));
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_layer(layer_name_0);
FillDebugUtilsCreateDetails(inst.create_info, log);
// Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
// Apple only throws a wrong library type of error
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" failed to load!")));
ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" failed to load.")));
}
TEST(TryLoadWrongBinaries, WrongArchDriver) {
FrameworkEnvironment env{};
// Intentionally set the wrong arch
env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2}.icd_manifest.set_library_arch(sizeof(void*) == 4 ? "64" : "32"))
.add_physical_device("physical_device_0");
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
ASSERT_TRUE(
log.find("loader_parse_icd_manifest: Driver library architecture doesn't match the current running architecture, skipping "
"this driver"));
}
TEST(TryLoadWrongBinaries, WrongArchLayer) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2}).add_physical_device("physical_device_0");
const char* layer_name = "TestLayer";
env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(layer_name)
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
// Intentionally set the wrong arch
.set_library_arch(sizeof(void*) == 4 ? "64" : "32")),
"test_layer.json");
DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
InstWrapper inst{env.vulkan_functions};
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.create_info.add_layer(layer_name);
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
ASSERT_TRUE(log.find("Layer library architecture doesn't match the current running architecture, skipping this layer"));
}
TEST(EnumeratePhysicalDeviceGroups, OneCall) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1)
.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
// ICD contains 3 devices in two groups
for (size_t i = 0; i < 3; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().extensions.push_back({VK_EXT_PCI_BUS_INFO_EXTENSION_NAME, 0});
driver.physical_devices.back().properties.apiVersion = VK_API_VERSION_1_1;
}
driver.physical_device_groups.emplace_back(driver.physical_devices[0]);
driver.physical_device_groups.back().use_physical_device(driver.physical_devices[1]);
driver.physical_device_groups.emplace_back(driver.physical_devices[2]);
const uint32_t max_physical_device_count = 3;
// Core function
{
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(VK_API_VERSION_1_1);
inst.CheckCreate();
auto physical_devices = std::vector<VkPhysicalDevice>(max_physical_device_count);
uint32_t returned_phys_dev_count = max_physical_device_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_phys_dev_count, physical_devices.data()));
handle_assert_has_values(physical_devices);
uint32_t group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
uint32_t returned_group_count = group_count;
std::vector<VkPhysicalDeviceGroupProperties> group_props{};
group_props.resize(group_count, VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props.data()));
ASSERT_EQ(group_count, returned_group_count);
// Make sure each physical device shows up in a group, but only once
std::array<bool, max_physical_device_count> found{false};
for (uint32_t group = 0; group < group_count; ++group) {
for (uint32_t g_dev = 0; g_dev < group_props[group].physicalDeviceCount; ++g_dev) {
for (uint32_t dev = 0; dev < max_physical_device_count; ++dev) {
if (physical_devices[dev] == group_props[group].physicalDevices[g_dev]) {
ASSERT_EQ(false, found[dev]);
found[dev] = true;
break;
}
}
}
}
for (uint32_t dev = 0; dev < max_physical_device_count; ++dev) {
ASSERT_EQ(true, found[dev]);
}
for (auto& group : group_props) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
VkBaseInStructure spacer_structure{};
spacer_structure.sType = static_cast<VkStructureType>(100000);
spacer_structure.pNext = reinterpret_cast<const VkBaseInStructure*>(&group_info);
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &spacer_structure;
dev.CheckCreate(group.physicalDevices[0]);
// This convoluted logic makes sure that the pNext chain is unmolested after being passed into vkCreateDevice
// While not expected for applications to iterate over this chain, since it is const it is important to make sure
// that the chain didn't change somehow, and especially so that iterating it doesn't crash.
int count = 0;
const VkBaseInStructure* pNext = reinterpret_cast<const VkBaseInStructure*>(dev.create_info.dev.pNext);
while (pNext != nullptr) {
if (pNext->sType == VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO) {
ASSERT_EQ(&group_info, reinterpret_cast<const VkDeviceGroupDeviceCreateInfo*>(pNext));
}
if (pNext->sType == 100000) {
ASSERT_EQ(&spacer_structure, pNext);
}
pNext = pNext->pNext;
count++;
}
ASSERT_EQ(count, 2);
}
}
driver.add_instance_extension({VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME});
// Extension
{
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_extension(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME);
inst.CheckCreate();
PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR = inst.load("vkEnumeratePhysicalDeviceGroupsKHR");
auto physical_devices = std::vector<VkPhysicalDevice>(max_physical_device_count);
uint32_t returned_phys_dev_count = max_physical_device_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_phys_dev_count, physical_devices.data()));
handle_assert_has_values(physical_devices);
uint32_t group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
uint32_t returned_group_count = group_count;
std::vector<VkPhysicalDeviceGroupProperties> group_props{};
group_props.resize(group_count, VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, vkEnumeratePhysicalDeviceGroupsKHR(inst, &returned_group_count, group_props.data()));
ASSERT_EQ(group_count, returned_group_count);
// Make sure each physical device shows up in a group, but only once
std::array<bool, max_physical_device_count> found{false};
for (uint32_t group = 0; group < group_count; ++group) {
for (uint32_t g_dev = 0; g_dev < group_props[group].physicalDeviceCount; ++g_dev) {
for (uint32_t dev = 0; dev < max_physical_device_count; ++dev) {
if (physical_devices[dev] == group_props[group].physicalDevices[g_dev]) {
ASSERT_EQ(false, found[dev]);
found[dev] = true;
break;
}
}
}
}
for (uint32_t dev = 0; dev < max_physical_device_count; ++dev) {
ASSERT_EQ(true, found[dev]);
}
for (auto& group : group_props) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
VkBaseInStructure spacer_structure{};
spacer_structure.sType = static_cast<VkStructureType>(100000);
spacer_structure.pNext = reinterpret_cast<const VkBaseInStructure*>(&group_info);
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &spacer_structure;
dev.CheckCreate(group.physicalDevices[0]);
}
}
}
TEST(EnumeratePhysicalDeviceGroups, TwoCall) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1)
.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
// ICD contains 3 devices in two groups
for (size_t i = 0; i < 3; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().extensions.push_back({VK_EXT_PCI_BUS_INFO_EXTENSION_NAME, 0});
driver.physical_devices.back().properties.apiVersion = VK_API_VERSION_1_1;
}
driver.physical_device_groups.emplace_back(driver.physical_devices[0]);
driver.physical_device_groups.back().use_physical_device(driver.physical_devices[1]);
driver.physical_device_groups.emplace_back(driver.physical_devices[2]);
const uint32_t max_physical_device_count = 3;
// Core function
{
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(VK_API_VERSION_1_1);
inst.CheckCreate();
auto physical_devices = std::vector<VkPhysicalDevice>(max_physical_device_count);
uint32_t returned_phys_dev_count = max_physical_device_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_phys_dev_count, physical_devices.data()));
handle_assert_has_values(physical_devices);
uint32_t group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
uint32_t returned_group_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, nullptr));
ASSERT_EQ(group_count, returned_group_count);
std::vector<VkPhysicalDeviceGroupProperties> group_props{};
group_props.resize(group_count, VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props.data()));
ASSERT_EQ(group_count, returned_group_count);
// Make sure each physical device shows up in a group, but only once
std::array<bool, max_physical_device_count> found{false};
for (uint32_t group = 0; group < group_count; ++group) {
for (uint32_t g_dev = 0; g_dev < group_props[group].physicalDeviceCount; ++g_dev) {
for (uint32_t dev = 0; dev < max_physical_device_count; ++dev) {
if (physical_devices[dev] == group_props[group].physicalDevices[g_dev]) {
ASSERT_EQ(false, found[dev]);
found[dev] = true;
break;
}
}
}
}
for (uint32_t dev = 0; dev < max_physical_device_count; ++dev) {
ASSERT_EQ(true, found[dev]);
}
for (auto& group : group_props) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
driver.add_instance_extension({VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME});
// Extension
{
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_extension("VK_KHR_device_group_creation");
inst.CheckCreate();
auto physical_devices = std::vector<VkPhysicalDevice>(max_physical_device_count);
uint32_t returned_phys_dev_count = max_physical_device_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_phys_dev_count, physical_devices.data()));
handle_assert_has_values(physical_devices);
PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR = inst.load("vkEnumeratePhysicalDeviceGroupsKHR");
uint32_t group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
uint32_t returned_group_count = 0;
ASSERT_EQ(VK_SUCCESS, vkEnumeratePhysicalDeviceGroupsKHR(inst, &returned_group_count, nullptr));
ASSERT_EQ(group_count, returned_group_count);
std::vector<VkPhysicalDeviceGroupProperties> group_props{};
group_props.resize(group_count, VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, vkEnumeratePhysicalDeviceGroupsKHR(inst, &returned_group_count, group_props.data()));
ASSERT_EQ(group_count, returned_group_count);
// Make sure each physical device shows up in a group, but only once
std::array<bool, max_physical_device_count> found{false};
for (uint32_t group = 0; group < group_count; ++group) {
for (uint32_t g_dev = 0; g_dev < group_props[group].physicalDeviceCount; ++g_dev) {
for (uint32_t dev = 0; dev < max_physical_device_count; ++dev) {
if (physical_devices[dev] == group_props[group].physicalDevices[g_dev]) {
ASSERT_EQ(false, found[dev]);
found[dev] = true;
break;
}
}
}
}
for (uint32_t dev = 0; dev < max_physical_device_count; ++dev) {
ASSERT_EQ(true, found[dev]);
}
for (auto& group : group_props) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
}
TEST(EnumeratePhysicalDeviceGroups, TwoCallIncomplete) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1)
.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
// ICD contains 3 devices in two groups
for (size_t i = 0; i < 3; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().extensions.push_back({VK_EXT_PCI_BUS_INFO_EXTENSION_NAME, 0});
driver.physical_devices.back().properties.apiVersion = VK_API_VERSION_1_1;
}
driver.physical_device_groups.emplace_back(driver.physical_devices[0]);
driver.physical_device_groups.back().use_physical_device(driver.physical_devices[1]);
driver.physical_device_groups.emplace_back(driver.physical_devices[2]);
// Core function
{
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(VK_API_VERSION_1_1);
inst.CheckCreate();
uint32_t group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
uint32_t returned_group_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, nullptr));
ASSERT_EQ(group_count, returned_group_count);
returned_group_count = 1;
std::array<VkPhysicalDeviceGroupProperties, 1> group_props{};
group_props[0].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props.data()));
ASSERT_EQ(1U, returned_group_count);
returned_group_count = 2;
std::array<VkPhysicalDeviceGroupProperties, 2> group_props_2{};
group_props_2[0].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
group_props_2[1].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_2.data()));
ASSERT_EQ(2U, returned_group_count);
ASSERT_EQ(group_props[0].physicalDeviceCount, group_props_2[0].physicalDeviceCount);
ASSERT_EQ(group_props[0].physicalDevices[0], group_props_2[0].physicalDevices[0]);
ASSERT_EQ(group_props[0].physicalDevices[1], group_props_2[0].physicalDevices[1]);
for (auto& group : group_props) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
driver.add_instance_extension({VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME});
// Extension
{
InstWrapper inst{env.vulkan_functions};
inst.create_info.add_extension("VK_KHR_device_group_creation");
inst.CheckCreate();
PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR = inst.load("vkEnumeratePhysicalDeviceGroupsKHR");
uint32_t group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
uint32_t returned_group_count = 0;
ASSERT_EQ(VK_SUCCESS, vkEnumeratePhysicalDeviceGroupsKHR(inst, &returned_group_count, nullptr));
ASSERT_EQ(group_count, returned_group_count);
returned_group_count = 1;
std::array<VkPhysicalDeviceGroupProperties, 1> group_props{};
group_props[0].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
ASSERT_EQ(VK_INCOMPLETE, vkEnumeratePhysicalDeviceGroupsKHR(inst, &returned_group_count, group_props.data()));
ASSERT_EQ(1U, returned_group_count);
returned_group_count = 2;
std::array<VkPhysicalDeviceGroupProperties, 2> group_props_2{};
group_props_2[0].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
group_props_2[1].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
ASSERT_EQ(VK_SUCCESS, vkEnumeratePhysicalDeviceGroupsKHR(inst, &returned_group_count, group_props_2.data()));
ASSERT_EQ(2U, returned_group_count);
ASSERT_EQ(group_props[0].physicalDeviceCount, group_props_2[0].physicalDeviceCount);
ASSERT_EQ(group_props[0].physicalDevices[0], group_props_2[0].physicalDevices[0]);
ASSERT_EQ(group_props[0].physicalDevices[1], group_props_2[0].physicalDevices[1]);
for (auto& group : group_props) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
}
// Call the core vkEnumeratePhysicalDeviceGroups and the extension
// vkEnumeratePhysicalDeviceGroupsKHR, and make sure they return the same info.
TEST(EnumeratePhysicalDeviceGroups, TestCoreVersusExtensionSameReturns) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1)
.add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME})
.add_instance_extension({VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME});
// Generate the devices
for (size_t i = 0; i < 6; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().properties.apiVersion = VK_API_VERSION_1_1;
}
// Generate the starting groups
driver.physical_device_groups.emplace_back(driver.physical_devices[0]);
driver.physical_device_groups.emplace_back(driver.physical_devices[1]);
driver.physical_device_groups.back()
.use_physical_device(driver.physical_devices[2])
.use_physical_device(driver.physical_devices[3]);
driver.physical_device_groups.emplace_back(driver.physical_devices[4]);
driver.physical_device_groups.back().use_physical_device(driver.physical_devices[5]);
uint32_t expected_counts[3] = {1, 3, 2};
uint32_t core_group_count = 0;
std::vector<VkPhysicalDeviceGroupProperties> core_group_props{};
uint32_t ext_group_count = 0;
std::vector<VkPhysicalDeviceGroupProperties> ext_group_props{};
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(1, 1, 0);
inst.create_info.add_extension("VK_KHR_device_group_creation");
inst.CheckCreate();
// Core function
core_group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
uint32_t returned_group_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, nullptr));
ASSERT_EQ(core_group_count, returned_group_count);
core_group_props.resize(returned_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, core_group_props.data()));
ASSERT_EQ(core_group_count, returned_group_count);
PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR = inst.load("vkEnumeratePhysicalDeviceGroupsKHR");
ext_group_count = static_cast<uint32_t>(driver.physical_device_groups.size());
returned_group_count = 0;
ASSERT_EQ(VK_SUCCESS, vkEnumeratePhysicalDeviceGroupsKHR(inst, &returned_group_count, nullptr));
ASSERT_EQ(ext_group_count, returned_group_count);
ext_group_props.resize(returned_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, vkEnumeratePhysicalDeviceGroupsKHR(inst, &returned_group_count, ext_group_props.data()));
ASSERT_EQ(ext_group_count, returned_group_count);
// Make sure data from each matches
ASSERT_EQ(core_group_count, 3U);
ASSERT_EQ(ext_group_count, 3U);
for (uint32_t group = 0; group < core_group_count; ++group) {
ASSERT_EQ(core_group_props[group].physicalDeviceCount, expected_counts[group]);
ASSERT_EQ(ext_group_props[group].physicalDeviceCount, expected_counts[group]);
for (uint32_t dev = 0; dev < core_group_props[group].physicalDeviceCount; ++dev) {
ASSERT_EQ(core_group_props[group].physicalDevices[dev], ext_group_props[group].physicalDevices[dev]);
}
}
// Make sure no physical device appears in more than one group
for (uint32_t group1 = 0; group1 < core_group_count; ++group1) {
for (uint32_t group2 = group1 + 1; group2 < core_group_count; ++group2) {
for (uint32_t dev1 = 0; dev1 < core_group_props[group1].physicalDeviceCount; ++dev1) {
for (uint32_t dev2 = 0; dev2 < core_group_props[group1].physicalDeviceCount; ++dev2) {
ASSERT_NE(core_group_props[group1].physicalDevices[dev1], core_group_props[group2].physicalDevices[dev2]);
}
}
}
}
for (auto& group : core_group_props) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
// Start with 6 devices in 3 different groups, and then add a group,
// querying vkEnumeratePhysicalDeviceGroups before and after the add.
TEST(EnumeratePhysicalDeviceGroups, CallThriceAddGroupInBetween) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1);
// Generate the devices
for (size_t i = 0; i < 7; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().properties.apiVersion = VK_API_VERSION_1_1;
}
// Generate the starting groups
driver.physical_device_groups.emplace_back(driver.physical_devices[0]);
driver.physical_device_groups.emplace_back(driver.physical_devices[1]);
driver.physical_device_groups.back()
.use_physical_device(driver.physical_devices[2])
.use_physical_device(driver.physical_devices[3]);
driver.physical_device_groups.emplace_back(driver.physical_devices[4]);
driver.physical_device_groups.back().use_physical_device(driver.physical_devices[5]);
uint32_t before_expected_counts[3] = {1, 3, 2};
uint32_t after_expected_counts[4] = {1, 3, 1, 2};
uint32_t before_group_count = 3;
uint32_t after_group_count = 4;
uint32_t returned_group_count = 0;
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(1, 1, 0);
inst.CheckCreate();
std::vector<VkPhysicalDeviceGroupProperties> group_props_before{};
group_props_before.resize(before_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
returned_group_count = before_group_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_before.data()));
ASSERT_EQ(before_group_count, returned_group_count);
for (uint32_t group = 0; group < before_group_count; ++group) {
ASSERT_EQ(group_props_before[group].physicalDeviceCount, before_expected_counts[group]);
}
// Insert new group after first two
driver.physical_device_groups.insert(driver.physical_device_groups.begin() + 2, driver.physical_devices[6]);
std::vector<VkPhysicalDeviceGroupProperties> group_props_after{};
group_props_after.resize(before_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_after.data()));
ASSERT_EQ(before_group_count, returned_group_count);
for (uint32_t group = 0; group < before_group_count; ++group) {
ASSERT_EQ(group_props_after[group].physicalDeviceCount, after_expected_counts[group]);
}
group_props_after.resize(after_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
returned_group_count = after_group_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_after.data()));
ASSERT_EQ(after_group_count, returned_group_count);
for (uint32_t group = 0; group < after_group_count; ++group) {
ASSERT_EQ(group_props_after[group].physicalDeviceCount, after_expected_counts[group]);
}
// Make sure all devices in the old group info are still found in the new group info
for (uint32_t group1 = 0; group1 < group_props_before.size(); ++group1) {
for (uint32_t group2 = 0; group2 < group_props_after.size(); ++group2) {
if (group_props_before[group1].physicalDeviceCount == group_props_after[group2].physicalDeviceCount) {
uint32_t found_count = 0;
bool found = false;
for (uint32_t dev1 = 0; dev1 < group_props_before[group1].physicalDeviceCount; ++dev1) {
found = false;
for (uint32_t dev2 = 0; dev2 < group_props_after[group2].physicalDeviceCount; ++dev2) {
if (group_props_before[group1].physicalDevices[dev1] == group_props_after[group2].physicalDevices[dev2]) {
found_count++;
found = true;
break;
}
}
}
ASSERT_EQ(found, found_count == group_props_before[group1].physicalDeviceCount);
}
}
}
for (auto& group : group_props_after) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
// Start with 7 devices in 4 different groups, and then remove a group,
// querying vkEnumeratePhysicalDeviceGroups before and after the remove.
TEST(EnumeratePhysicalDeviceGroups, CallTwiceRemoveGroupInBetween) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1);
// Generate the devices
for (size_t i = 0; i < 7; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().properties.apiVersion = VK_API_VERSION_1_1;
}
// Generate the starting groups
driver.physical_device_groups.emplace_back(driver.physical_devices[0]);
driver.physical_device_groups.emplace_back(driver.physical_devices[1]);
driver.physical_device_groups.back()
.use_physical_device(driver.physical_devices[2])
.use_physical_device(driver.physical_devices[3]);
driver.physical_device_groups.emplace_back(driver.physical_devices[4]);
driver.physical_device_groups.emplace_back(driver.physical_devices[5]);
driver.physical_device_groups.back().use_physical_device(driver.physical_devices[6]);
uint32_t before_expected_counts[4] = {1, 3, 1, 2};
uint32_t after_expected_counts[3] = {1, 3, 2};
uint32_t before_group_count = 4;
uint32_t after_group_count = 3;
uint32_t returned_group_count = 0;
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(1, 1, 0);
inst.CheckCreate();
std::vector<VkPhysicalDeviceGroupProperties> group_props_before{};
group_props_before.resize(before_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
returned_group_count = before_group_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_before.data()));
ASSERT_EQ(before_group_count, returned_group_count);
for (uint32_t group = 0; group < before_group_count; ++group) {
ASSERT_EQ(group_props_before[group].physicalDeviceCount, before_expected_counts[group]);
}
// Insert new group after first two
driver.physical_device_groups.erase(driver.physical_device_groups.begin() + 2);
std::vector<VkPhysicalDeviceGroupProperties> group_props_after{};
group_props_after.resize(after_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_after.data()));
ASSERT_EQ(after_group_count, returned_group_count);
for (uint32_t group = 0; group < after_group_count; ++group) {
ASSERT_EQ(group_props_after[group].physicalDeviceCount, after_expected_counts[group]);
}
// Make sure all devices in the new group info are found in the old group info
for (uint32_t group1 = 0; group1 < group_props_after.size(); ++group1) {
for (uint32_t group2 = 0; group2 < group_props_before.size(); ++group2) {
if (group_props_after[group1].physicalDeviceCount == group_props_before[group2].physicalDeviceCount) {
uint32_t found_count = 0;
bool found = false;
for (uint32_t dev1 = 0; dev1 < group_props_after[group1].physicalDeviceCount; ++dev1) {
found = false;
for (uint32_t dev2 = 0; dev2 < group_props_before[group2].physicalDeviceCount; ++dev2) {
if (group_props_after[group1].physicalDevices[dev1] == group_props_before[group2].physicalDevices[dev2]) {
found_count++;
found = true;
break;
}
}
}
ASSERT_EQ(found, found_count == group_props_after[group1].physicalDeviceCount);
}
}
}
for (auto& group : group_props_after) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
// Start with 6 devices in 3 different groups, and then add a device to the middle group,
// querying vkEnumeratePhysicalDeviceGroups before and after the add.
TEST(EnumeratePhysicalDeviceGroups, CallTwiceAddDeviceInBetween) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1);
// Generate the devices
for (size_t i = 0; i < 7; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().properties.apiVersion = VK_API_VERSION_1_1;
}
// Generate the starting groups
driver.physical_device_groups.emplace_back(driver.physical_devices[0]);
driver.physical_device_groups.emplace_back(driver.physical_devices[1]);
driver.physical_device_groups.back()
.use_physical_device(driver.physical_devices[2])
.use_physical_device(driver.physical_devices[3]);
driver.physical_device_groups.emplace_back(driver.physical_devices[4]);
driver.physical_device_groups.back().use_physical_device(driver.physical_devices[5]);
uint32_t expected_group_count = 3;
uint32_t before_expected_counts[3] = {1, 3, 2};
uint32_t after_expected_counts[3] = {1, 4, 2};
uint32_t returned_group_count = 0;
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(1, 1, 0);
inst.CheckCreate();
std::vector<VkPhysicalDeviceGroupProperties> group_props_before{};
group_props_before.resize(expected_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
returned_group_count = expected_group_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_before.data()));
ASSERT_EQ(expected_group_count, returned_group_count);
for (uint32_t group = 0; group < expected_group_count; ++group) {
ASSERT_EQ(group_props_before[group].physicalDeviceCount, before_expected_counts[group]);
}
// Insert new device to 2nd group
driver.physical_device_groups[1].use_physical_device(driver.physical_devices[6]);
std::vector<VkPhysicalDeviceGroupProperties> group_props_after{};
group_props_after.resize(expected_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_after.data()));
ASSERT_EQ(expected_group_count, returned_group_count);
for (uint32_t group = 0; group < expected_group_count; ++group) {
ASSERT_EQ(group_props_after[group].physicalDeviceCount, after_expected_counts[group]);
}
// Make sure all devices in the old group info are still found in the new group info
for (uint32_t group1 = 0; group1 < group_props_before.size(); ++group1) {
for (uint32_t group2 = 0; group2 < group_props_after.size(); ++group2) {
uint32_t found_count = 0;
bool found = false;
for (uint32_t dev1 = 0; dev1 < group_props_before[group1].physicalDeviceCount; ++dev1) {
found = false;
for (uint32_t dev2 = 0; dev2 < group_props_after[group2].physicalDeviceCount; ++dev2) {
if (group_props_before[group1].physicalDevices[dev1] == group_props_after[group2].physicalDevices[dev2]) {
found_count++;
found = true;
break;
}
}
}
ASSERT_EQ(found, found_count != 0 && found_count == before_expected_counts[group1]);
if (found) {
break;
}
}
}
for (auto& group : group_props_after) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
// Start with 6 devices in 3 different groups, and then remove a device to the middle group,
// querying vkEnumeratePhysicalDeviceGroups before and after the remove.
TEST(EnumeratePhysicalDeviceGroups, CallTwiceRemoveDeviceInBetween) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1);
// Generate the devices
for (size_t i = 0; i < 6; i++) {
driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i));
driver.physical_devices.back().properties.apiVersion = VK_API_VERSION_1_1;
}
// Generate the starting groups
driver.physical_device_groups.emplace_back(driver.physical_devices[0]);
driver.physical_device_groups.emplace_back(driver.physical_devices[1]);
driver.physical_device_groups.back()
.use_physical_device(driver.physical_devices[2])
.use_physical_device(driver.physical_devices[3]);
driver.physical_device_groups.emplace_back(driver.physical_devices[4]);
driver.physical_device_groups.back().use_physical_device(driver.physical_devices[5]);
uint32_t before_expected_counts[3] = {1, 3, 2};
uint32_t after_expected_counts[3] = {1, 2, 2};
uint32_t expected_group_count = 3;
uint32_t returned_group_count = 0;
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(1, 1, 0);
inst.CheckCreate();
std::vector<VkPhysicalDeviceGroupProperties> group_props_before{};
group_props_before.resize(expected_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
returned_group_count = expected_group_count;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_before.data()));
ASSERT_EQ(expected_group_count, returned_group_count);
printf("Before:\n");
for (uint32_t group = 0; group < expected_group_count; ++group) {
printf(" Group %u:\n", group);
ASSERT_EQ(group_props_before[group].physicalDeviceCount, before_expected_counts[group]);
for (uint32_t dev = 0; dev < group_props_before[group].physicalDeviceCount; ++dev) {
printf(" Dev %u: %p\n", dev, group_props_before[group].physicalDevices[dev]);
}
}
// Remove middle device in middle group
driver.physical_device_groups[1].physical_device_handles.erase(
driver.physical_device_groups[1].physical_device_handles.begin() + 1);
std::vector<VkPhysicalDeviceGroupProperties> group_props_after{};
group_props_after.resize(expected_group_count,
VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_group_count, group_props_after.data()));
ASSERT_EQ(expected_group_count, returned_group_count);
printf("After:\n");
for (uint32_t group = 0; group < expected_group_count; ++group) {
printf(" Group %u:\n", group);
ASSERT_EQ(group_props_after[group].physicalDeviceCount, after_expected_counts[group]);
for (uint32_t dev = 0; dev < group_props_after[group].physicalDeviceCount; ++dev) {
printf(" Dev %u: %p\n", dev, group_props_after[group].physicalDevices[dev]);
}
}
// Make sure all devices in the new group info are found in the old group info
for (uint32_t group1 = 0; group1 < group_props_after.size(); ++group1) {
for (uint32_t group2 = 0; group2 < group_props_before.size(); ++group2) {
uint32_t found_count = 0;
bool found = false;
for (uint32_t dev1 = 0; dev1 < group_props_after[group1].physicalDeviceCount; ++dev1) {
found = false;
for (uint32_t dev2 = 0; dev2 < group_props_before[group2].physicalDeviceCount; ++dev2) {
if (group_props_after[group1].physicalDevices[dev1] == group_props_before[group2].physicalDevices[dev2]) {
found_count++;
found = true;
break;
}
}
}
ASSERT_EQ(found, found_count != 0 && found_count == after_expected_counts[group1]);
if (found) {
break;
}
}
}
for (auto& group : group_props_after) {
VkDeviceGroupDeviceCreateInfo group_info{};
group_info.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
group_info.physicalDeviceCount = group.physicalDeviceCount;
group_info.pPhysicalDevices = &group.physicalDevices[0];
DeviceWrapper dev{inst};
dev.create_info.dev.pNext = &group_info;
dev.CheckCreate(group.physicalDevices[0]);
}
}
// Start with 9 devices but only some in 3 different groups, add and remove
// various devices and groups while querying in between.
TEST(EnumeratePhysicalDeviceGroups, MultipleAddRemoves) {
FrameworkEnvironment env{};
auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_1))
.set_min_icd_interface_version(5)
.set_icd_api_version(VK_API_VERSION_1_1);
// Generate the devices