Skip to content

Commit eae3da9

Browse files
hapakjcharles-lunarg
authored andcommitted
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"
1 parent be3fe40 commit eae3da9

File tree

11 files changed

+751
-3
lines changed

11 files changed

+751
-3
lines changed

loader/loader.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7986,3 +7986,133 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
79867986
}
79877987
return res;
79887988
}
7989+
7990+
VkResult get_device_driver_id(VkPhysicalDevice physicalDevice, VkDriverId *driverId) {
7991+
VkPhysicalDeviceDriverProperties physical_device_driver_props = {0};
7992+
physical_device_driver_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
7993+
7994+
VkPhysicalDeviceProperties2 props2 = {0};
7995+
props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
7996+
props2.pNext = &physical_device_driver_props;
7997+
7998+
struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
7999+
struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
8000+
const struct loader_instance *inst = icd_term->this_instance;
8001+
8002+
assert(inst != NULL);
8003+
8004+
// Get the function pointer to use to call into the ICD. This could be the core or KHR version
8005+
PFN_vkGetPhysicalDeviceProperties2 fpGetPhysicalDeviceProperties2 = NULL;
8006+
if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
8007+
fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2;
8008+
}
8009+
if (fpGetPhysicalDeviceProperties2 == NULL && inst->enabled_extensions.khr_get_physical_device_properties2) {
8010+
fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2KHR;
8011+
}
8012+
8013+
if (fpGetPhysicalDeviceProperties2 == NULL) {
8014+
*driverId = 0;
8015+
return VK_ERROR_UNKNOWN;
8016+
}
8017+
8018+
fpGetPhysicalDeviceProperties2(phys_dev_term->phys_dev, &props2);
8019+
8020+
*driverId = physical_device_driver_props.driverID;
8021+
return VK_SUCCESS;
8022+
}
8023+
8024+
VkResult loader_filter_enumerated_physical_device(const struct loader_instance *inst,
8025+
const struct loader_envvar_id_filter *device_id_filter,
8026+
const struct loader_envvar_id_filter *vendor_id_filter,
8027+
const struct loader_envvar_id_filter *driver_id_filter,
8028+
const uint32_t in_PhysicalDeviceCount,
8029+
const VkPhysicalDevice *in_pPhysicalDevices, uint32_t *out_pPhysicalDeviceCount,
8030+
VkPhysicalDevice *out_pPhysicalDevices) {
8031+
uint32_t filtered_physical_device_count = 0;
8032+
for (uint32_t i = 0; i < in_PhysicalDeviceCount; i++) {
8033+
VkPhysicalDeviceProperties dev_props = {0};
8034+
inst->disp->layer_inst_disp.GetPhysicalDeviceProperties(in_pPhysicalDevices[i], &dev_props);
8035+
8036+
if ((0 != device_id_filter->count) && !check_id_matches_filter_environment_var(dev_props.deviceID, device_id_filter)) {
8037+
continue;
8038+
}
8039+
8040+
if ((0 != vendor_id_filter->count) && !check_id_matches_filter_environment_var(dev_props.vendorID, vendor_id_filter)) {
8041+
continue;
8042+
}
8043+
8044+
if (0 != driver_id_filter->count) {
8045+
VkDriverId driver_id;
8046+
VkResult res = get_device_driver_id(in_pPhysicalDevices[i], &driver_id);
8047+
8048+
if ((res != VK_SUCCESS) || !check_id_matches_filter_environment_var(driver_id, driver_id_filter)) {
8049+
continue;
8050+
}
8051+
}
8052+
8053+
if ((NULL != out_pPhysicalDevices) && (filtered_physical_device_count < *out_pPhysicalDeviceCount)) {
8054+
out_pPhysicalDevices[filtered_physical_device_count] = in_pPhysicalDevices[i];
8055+
}
8056+
filtered_physical_device_count++;
8057+
}
8058+
8059+
if ((NULL == out_pPhysicalDevices) || (filtered_physical_device_count < *out_pPhysicalDeviceCount)) {
8060+
*out_pPhysicalDeviceCount = filtered_physical_device_count;
8061+
}
8062+
8063+
return (*out_pPhysicalDeviceCount < filtered_physical_device_count) ? VK_INCOMPLETE : VK_SUCCESS;
8064+
}
8065+
8066+
VkResult loader_filter_enumerated_physical_device_groups(
8067+
const struct loader_instance *inst, const struct loader_envvar_id_filter *device_id_filter,
8068+
const struct loader_envvar_id_filter *vendor_id_filter, const struct loader_envvar_id_filter *driver_id_filter,
8069+
const uint32_t in_PhysicalDeviceGroupCount, const VkPhysicalDeviceGroupProperties *in_pPhysicalDeviceGroupProperties,
8070+
uint32_t *out_PhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *out_pPhysicalDeviceGroupProperties) {
8071+
uint32_t filtered_physical_device_group_count = 0;
8072+
for (uint32_t i = 0; i < in_PhysicalDeviceGroupCount; i++) {
8073+
const VkPhysicalDeviceGroupProperties *device_group = &in_pPhysicalDeviceGroupProperties[i];
8074+
8075+
bool skip_group = false;
8076+
for (uint32_t j = 0; j < device_group->physicalDeviceCount; j++) {
8077+
VkPhysicalDeviceProperties dev_props = {0};
8078+
inst->disp->layer_inst_disp.GetPhysicalDeviceProperties(device_group->physicalDevices[j], &dev_props);
8079+
8080+
if ((0 != device_id_filter->count) && !check_id_matches_filter_environment_var(dev_props.deviceID, device_id_filter)) {
8081+
skip_group = true;
8082+
break;
8083+
}
8084+
8085+
if ((0 != vendor_id_filter->count) && !check_id_matches_filter_environment_var(dev_props.vendorID, vendor_id_filter)) {
8086+
skip_group = true;
8087+
break;
8088+
}
8089+
8090+
if (0 != driver_id_filter->count) {
8091+
VkDriverId driver_id;
8092+
VkResult res = get_device_driver_id(device_group->physicalDevices[j], &driver_id);
8093+
8094+
if ((res != VK_SUCCESS) || !check_id_matches_filter_environment_var(driver_id, driver_id_filter)) {
8095+
skip_group = true;
8096+
break;
8097+
}
8098+
}
8099+
}
8100+
8101+
if (skip_group) {
8102+
continue;
8103+
}
8104+
8105+
if ((NULL != out_pPhysicalDeviceGroupProperties) &&
8106+
(filtered_physical_device_group_count < *out_PhysicalDeviceGroupCount)) {
8107+
out_pPhysicalDeviceGroupProperties[filtered_physical_device_group_count] = *device_group;
8108+
}
8109+
8110+
filtered_physical_device_group_count++;
8111+
}
8112+
8113+
if ((NULL == out_pPhysicalDeviceGroupProperties) || (filtered_physical_device_group_count < *out_PhysicalDeviceGroupCount)) {
8114+
*out_PhysicalDeviceGroupCount = filtered_physical_device_group_count;
8115+
}
8116+
8117+
return (*out_PhysicalDeviceGroupCount < filtered_physical_device_group_count) ? VK_INCOMPLETE : VK_SUCCESS;
8118+
}

loader/loader.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,20 @@ loader_api_version loader_combine_version(uint32_t major, uint32_t minor, uint32
237237
// Helper macros for determining if a version is valid or not
238238
bool loader_check_version_meets_required(loader_api_version required, loader_api_version version);
239239

240+
VkResult loader_filter_enumerated_physical_device(const struct loader_instance *inst,
241+
const struct loader_envvar_id_filter *device_id_filter,
242+
const struct loader_envvar_id_filter *vendor_id_filter,
243+
const struct loader_envvar_id_filter *driver_id_filter,
244+
const uint32_t in_PhysicalDeviceCount,
245+
const VkPhysicalDevice *in_pPhysicalDevices, uint32_t *out_pPhysicalDeviceCount,
246+
VkPhysicalDevice *out_pPhysicalDevices);
247+
248+
VkResult loader_filter_enumerated_physical_device_groups(
249+
const struct loader_instance *inst, const struct loader_envvar_id_filter *device_id_filter,
250+
const struct loader_envvar_id_filter *vendor_id_filter, const struct loader_envvar_id_filter *driver_id_filter,
251+
const uint32_t in_PhysicalDeviceGroupCount, const VkPhysicalDeviceGroupProperties *in_pPhysicalDeviceGroupProperties,
252+
uint32_t *out_PhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *out_pPhysicalDeviceGroupProperties);
253+
240254
// Convenience macros for common versions
241255
#if !defined(LOADER_VERSION_1_0_0)
242256
#define LOADER_VERSION_1_0_0 loader_combine_version(1, 0, 0)

loader/loader_common.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,3 +521,13 @@ struct loader_envvar_all_filters {
521521
struct loader_envvar_disable_layers_filter disable_filter;
522522
struct loader_envvar_filter allow_filter;
523523
};
524+
525+
struct loader_envvar_id_filter_value {
526+
uint32_t begin;
527+
uint32_t end;
528+
};
529+
530+
struct loader_envvar_id_filter {
531+
uint32_t count;
532+
struct loader_envvar_id_filter_value filters[MAX_ADDITIONAL_FILTERS];
533+
};

loader/loader_environment.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,3 +566,56 @@ VkResult loader_add_environment_layers(struct loader_instance *inst, const enum
566566

567567
return res;
568568
}
569+
570+
void parse_id_filter_enviroment_var(const struct loader_instance *inst, const char *env_var_name,
571+
struct loader_envvar_id_filter *filter_struct) {
572+
memset(filter_struct, 0, sizeof(struct loader_envvar_id_filter));
573+
char *parsing_string = NULL;
574+
char *env_var_value = loader_secure_getenv(env_var_name, inst);
575+
if (NULL == env_var_value) {
576+
return;
577+
}
578+
const size_t env_var_len = strlen(env_var_value);
579+
if (env_var_len == 0) {
580+
goto out;
581+
}
582+
// Allocate a separate string since scan_for_next_comma modifies the original string
583+
parsing_string = loader_stack_alloc(env_var_len + 1);
584+
for (uint32_t iii = 0; iii < env_var_len; ++iii) {
585+
parsing_string[iii] = (char)tolower(env_var_value[iii]);
586+
}
587+
parsing_string[env_var_len] = '\0';
588+
589+
filter_struct->count = 0;
590+
char *context = NULL;
591+
char *token = thread_safe_strtok(parsing_string, ",", &context);
592+
while (NULL != token) {
593+
struct loader_envvar_id_filter_value *filter_value = &filter_struct->filters[filter_struct->count];
594+
595+
char *pEnd;
596+
filter_value->begin = (uint32_t)strtoul(token, &pEnd, 0);
597+
598+
if (*pEnd != '\0') {
599+
pEnd++;
600+
filter_value->end = (uint32_t)strtoul(pEnd, NULL, 0);
601+
} else {
602+
filter_value->end = filter_value->begin;
603+
}
604+
605+
filter_struct->count++;
606+
token = thread_safe_strtok(NULL, ",", &context);
607+
}
608+
609+
out:
610+
611+
loader_free_getenv(env_var_value, inst);
612+
}
613+
614+
bool check_id_matches_filter_environment_var(const uint32_t id, const struct loader_envvar_id_filter *filter_struct) {
615+
for (uint32_t i = 0; i < filter_struct->count; i++) {
616+
if ((filter_struct->filters[i].begin <= id) && (id <= filter_struct->filters[i].end)) {
617+
return true;
618+
}
619+
}
620+
return false;
621+
}

loader/loader_environment.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,7 @@ VkResult loader_add_environment_layers(struct loader_instance *inst, const enum
5454
struct loader_pointer_layer_list *target_list,
5555
struct loader_pointer_layer_list *expanded_target_list,
5656
const struct loader_layer_list *source_list);
57+
58+
void parse_id_filter_enviroment_var(const struct loader_instance *inst, const char *env_var_name,
59+
struct loader_envvar_id_filter *filter_struct);
60+
bool check_id_matches_filter_environment_var(const uint32_t id, const struct loader_envvar_id_filter *filter_struct);

loader/trampoline.c

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "loader_environment.h"
3737
#include "log.h"
3838
#include "settings.h"
39+
#include "stack_allocation.h"
3940
#include "vk_loader_extensions.h"
4041
#include "vk_loader_platform.h"
4142
#include "wsi.h"
@@ -852,8 +853,34 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstan
852853
goto out;
853854
}
854855

856+
struct loader_envvar_id_filter device_id_filter;
857+
struct loader_envvar_id_filter vendor_id_filter;
858+
struct loader_envvar_id_filter driver_id_filter;
859+
860+
parse_id_filter_enviroment_var(inst, VK_DEVICE_ID_FILTER_ENV_VAR, &device_id_filter);
861+
parse_id_filter_enviroment_var(inst, VK_VENDOR_ID_FILTER_ENV_VAR, &vendor_id_filter);
862+
parse_id_filter_enviroment_var(inst, VK_DRIVER_ID_FILTER_ENV_VAR, &driver_id_filter);
863+
855864
// Call down the chain to get the physical device info
856-
res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, pPhysicalDeviceCount, pPhysicalDevices);
865+
if ((0 == device_id_filter.count) && (0 == vendor_id_filter.count) && (0 == driver_id_filter.count)) {
866+
res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, pPhysicalDeviceCount, pPhysicalDevices);
867+
} else {
868+
uint32_t physical_device_count = 0;
869+
res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, &physical_device_count, NULL);
870+
if (res != VK_SUCCESS) {
871+
goto out;
872+
}
873+
874+
VkPhysicalDevice *physical_devices = loader_stack_alloc(physical_device_count * sizeof(VkPhysicalDevice));
875+
res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, &physical_device_count, physical_devices);
876+
if (res != VK_SUCCESS) {
877+
goto out;
878+
}
879+
880+
res = loader_filter_enumerated_physical_device(inst, &device_id_filter, &vendor_id_filter, &driver_id_filter,
881+
physical_device_count, physical_devices, pPhysicalDeviceCount,
882+
pPhysicalDevices);
883+
}
857884

858885
if (NULL != pPhysicalDevices && (VK_SUCCESS == res || VK_INCOMPLETE == res)) {
859886
// Wrap the PhysDev object for loader usage, return wrapped objects
@@ -2586,9 +2613,40 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups(
25862613
goto out;
25872614
}
25882615

2616+
struct loader_envvar_id_filter device_id_filter;
2617+
struct loader_envvar_id_filter vendor_id_filter;
2618+
struct loader_envvar_id_filter driver_id_filter;
2619+
2620+
parse_id_filter_enviroment_var(inst, VK_DEVICE_ID_FILTER_ENV_VAR, &device_id_filter);
2621+
parse_id_filter_enviroment_var(inst, VK_VENDOR_ID_FILTER_ENV_VAR, &vendor_id_filter);
2622+
parse_id_filter_enviroment_var(inst, VK_DRIVER_ID_FILTER_ENV_VAR, &driver_id_filter);
2623+
25892624
// Call down the chain to get the physical device group info.
2590-
res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, pPhysicalDeviceGroupCount,
2591-
pPhysicalDeviceGroupProperties);
2625+
if ((0 == device_id_filter.count) && (0 == vendor_id_filter.count) && (0 == driver_id_filter.count)) {
2626+
res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, pPhysicalDeviceGroupCount,
2627+
pPhysicalDeviceGroupProperties);
2628+
} else {
2629+
uint32_t physical_device_group_count = 0;
2630+
res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, &physical_device_group_count, NULL);
2631+
if (res != VK_SUCCESS) {
2632+
goto out;
2633+
}
2634+
2635+
VkPhysicalDeviceGroupProperties *physical_device_group_properties =
2636+
loader_stack_alloc(physical_device_group_count * sizeof(VkPhysicalDeviceGroupProperties));
2637+
memset(physical_device_group_properties, 0, physical_device_group_count * sizeof(VkPhysicalDeviceGroupProperties));
2638+
2639+
res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, &physical_device_group_count,
2640+
physical_device_group_properties);
2641+
if (res != VK_SUCCESS) {
2642+
goto out;
2643+
}
2644+
2645+
res = loader_filter_enumerated_physical_device_groups(inst, &device_id_filter, &vendor_id_filter, &driver_id_filter,
2646+
physical_device_group_count, physical_device_group_properties,
2647+
pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
2648+
}
2649+
25922650
if (NULL != pPhysicalDeviceGroupProperties && (VK_SUCCESS == res || VK_INCOMPLETE == res)) {
25932651
// Wrap the PhysDev object for loader usage, return wrapped objects
25942652
VkResult update_res = setup_loader_tramp_phys_dev_groups(inst, *pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);

loader/vk_loader_platform.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@
130130
#define VK_IMPLICIT_LAYER_PATH_ENV_VAR "VK_IMPLICIT_LAYER_PATH"
131131
#define VK_ADDITIONAL_IMPLICIT_LAYER_PATH_ENV_VAR "VK_ADD_IMPLICIT_LAYER_PATH"
132132

133+
#define VK_DEVICE_ID_FILTER_ENV_VAR "VK_LOADER_DEVICE_ID_FILTER"
134+
#define VK_VENDOR_ID_FILTER_ENV_VAR "VK_LOADER_VENDOR_ID_FILTER"
135+
#define VK_DRIVER_ID_FILTER_ENV_VAR "VK_LOADER_DRIVER_ID_FILTER"
136+
133137
// Override layer information
134138
#define VK_OVERRIDE_LAYER_NAME "VK_LAYER_LUNARG_override"
135139

tests/framework/icd/test_icd.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,10 @@ VKAPI_ATTR void VKAPI_CALL test_vkGetPhysicalDeviceProperties2(VkPhysicalDevice
12321232
auto* vulkan_11_props = reinterpret_cast<VkPhysicalDeviceVulkan11Properties*>(pNext);
12331233
memcpy(vulkan_11_props->deviceUUID, phys_dev.deviceUUID.data(), VK_UUID_SIZE);
12341234
}
1235+
if (pNext->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES) {
1236+
auto* device_driver_props = reinterpret_cast<VkPhysicalDeviceDriverProperties*>(pNext);
1237+
*device_driver_props = phys_dev.driver_properties;
1238+
}
12351239
pNext = reinterpret_cast<VkBaseInStructure*>(const_cast<VkBaseInStructure*>(pNext->pNext));
12361240
}
12371241
}

tests/framework/icd/test_icd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct PhysicalDevice {
9494
BUILDER_VALUE(VkPhysicalDeviceProperties, properties)
9595
BUILDER_VALUE(VkPhysicalDeviceFeatures, features)
9696
BUILDER_VALUE(VkPhysicalDeviceMemoryProperties, memory_properties)
97+
BUILDER_VALUE(VkPhysicalDeviceDriverProperties, driver_properties)
9798
BUILDER_VALUE(VkImageFormatProperties, image_format_properties)
9899
BUILDER_VALUE(VkExternalMemoryProperties, external_memory_properties)
99100
BUILDER_VALUE(VkExternalSemaphoreProperties, external_semaphore_properties)

tests/framework/test_environment.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,9 @@ struct FrameworkEnvironment {
561561
EnvVarWrapper add_env_var_vk_layer_paths{"VK_ADD_LAYER_PATH"};
562562
EnvVarWrapper env_var_vk_implicit_layer_paths{"VK_IMPLICIT_LAYER_PATH"};
563563
EnvVarWrapper add_env_var_vk_implicit_layer_paths{"VK_ADD_IMPLICIT_LAYER_PATH"};
564+
EnvVarWrapper env_var_vk_loader_device_id_filter{"VK_LOADER_DEVICE_ID_FILTER"};
565+
EnvVarWrapper env_var_vk_loader_vendor_id_filter{"VK_LOADER_VENDOR_ID_FILTER"};
566+
EnvVarWrapper env_var_vk_loader_driver_id_filter{"VK_LOADER_DRIVER_ID_FILTER"};
564567

565568
#if TESTING_COMMON_UNIX_PLATFORMS
566569
EnvVarWrapper env_var_home{"HOME", "/home/fake_home"};

0 commit comments

Comments
 (0)