From 42efdea97c506694324d1f901e5e2768b5617dcb Mon Sep 17 00:00:00 2001 From: Jozsef Hapak Date: Tue, 12 Aug 2025 12:47:32 +0200 Subject: [PATCH] loader: make it possible to filter the physical devices by vendor, device and / or driver id This change introduces the VK_LOADER_DEVICE_ID_FILTER, VK_LOADER_VENDOR_ID_FILTER and VK_LOADER_DRIVER_ID_FILTER enviroment variables, where a comma separated list of id ranges can be provided to restrict the enumerated physical devices by device, vendor and/or driver id. e.g. VK_LOADER_DEVICE_ID_FILTER or VK_LOADER_VENDOR_ID_FILTER: "0x10001-0x1FFFF,0x1eb1" e.g. VK_LOADER_DRIVER_ID_FILTER: "3,7-9" --- loader/loader.c | 130 ++++++++ loader/loader.h | 14 + loader/loader_common.h | 10 + loader/loader_environment.c | 53 ++++ loader/loader_environment.h | 4 + loader/trampoline.c | 64 +++- loader/vk_loader_platform.h | 4 + tests/framework/icd/test_icd.cpp | 4 + tests/framework/icd/test_icd.h | 1 + tests/framework/test_environment.h | 3 + tests/loader_regression_tests.cpp | 467 +++++++++++++++++++++++++++++ 11 files changed, 751 insertions(+), 3 deletions(-) diff --git a/loader/loader.c b/loader/loader.c index 99daa47ea..c6ace5027 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -7986,3 +7986,133 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups( } return res; } + +VkResult get_device_driver_id(VkPhysicalDevice physicalDevice, VkDriverId *driverId) { + VkPhysicalDeviceDriverProperties physical_device_driver_props = {0}; + physical_device_driver_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; + + VkPhysicalDeviceProperties2 props2 = {0}; + props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + props2.pNext = &physical_device_driver_props; + + struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice; + struct loader_icd_term *icd_term = phys_dev_term->this_icd_term; + const struct loader_instance *inst = icd_term->this_instance; + + assert(inst != NULL); + + // Get the function pointer to use to call into the ICD. This could be the core or KHR version + PFN_vkGetPhysicalDeviceProperties2 fpGetPhysicalDeviceProperties2 = NULL; + if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) { + fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2; + } + if (fpGetPhysicalDeviceProperties2 == NULL && inst->enabled_extensions.khr_get_physical_device_properties2) { + fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2KHR; + } + + if (fpGetPhysicalDeviceProperties2 == NULL) { + *driverId = 0; + return VK_ERROR_UNKNOWN; + } + + fpGetPhysicalDeviceProperties2(phys_dev_term->phys_dev, &props2); + + *driverId = physical_device_driver_props.driverID; + return VK_SUCCESS; +} + +VkResult loader_filter_enumerated_physical_device(const struct loader_instance *inst, + const struct loader_envvar_id_filter *device_id_filter, + const struct loader_envvar_id_filter *vendor_id_filter, + const struct loader_envvar_id_filter *driver_id_filter, + const uint32_t in_PhysicalDeviceCount, + const VkPhysicalDevice *in_pPhysicalDevices, uint32_t *out_pPhysicalDeviceCount, + VkPhysicalDevice *out_pPhysicalDevices) { + uint32_t filtered_physical_device_count = 0; + for (uint32_t i = 0; i < in_PhysicalDeviceCount; i++) { + VkPhysicalDeviceProperties dev_props = {0}; + inst->disp->layer_inst_disp.GetPhysicalDeviceProperties(in_pPhysicalDevices[i], &dev_props); + + if ((0 != device_id_filter->count) && !check_id_matches_filter_environment_var(dev_props.deviceID, device_id_filter)) { + continue; + } + + if ((0 != vendor_id_filter->count) && !check_id_matches_filter_environment_var(dev_props.vendorID, vendor_id_filter)) { + continue; + } + + if (0 != driver_id_filter->count) { + VkDriverId driver_id; + VkResult res = get_device_driver_id(in_pPhysicalDevices[i], &driver_id); + + if ((res != VK_SUCCESS) || !check_id_matches_filter_environment_var(driver_id, driver_id_filter)) { + continue; + } + } + + if ((NULL != out_pPhysicalDevices) && (filtered_physical_device_count < *out_pPhysicalDeviceCount)) { + out_pPhysicalDevices[filtered_physical_device_count] = in_pPhysicalDevices[i]; + } + filtered_physical_device_count++; + } + + if ((NULL == out_pPhysicalDevices) || (filtered_physical_device_count < *out_pPhysicalDeviceCount)) { + *out_pPhysicalDeviceCount = filtered_physical_device_count; + } + + return (*out_pPhysicalDeviceCount < filtered_physical_device_count) ? VK_INCOMPLETE : VK_SUCCESS; +} + +VkResult loader_filter_enumerated_physical_device_groups( + const struct loader_instance *inst, const struct loader_envvar_id_filter *device_id_filter, + const struct loader_envvar_id_filter *vendor_id_filter, const struct loader_envvar_id_filter *driver_id_filter, + const uint32_t in_PhysicalDeviceGroupCount, const VkPhysicalDeviceGroupProperties *in_pPhysicalDeviceGroupProperties, + uint32_t *out_PhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *out_pPhysicalDeviceGroupProperties) { + uint32_t filtered_physical_device_group_count = 0; + for (uint32_t i = 0; i < in_PhysicalDeviceGroupCount; i++) { + const VkPhysicalDeviceGroupProperties *device_group = &in_pPhysicalDeviceGroupProperties[i]; + + bool skip_group = false; + for (uint32_t j = 0; j < device_group->physicalDeviceCount; j++) { + VkPhysicalDeviceProperties dev_props = {0}; + inst->disp->layer_inst_disp.GetPhysicalDeviceProperties(device_group->physicalDevices[j], &dev_props); + + if ((0 != device_id_filter->count) && !check_id_matches_filter_environment_var(dev_props.deviceID, device_id_filter)) { + skip_group = true; + break; + } + + if ((0 != vendor_id_filter->count) && !check_id_matches_filter_environment_var(dev_props.vendorID, vendor_id_filter)) { + skip_group = true; + break; + } + + if (0 != driver_id_filter->count) { + VkDriverId driver_id; + VkResult res = get_device_driver_id(device_group->physicalDevices[j], &driver_id); + + if ((res != VK_SUCCESS) || !check_id_matches_filter_environment_var(driver_id, driver_id_filter)) { + skip_group = true; + break; + } + } + } + + if (skip_group) { + continue; + } + + if ((NULL != out_pPhysicalDeviceGroupProperties) && + (filtered_physical_device_group_count < *out_PhysicalDeviceGroupCount)) { + out_pPhysicalDeviceGroupProperties[filtered_physical_device_group_count] = *device_group; + } + + filtered_physical_device_group_count++; + } + + if ((NULL == out_pPhysicalDeviceGroupProperties) || (filtered_physical_device_group_count < *out_PhysicalDeviceGroupCount)) { + *out_PhysicalDeviceGroupCount = filtered_physical_device_group_count; + } + + return (*out_PhysicalDeviceGroupCount < filtered_physical_device_group_count) ? VK_INCOMPLETE : VK_SUCCESS; +} diff --git a/loader/loader.h b/loader/loader.h index 2ed309c0e..04eee0246 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -237,6 +237,20 @@ loader_api_version loader_combine_version(uint32_t major, uint32_t minor, uint32 // Helper macros for determining if a version is valid or not bool loader_check_version_meets_required(loader_api_version required, loader_api_version version); +VkResult loader_filter_enumerated_physical_device(const struct loader_instance *inst, + const struct loader_envvar_id_filter *device_id_filter, + const struct loader_envvar_id_filter *vendor_id_filter, + const struct loader_envvar_id_filter *driver_id_filter, + const uint32_t in_PhysicalDeviceCount, + const VkPhysicalDevice *in_pPhysicalDevices, uint32_t *out_pPhysicalDeviceCount, + VkPhysicalDevice *out_pPhysicalDevices); + +VkResult loader_filter_enumerated_physical_device_groups( + const struct loader_instance *inst, const struct loader_envvar_id_filter *device_id_filter, + const struct loader_envvar_id_filter *vendor_id_filter, const struct loader_envvar_id_filter *driver_id_filter, + const uint32_t in_PhysicalDeviceGroupCount, const VkPhysicalDeviceGroupProperties *in_pPhysicalDeviceGroupProperties, + uint32_t *out_PhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *out_pPhysicalDeviceGroupProperties); + // Convenience macros for common versions #if !defined(LOADER_VERSION_1_0_0) #define LOADER_VERSION_1_0_0 loader_combine_version(1, 0, 0) diff --git a/loader/loader_common.h b/loader/loader_common.h index 865c2ccee..45baa79e9 100644 --- a/loader/loader_common.h +++ b/loader/loader_common.h @@ -521,3 +521,13 @@ struct loader_envvar_all_filters { struct loader_envvar_disable_layers_filter disable_filter; struct loader_envvar_filter allow_filter; }; + +struct loader_envvar_id_filter_value { + uint32_t begin; + uint32_t end; +}; + +struct loader_envvar_id_filter { + uint32_t count; + struct loader_envvar_id_filter_value filters[MAX_ADDITIONAL_FILTERS]; +}; diff --git a/loader/loader_environment.c b/loader/loader_environment.c index 6489efac8..77593a9d3 100644 --- a/loader/loader_environment.c +++ b/loader/loader_environment.c @@ -566,3 +566,56 @@ VkResult loader_add_environment_layers(struct loader_instance *inst, const enum return res; } + +void parse_id_filter_enviroment_var(const struct loader_instance *inst, const char *env_var_name, + struct loader_envvar_id_filter *filter_struct) { + memset(filter_struct, 0, sizeof(struct loader_envvar_id_filter)); + char *parsing_string = NULL; + char *env_var_value = loader_secure_getenv(env_var_name, inst); + if (NULL == env_var_value) { + return; + } + const size_t env_var_len = strlen(env_var_value); + if (env_var_len == 0) { + goto out; + } + // Allocate a separate string since scan_for_next_comma modifies the original string + parsing_string = loader_stack_alloc(env_var_len + 1); + for (uint32_t iii = 0; iii < env_var_len; ++iii) { + parsing_string[iii] = (char)tolower(env_var_value[iii]); + } + parsing_string[env_var_len] = '\0'; + + filter_struct->count = 0; + char *context = NULL; + char *token = thread_safe_strtok(parsing_string, ",", &context); + while (NULL != token) { + struct loader_envvar_id_filter_value *filter_value = &filter_struct->filters[filter_struct->count]; + + char *pEnd; + filter_value->begin = (uint32_t)strtoul(token, &pEnd, 0); + + if (*pEnd != '\0') { + pEnd++; + filter_value->end = (uint32_t)strtoul(pEnd, NULL, 0); + } else { + filter_value->end = filter_value->begin; + } + + filter_struct->count++; + token = thread_safe_strtok(NULL, ",", &context); + } + +out: + + loader_free_getenv(env_var_value, inst); +} + +bool check_id_matches_filter_environment_var(const uint32_t id, const struct loader_envvar_id_filter *filter_struct) { + for (uint32_t i = 0; i < filter_struct->count; i++) { + if ((filter_struct->filters[i].begin <= id) && (id <= filter_struct->filters[i].end)) { + return true; + } + } + return false; +} diff --git a/loader/loader_environment.h b/loader/loader_environment.h index d120ec95c..da35237b5 100644 --- a/loader/loader_environment.h +++ b/loader/loader_environment.h @@ -54,3 +54,7 @@ VkResult loader_add_environment_layers(struct loader_instance *inst, const enum struct loader_pointer_layer_list *target_list, struct loader_pointer_layer_list *expanded_target_list, const struct loader_layer_list *source_list); + +void parse_id_filter_enviroment_var(const struct loader_instance *inst, const char *env_var_name, + struct loader_envvar_id_filter *filter_struct); +bool check_id_matches_filter_environment_var(const uint32_t id, const struct loader_envvar_id_filter *filter_struct); diff --git a/loader/trampoline.c b/loader/trampoline.c index 0ebb4c172..73e55ef64 100644 --- a/loader/trampoline.c +++ b/loader/trampoline.c @@ -36,6 +36,7 @@ #include "loader_environment.h" #include "log.h" #include "settings.h" +#include "stack_allocation.h" #include "vk_loader_extensions.h" #include "vk_loader_platform.h" #include "wsi.h" @@ -852,8 +853,34 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstan goto out; } + struct loader_envvar_id_filter device_id_filter; + struct loader_envvar_id_filter vendor_id_filter; + struct loader_envvar_id_filter driver_id_filter; + + parse_id_filter_enviroment_var(inst, VK_DEVICE_ID_FILTER_ENV_VAR, &device_id_filter); + parse_id_filter_enviroment_var(inst, VK_VENDOR_ID_FILTER_ENV_VAR, &vendor_id_filter); + parse_id_filter_enviroment_var(inst, VK_DRIVER_ID_FILTER_ENV_VAR, &driver_id_filter); + // Call down the chain to get the physical device info - res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, pPhysicalDeviceCount, pPhysicalDevices); + if ((0 == device_id_filter.count) && (0 == vendor_id_filter.count) && (0 == driver_id_filter.count)) { + res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, pPhysicalDeviceCount, pPhysicalDevices); + } else { + uint32_t physical_device_count = 0; + res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, &physical_device_count, NULL); + if (res != VK_SUCCESS) { + goto out; + } + + VkPhysicalDevice *physical_devices = loader_stack_alloc(physical_device_count * sizeof(VkPhysicalDevice)); + res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, &physical_device_count, physical_devices); + if (res != VK_SUCCESS) { + goto out; + } + + res = loader_filter_enumerated_physical_device(inst, &device_id_filter, &vendor_id_filter, &driver_id_filter, + physical_device_count, physical_devices, pPhysicalDeviceCount, + pPhysicalDevices); + } if (NULL != pPhysicalDevices && (VK_SUCCESS == res || VK_INCOMPLETE == res)) { // Wrap the PhysDev object for loader usage, return wrapped objects @@ -2586,9 +2613,40 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( goto out; } + struct loader_envvar_id_filter device_id_filter; + struct loader_envvar_id_filter vendor_id_filter; + struct loader_envvar_id_filter driver_id_filter; + + parse_id_filter_enviroment_var(inst, VK_DEVICE_ID_FILTER_ENV_VAR, &device_id_filter); + parse_id_filter_enviroment_var(inst, VK_VENDOR_ID_FILTER_ENV_VAR, &vendor_id_filter); + parse_id_filter_enviroment_var(inst, VK_DRIVER_ID_FILTER_ENV_VAR, &driver_id_filter); + // Call down the chain to get the physical device group info. - res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, pPhysicalDeviceGroupCount, - pPhysicalDeviceGroupProperties); + if ((0 == device_id_filter.count) && (0 == vendor_id_filter.count) && (0 == driver_id_filter.count)) { + res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, pPhysicalDeviceGroupCount, + pPhysicalDeviceGroupProperties); + } else { + uint32_t physical_device_group_count = 0; + res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, &physical_device_group_count, NULL); + if (res != VK_SUCCESS) { + goto out; + } + + VkPhysicalDeviceGroupProperties *physical_device_group_properties = + loader_stack_alloc(physical_device_group_count * sizeof(VkPhysicalDeviceGroupProperties)); + memset(physical_device_group_properties, 0, physical_device_group_count * sizeof(VkPhysicalDeviceGroupProperties)); + + res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, &physical_device_group_count, + physical_device_group_properties); + if (res != VK_SUCCESS) { + goto out; + } + + res = loader_filter_enumerated_physical_device_groups(inst, &device_id_filter, &vendor_id_filter, &driver_id_filter, + physical_device_group_count, physical_device_group_properties, + pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); + } + if (NULL != pPhysicalDeviceGroupProperties && (VK_SUCCESS == res || VK_INCOMPLETE == res)) { // Wrap the PhysDev object for loader usage, return wrapped objects VkResult update_res = setup_loader_tramp_phys_dev_groups(inst, *pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h index 272f6f8ec..987337c93 100644 --- a/loader/vk_loader_platform.h +++ b/loader/vk_loader_platform.h @@ -130,6 +130,10 @@ #define VK_IMPLICIT_LAYER_PATH_ENV_VAR "VK_IMPLICIT_LAYER_PATH" #define VK_ADDITIONAL_IMPLICIT_LAYER_PATH_ENV_VAR "VK_ADD_IMPLICIT_LAYER_PATH" +#define VK_DEVICE_ID_FILTER_ENV_VAR "VK_LOADER_DEVICE_ID_FILTER" +#define VK_VENDOR_ID_FILTER_ENV_VAR "VK_LOADER_VENDOR_ID_FILTER" +#define VK_DRIVER_ID_FILTER_ENV_VAR "VK_LOADER_DRIVER_ID_FILTER" + // Override layer information #define VK_OVERRIDE_LAYER_NAME "VK_LAYER_LUNARG_override" diff --git a/tests/framework/icd/test_icd.cpp b/tests/framework/icd/test_icd.cpp index 01bf1dd36..466293a55 100644 --- a/tests/framework/icd/test_icd.cpp +++ b/tests/framework/icd/test_icd.cpp @@ -1232,6 +1232,10 @@ VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceProperties2(VkPhysicalDevice auto* vulkan_11_props = reinterpret_cast(pNext); memcpy(vulkan_11_props->deviceUUID, phys_dev.deviceUUID.data(), VK_UUID_SIZE); } + if (pNext->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES) { + auto* device_driver_props = reinterpret_cast(pNext); + *device_driver_props = phys_dev.driver_properties; + } pNext = reinterpret_cast(const_cast(pNext->pNext)); } } diff --git a/tests/framework/icd/test_icd.h b/tests/framework/icd/test_icd.h index d84f4f8a3..24309f410 100644 --- a/tests/framework/icd/test_icd.h +++ b/tests/framework/icd/test_icd.h @@ -94,6 +94,7 @@ struct PhysicalDevice { BUILDER_VALUE(VkPhysicalDeviceProperties, properties) BUILDER_VALUE(VkPhysicalDeviceFeatures, features) BUILDER_VALUE(VkPhysicalDeviceMemoryProperties, memory_properties) + BUILDER_VALUE(VkPhysicalDeviceDriverProperties, driver_properties) BUILDER_VALUE(VkImageFormatProperties, image_format_properties) BUILDER_VALUE(VkExternalMemoryProperties, external_memory_properties) BUILDER_VALUE(VkExternalSemaphoreProperties, external_semaphore_properties) diff --git a/tests/framework/test_environment.h b/tests/framework/test_environment.h index 0a1f89e0d..678e88e99 100644 --- a/tests/framework/test_environment.h +++ b/tests/framework/test_environment.h @@ -561,6 +561,9 @@ struct FrameworkEnvironment { EnvVarWrapper add_env_var_vk_layer_paths{"VK_ADD_LAYER_PATH"}; EnvVarWrapper env_var_vk_implicit_layer_paths{"VK_IMPLICIT_LAYER_PATH"}; EnvVarWrapper add_env_var_vk_implicit_layer_paths{"VK_ADD_IMPLICIT_LAYER_PATH"}; + EnvVarWrapper env_var_vk_loader_device_id_filter{"VK_LOADER_DEVICE_ID_FILTER"}; + EnvVarWrapper env_var_vk_loader_vendor_id_filter{"VK_LOADER_VENDOR_ID_FILTER"}; + EnvVarWrapper env_var_vk_loader_driver_id_filter{"VK_LOADER_DRIVER_ID_FILTER"}; #if TESTING_COMMON_UNIX_PLATFORMS EnvVarWrapper env_var_home{"HOME", "/home/fake_home"}; diff --git a/tests/loader_regression_tests.cpp b/tests/loader_regression_tests.cpp index dab31af3d..cae8c211b 100644 --- a/tests/loader_regression_tests.cpp +++ b/tests/loader_regression_tests.cpp @@ -1223,6 +1223,213 @@ TEST(EnumeratePhysicalDevices, TwoDriversOneWithWrongErrorCodes) { } } +TEST(EnumeratePhysicalDevices, DeviceFiltering) { + FrameworkEnvironment env{}; + auto& driver = env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).set_min_icd_interface_version(5); + + for (uint32_t i = 0; i < 10; i++) { + auto& physical_device = driver.add_and_get_physical_device("physical_device_" + std::to_string(i)); + physical_device.properties.deviceID = 0x1000 + i; + physical_device.properties.vendorID = 0x2000 + i; + } + + InstWrapper inst{env.vulkan_functions}; + inst.CheckCreate(); + + uint32_t physical_count = static_cast(driver.physical_devices.size()); + + // filter multiple device by device id + { + env.env_var_vk_loader_device_id_filter.set_new_value("0x1001-0x1003,0x1006"); + + uint32_t returned_physical_count = static_cast(driver.physical_devices.size()); + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(4, returned_physical_count); + + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // filter multiple device by vendor id + { + env.env_var_vk_loader_vendor_id_filter.set_new_value("0x2001-0x2003,0x2006"); + + uint32_t returned_physical_count = static_cast(driver.physical_devices.size()); + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(4, returned_physical_count); + + env.env_var_vk_loader_vendor_id_filter.remove_value(); + } + + // filter multiple device by vendor id and device id + { + env.env_var_vk_loader_device_id_filter.set_new_value("0x1002-0x1004"); + env.env_var_vk_loader_vendor_id_filter.set_new_value("0x2003-0x2007"); + + uint32_t returned_physical_count = static_cast(driver.physical_devices.size()); + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(2, returned_physical_count); + + env.env_var_vk_loader_vendor_id_filter.remove_value(); + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // return value change by device filter + { + uint32_t returned_physical_count = 5; + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(5, returned_physical_count); + + env.env_var_vk_loader_device_id_filter.set_new_value("0x1003-0x1004"); + + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(2, returned_physical_count); + + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // return value change by vendor filter + { + uint32_t returned_physical_count = 5; + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(5, returned_physical_count); + + env.env_var_vk_loader_vendor_id_filter.set_new_value("0x2005-0x2006"); + + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(2, returned_physical_count); + + env.env_var_vk_loader_vendor_id_filter.remove_value(); + } + + // incomplete result with device filter + { + env.env_var_vk_loader_device_id_filter.set_new_value("0x1001-0x1006"); + + uint32_t returned_physical_count = 3; + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(3, returned_physical_count); + + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // filter all device + { + env.env_var_vk_loader_device_id_filter.set_new_value("0x2002-0x2003"); + + uint32_t returned_physical_count = static_cast(driver.physical_devices.size()); + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(0, returned_physical_count); + + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // no device filtering + { + env.env_var_vk_loader_vendor_id_filter.remove_value(); + env.env_var_vk_loader_device_id_filter.remove_value(); + + uint32_t returned_physical_count = static_cast(driver.physical_devices.size()); + std::vector physical_device_handles = std::vector(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, DeviceFilteringByDriverId) { + 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}); + + for (uint32_t i = 0; i < 10; i++) { + auto& physical_device = driver.add_and_get_physical_device("physical_device_" + std::to_string(i)); + physical_device.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0}); + physical_device.driver_properties.driverID = VkDriverId(100 + i); + } + + InstWrapper inst{env.vulkan_functions}; + inst.create_info.set_api_version(VK_API_VERSION_1_1); + inst.CheckCreate(); + + uint32_t physical_count = static_cast(driver.physical_devices.size()); + + // filter multiple device by driver id + { + env.env_var_vk_loader_driver_id_filter.set_new_value("103-105,107"); + + uint32_t returned_physical_count = static_cast(driver.physical_devices.size()); + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(4, returned_physical_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } + + // return value change by driver filter + { + uint32_t returned_physical_count = 5; + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(5, returned_physical_count); + + env.env_var_vk_loader_driver_id_filter.set_new_value("103-104"); + + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(2, returned_physical_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } + + // incomplete result with driver filter + { + env.env_var_vk_loader_driver_id_filter.set_new_value("102-105"); + + uint32_t returned_physical_count = 3; + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(3, returned_physical_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } + + // filter all device + { + env.env_var_vk_loader_driver_id_filter.set_new_value("50"); + + uint32_t returned_physical_count = static_cast(driver.physical_devices.size()); + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(0, returned_physical_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } + + InstWrapper inst_1_0{env.vulkan_functions}; + inst_1_0.create_info.set_api_version(VK_API_VERSION_1_0); + inst_1_0.CheckCreate(); + + // Unsupported device filtering by driver id + { + env.env_var_vk_loader_driver_id_filter.set_new_value("103-105,107"); + + uint32_t returned_physical_count = static_cast(driver.physical_devices.size()); + std::vector physical_device_handles = std::vector(physical_count); + ASSERT_EQ(VK_SUCCESS, + inst_1_0->vkEnumeratePhysicalDevices(inst_1_0, &returned_physical_count, physical_device_handles.data())); + ASSERT_EQ(0, returned_physical_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } +} + TEST(CreateDevice, ExtensionNotPresent) { FrameworkEnvironment env{}; env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0"); @@ -2706,6 +2913,266 @@ TEST(EnumeratePhysicalDeviceGroups, FakePNext) { } } +TEST(EnumeratePhysicalDeviceGroups, DeviceFiltering) { + 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 10 devices in 5 groups + std::array phys_devices; + for (size_t i = 0; i < phys_devices.size(); i++) { + auto& physical_device = driver.add_and_get_physical_device(std::string("physical_device_") + std::to_string(i)); + physical_device.properties.apiVersion = VK_API_VERSION_1_1; + + physical_device.properties.deviceID = 0x1000 + i; + physical_device.properties.vendorID = 0x2000 + i; + + phys_devices[i] = &physical_device; + } + + for (size_t i = 0; i < 5; i++) { + driver.physical_device_groups.emplace_back(phys_devices[2 * i]); + driver.physical_device_groups.back().use_physical_device(phys_devices[2 * i + 1]); + } + + InstWrapper inst{env.vulkan_functions}; + inst.CheckCreate(); + + uint32_t physical_device_group_count = static_cast(driver.physical_device_groups.size()); + + // filter multiple device by device id + { + env.env_var_vk_loader_device_id_filter.set_new_value("0x1000-0x1002,0x1006-0x1010"); + + uint32_t returned_physical_device_group_count = static_cast(driver.physical_device_groups.size()); + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_device_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(3, returned_physical_device_group_count); + + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // filter multiple device by vendor id + { + env.env_var_vk_loader_vendor_id_filter.set_new_value("0x200-0x2002,0x2006-0x2010"); + + uint32_t returned_physical_device_group_count = static_cast(driver.physical_device_groups.size()); + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_device_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(3, returned_physical_device_group_count); + + env.env_var_vk_loader_vendor_id_filter.remove_value(); + } + + // filter multiple device by vendor id and device id + { + env.env_var_vk_loader_device_id_filter.set_new_value("0x1000-0x1007"); + env.env_var_vk_loader_vendor_id_filter.set_new_value("0x2004-0x2009"); + + uint32_t returned_physical_device_group_count = static_cast(driver.physical_device_groups.size()); + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_device_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(2, returned_physical_device_group_count); + + env.env_var_vk_loader_vendor_id_filter.remove_value(); + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // return value change by device filter + { + uint32_t returned_physical_group_count = 3; + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(3, returned_physical_group_count); + + env.env_var_vk_loader_device_id_filter.set_new_value("0x1000-0x1001,0x1004-0x1005"); + + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(2, returned_physical_group_count); + + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // return value change by vendor filter + { + uint32_t returned_physical_group_count = 3; + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(3, returned_physical_group_count); + + env.env_var_vk_loader_vendor_id_filter.set_new_value("0x2002-0x2005"); + + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(2, returned_physical_group_count); + + env.env_var_vk_loader_vendor_id_filter.remove_value(); + } + + // incomplete result with device filter + { + env.env_var_vk_loader_device_id_filter.set_new_value("0x1000-0x1007"); + + uint32_t returned_physical_group_count = 2; + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(2, returned_physical_group_count); + + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // filter all device + { + env.env_var_vk_loader_device_id_filter.set_new_value("0x2002-0x2003"); + + uint32_t returned_physical_group_count = static_cast(driver.physical_device_groups.size()); + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(0, returned_physical_group_count); + + env.env_var_vk_loader_device_id_filter.remove_value(); + } + + // no device filtering + { + env.env_var_vk_loader_vendor_id_filter.remove_value(); + env.env_var_vk_loader_device_id_filter.remove_value(); + + uint32_t returned_physical_group_count = static_cast(driver.physical_device_groups.size()); + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(physical_device_group_count, returned_physical_group_count); + } +} + +TEST(EnumeratePhysicalDeviceGroups, DeviceFilteringByDriverId) { + 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 10 devices in 5 groups + std::array phys_devices; + for (size_t i = 0; i < phys_devices.size(); i++) { + auto& physical_device = driver.add_and_get_physical_device(std::string("physical_device_") + std::to_string(i)); + physical_device.properties.apiVersion = VK_API_VERSION_1_1; + + physical_device.extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0}); + physical_device.driver_properties.driverID = VkDriverId(100 + i); + + phys_devices[i] = &physical_device; + } + + for (size_t i = 0; i < 5; i++) { + driver.physical_device_groups.emplace_back(phys_devices[2 * i]); + driver.physical_device_groups.back().use_physical_device(phys_devices[2 * i + 1]); + } + + InstWrapper inst{env.vulkan_functions}; + inst.create_info.set_api_version(VK_API_VERSION_1_1); + inst.CheckCreate(); + + uint32_t physical_device_group_count = static_cast(driver.physical_device_groups.size()); + + // filter multiple device by device id + { + env.env_var_vk_loader_driver_id_filter.set_new_value("102-105,108-109"); + + uint32_t returned_physical_device_group_count = static_cast(driver.physical_device_groups.size()); + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_device_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(3, returned_physical_device_group_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } + + // return value change by driver filter + { + uint32_t returned_physical_group_count = 3; + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(3, returned_physical_group_count); + + env.env_var_vk_loader_driver_id_filter.set_new_value("102-103,106-107"); + + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(2, returned_physical_group_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } + + // incomplete result with driver filter + { + env.env_var_vk_loader_driver_id_filter.set_new_value("102-109"); + + uint32_t returned_physical_group_count = 2; + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_INCOMPLETE, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(2, returned_physical_group_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } + + // filter all device + { + env.env_var_vk_loader_driver_id_filter.set_new_value("50"); + + uint32_t returned_physical_group_count = static_cast(driver.physical_device_groups.size()); + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &returned_physical_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(0, returned_physical_group_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } + + InstWrapper inst_1_0{env.vulkan_functions}; + inst_1_0.create_info.set_api_version(VK_API_VERSION_1_0); + inst_1_0.CheckCreate(); + + // Unsupported device filtering by driver id + { + env.env_var_vk_loader_driver_id_filter.set_new_value("102-105,108-109"); + + uint32_t returned_physical_device_group_count = static_cast(driver.physical_device_groups.size()); + std::vector physical_device_group_properties = + std::vector(physical_device_group_count); + ASSERT_EQ(VK_SUCCESS, inst_1_0->vkEnumeratePhysicalDeviceGroups(inst_1_0, &returned_physical_device_group_count, + physical_device_group_properties.data())); + ASSERT_EQ(0, returned_physical_device_group_count); + + env.env_var_vk_loader_driver_id_filter.remove_value(); + } +} + TEST(ExtensionManual, ToolingProperties) { VkPhysicalDeviceToolPropertiesEXT icd_tool_props{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT, nullptr,