Skip to content

Commit eede24b

Browse files
Wint3rNightcharles-lunarg
authored andcommitted
loader: apply settings device configurations to device groups
The plain vkEnumeratePhysicalDevices path applies the settings file's device_configurations in terminator_EnumeratePhysicalDevices. Group enumeration did not, so an application enumerating groups could reach a VkPhysicalDevice that the settings file meant to hide, and the validation layer would then fault on a device it had never seen enumerated. Apply the same filter in terminator_EnumeratePhysicalDeviceGroups, reusing loader_apply_settings_device_configurations so the two paths cannot drift apart. If a group contains an excluded VkPhysicalDevice, drop the whole group rather than editing it: the devices in a group are physically linked, so a group with a member removed no longer describes the hardware it claims to. Also publish the post-filter group count. The copy loop already skipped groups whose physicalDeviceCount is zero, but the function published the pre-skip total, so enabling that path would have read past the groups actually written.
1 parent 255f659 commit eede24b

2 files changed

Lines changed: 216 additions & 3 deletions

File tree

loader/loader.c

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7217,7 +7217,7 @@ typedef struct physical_device_configuration_details {
72177217
VkResult loader_apply_settings_device_configurations(struct loader_instance *inst, uint32_t *pPhysicalDeviceCount,
72187218
VkPhysicalDevice *pPhysicalDevices) {
72197219
loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
7220-
"Reordering the output of vkEnumeratePhysicalDevices to match the loader settings device configurations list");
7220+
"Selecting and ordering VkPhysicalDevices to match the loader settings device configurations list");
72217221

72227222
physical_device_configuration_details *pd_details =
72237223
loader_stack_alloc(inst->phys_dev_count_term * sizeof(physical_device_configuration_details));
@@ -7734,6 +7734,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
77347734
VkResult res = VK_SUCCESS;
77357735
struct loader_icd_term *icd_term;
77367736
uint32_t total_count = 0;
7737+
// The number of groups actually written into new_phys_dev_groups. This is
7738+
// less than total_count when groups are skipped, which happens when the
7739+
// settings file hides a device that a group contains.
7740+
uint32_t new_group_count = 0;
77377741
uint32_t cur_icd_group_count = 0;
77387742
VkPhysicalDeviceGroupProperties **new_phys_dev_groups = NULL;
77397743
struct loader_physical_device_group_term *local_phys_dev_groups = NULL;
@@ -7988,11 +7992,61 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
79887992
}
79897993
}
79907994

7995+
// Apply the settings file's device_configurations to the groups. If a group
7996+
// contains an excluded VkPhysicalDevice, drop the whole group.
7997+
if (inst->settings.settings_active && inst->settings.device_configurations_active && NULL != inst->phys_devs_term) {
7998+
uint32_t visible_count = inst->phys_dev_count_term;
7999+
VkPhysicalDevice *visible_phys_devs = loader_stack_alloc(visible_count * sizeof(VkPhysicalDevice));
8000+
if (NULL == visible_phys_devs) {
8001+
res = VK_ERROR_OUT_OF_HOST_MEMORY;
8002+
goto out;
8003+
}
8004+
8005+
// Reuse the same matching the non-group path uses, so the two can't drift apart.
8006+
VkResult settings_res = loader_apply_settings_device_configurations(inst, &visible_count, visible_phys_devs);
8007+
if (VK_SUCCESS != settings_res) {
8008+
res = settings_res;
8009+
goto out;
8010+
}
8011+
8012+
for (uint32_t group = 0; group < total_count; group++) {
8013+
bool group_fully_visible = true;
8014+
for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].group_props.physicalDeviceCount;
8015+
group_gpu++) {
8016+
bool found = false;
8017+
for (uint32_t vis = 0; vis < visible_count; vis++) {
8018+
if (local_phys_dev_groups[group].group_props.physicalDevices[group_gpu] == visible_phys_devs[vis]) {
8019+
found = true;
8020+
break;
8021+
}
8022+
}
8023+
if (!found) {
8024+
group_fully_visible = false;
8025+
break;
8026+
}
8027+
}
8028+
8029+
if (!group_fully_visible) {
8030+
// Drop the whole group rather than removing the hidden device from it.
8031+
// The devices in a group are physically linked, so a group that has had
8032+
// a member removed no longer describes the hardware it claims to.
8033+
loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
8034+
"terminator_EnumeratePhysicalDeviceGroups: Physical device group %d contains a VkPhysicalDevice "
8035+
"which the settings file device configurations exclude, so the group was not reported.",
8036+
group);
8037+
local_phys_dev_groups[group].group_props.physicalDeviceCount = 0;
8038+
memset(local_phys_dev_groups[group].group_props.physicalDevices, 0,
8039+
sizeof(local_phys_dev_groups[group].group_props.physicalDevices));
8040+
}
8041+
}
8042+
}
8043+
79918044
uint32_t idx = 0;
79928045

79938046
// Copy or create everything to fill the new array of physical device groups
79948047
for (uint32_t group = 0; group < total_count; group++) {
7995-
// Skip groups which have been included through sorting
8048+
// Skip groups which have been included through sorting, and groups the
8049+
// settings file excluded above.
79968050
if (local_phys_dev_groups[group].group_props.physicalDeviceCount == 0) {
79978051
continue;
79988052
}
@@ -8046,6 +8100,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
80468100

80478101
++idx;
80488102
}
8103+
8104+
// Only idx entries were written; the rest of new_phys_dev_groups is still NULL
8105+
// from the calloc above, so the count must reflect what was actually filled in.
8106+
new_group_count = idx;
80498107
}
80508108

80518109
out:
@@ -8096,7 +8154,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
80968154
}
80978155

80988156
// Swap in the new physical device group list
8099-
inst->phys_dev_group_count_term = total_count;
8157+
inst->phys_dev_group_count_term = new_group_count;
81008158
inst->phys_dev_groups_term = new_phys_dev_groups;
81018159
}
81028160

tests/loader_settings_tests.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,6 +3203,161 @@ TEST(SettingsFile, InvalidAdditionalDriversField) {
32033203
EXPECT_TRUE(string_eq(active_layer_props.at(0).layerName, layer_name));
32043204
}
32053205

3206+
// Reproduces #1915: the settings file's device_configurations list restricts
3207+
// what vkEnumeratePhysicalDevices reports, but vkEnumeratePhysicalDeviceGroups
3208+
// ignores it entirely, so an application can still reach a hidden device.
3209+
//
3210+
// Singleton groups only -- one group per physical device. There is no
3211+
// ambiguity in that case: a device the settings file hides must not be
3212+
// reachable through any group.
3213+
TEST(SettingsFile, DeviceConfigurationAppliesToPhysicalDeviceGroups) {
3214+
FrameworkEnvironment env{};
3215+
std::vector<VulkanUUID> uuids{2, VulkanUUID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
3216+
3217+
// Mix up the uuid's so that they are all unique
3218+
int count = 1;
3219+
for (auto& uuid : uuids) {
3220+
std::rotate(uuid.begin(), uuid.begin() + count, uuid.end());
3221+
count++;
3222+
}
3223+
3224+
auto& icd = env.add_icd(TEST_ICD_PATH_VERSION_2).set_icd_api_version(VK_API_VERSION_1_1);
3225+
icd.add_physical_device(
3226+
PhysicalDevice().set_deviceName("visible").set_api_version(VK_API_VERSION_1_1).set_deviceUUID(uuids[0]));
3227+
icd.add_physical_device(PhysicalDevice().set_deviceName("hidden").set_api_version(VK_API_VERSION_1_1).set_deviceUUID(uuids[1]));
3228+
3229+
icd.physical_device_groups.emplace_back(0);
3230+
icd.physical_device_groups.emplace_back(1);
3231+
3232+
// The settings file lists only the first device, so the second is hidden.
3233+
env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(AppSpecificSettings{});
3234+
env.loader_settings.app_specific_settings.at(0).add_device_configuration(
3235+
LoaderSettingsDeviceConfiguration{}.set_deviceUUID(uuids[0]));
3236+
env.update_loader_settings(env.loader_settings);
3237+
3238+
InstWrapper inst{env.vulkan_functions};
3239+
inst.CheckCreate();
3240+
3241+
// The non-group path already honours the settings file.
3242+
auto pds = inst.GetPhysDevs();
3243+
ASSERT_EQ(pds.size(), 1U);
3244+
3245+
// The group path must agree. The count query is an upper bound -- the
3246+
// non-group path estimates its count the same way -- so what matters is
3247+
// that the groups actually written out exclude the hidden device.
3248+
uint32_t group_count = 0;
3249+
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &group_count, nullptr));
3250+
ASSERT_GE(group_count, 1U);
3251+
3252+
std::vector<VkPhysicalDeviceGroupProperties> groups{
3253+
group_count, VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES}};
3254+
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &group_count, groups.data()));
3255+
ASSERT_EQ(group_count, 1U);
3256+
3257+
// ...and the one device reachable through it is the visible one.
3258+
ASSERT_EQ(groups[0].physicalDeviceCount, 1U);
3259+
VkPhysicalDeviceProperties props{};
3260+
inst->vkGetPhysicalDeviceProperties(groups[0].physicalDevices[0], &props);
3261+
ASSERT_TRUE(string_eq(props.deviceName, "visible"));
3262+
}
3263+
3264+
// A group holding both a visible and a hidden device is dropped whole rather
3265+
// than having the hidden device removed from it. The devices in a group are
3266+
// physically linked, so a group missing a member misdescribes the hardware.
3267+
TEST(SettingsFile, DeviceConfigurationDropsPartiallyHiddenPhysicalDeviceGroup) {
3268+
FrameworkEnvironment env{};
3269+
std::vector<VulkanUUID> uuids{2, VulkanUUID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
3270+
3271+
int count = 1;
3272+
for (auto& uuid : uuids) {
3273+
std::rotate(uuid.begin(), uuid.begin() + count, uuid.end());
3274+
count++;
3275+
}
3276+
3277+
auto& icd = env.add_icd(TEST_ICD_PATH_VERSION_2).set_icd_api_version(VK_API_VERSION_1_1);
3278+
icd.add_physical_device(
3279+
PhysicalDevice().set_deviceName("visible").set_api_version(VK_API_VERSION_1_1).set_deviceUUID(uuids[0]));
3280+
icd.add_physical_device(PhysicalDevice().set_deviceName("hidden").set_api_version(VK_API_VERSION_1_1).set_deviceUUID(uuids[1]));
3281+
3282+
// A single group containing both devices.
3283+
icd.physical_device_groups.push_back(PhysicalDeviceGroup({0, 1}));
3284+
3285+
env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(AppSpecificSettings{});
3286+
env.loader_settings.app_specific_settings.at(0).add_device_configuration(
3287+
LoaderSettingsDeviceConfiguration{}.set_deviceUUID(uuids[0]));
3288+
env.update_loader_settings(env.loader_settings);
3289+
3290+
InstWrapper inst{env.vulkan_functions};
3291+
inst.CheckCreate();
3292+
3293+
auto pds = inst.GetPhysDevs();
3294+
ASSERT_EQ(pds.size(), 1U);
3295+
3296+
uint32_t group_count = 0;
3297+
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &group_count, nullptr));
3298+
std::vector<VkPhysicalDeviceGroupProperties> groups{
3299+
group_count, VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES}};
3300+
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &group_count, groups.data()));
3301+
ASSERT_EQ(group_count, 0U);
3302+
}
3303+
3304+
// When no device matches the settings file, the group path fails the same way
3305+
// the plain path does rather than quietly reporting every group.
3306+
TEST(SettingsFile, DeviceConfigurationMatchingNothingFailsPhysicalDeviceGroups) {
3307+
FrameworkEnvironment env{};
3308+
std::vector<VulkanUUID> uuids{2, VulkanUUID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
3309+
3310+
int count = 1;
3311+
for (auto& uuid : uuids) {
3312+
std::rotate(uuid.begin(), uuid.begin() + count, uuid.end());
3313+
count++;
3314+
}
3315+
3316+
auto& icd = env.add_icd(TEST_ICD_PATH_VERSION_2).set_icd_api_version(VK_API_VERSION_1_1);
3317+
icd.add_physical_device(PhysicalDevice().set_deviceName("only").set_api_version(VK_API_VERSION_1_1).set_deviceUUID(uuids[0]));
3318+
icd.physical_device_groups.emplace_back(0);
3319+
3320+
// The settings file names a device that does not exist.
3321+
env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(AppSpecificSettings{});
3322+
env.loader_settings.app_specific_settings.at(0).add_device_configuration(
3323+
LoaderSettingsDeviceConfiguration{}.set_deviceUUID(uuids[1]));
3324+
env.update_loader_settings(env.loader_settings);
3325+
3326+
InstWrapper inst{env.vulkan_functions};
3327+
inst.CheckCreate();
3328+
3329+
inst.GetPhysDev(VK_ERROR_INITIALIZATION_FAILED);
3330+
3331+
uint32_t group_count = 0;
3332+
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &group_count, nullptr));
3333+
std::vector<VkPhysicalDeviceGroupProperties> groups{
3334+
group_count, VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES}};
3335+
ASSERT_EQ(VK_ERROR_INITIALIZATION_FAILED, inst->vkEnumeratePhysicalDeviceGroups(inst, &group_count, groups.data()));
3336+
}
3337+
3338+
// Without a settings file the groups are reported exactly as the driver gives
3339+
// them, so the filtering above must not disturb the normal path.
3340+
TEST(SettingsFile, NoDeviceConfigurationLeavesPhysicalDeviceGroupsAlone) {
3341+
FrameworkEnvironment env{};
3342+
3343+
auto& icd = env.add_icd(TEST_ICD_PATH_VERSION_2).set_icd_api_version(VK_API_VERSION_1_1);
3344+
icd.add_physical_device(PhysicalDevice().set_deviceName("first").set_api_version(VK_API_VERSION_1_1));
3345+
icd.add_physical_device(PhysicalDevice().set_deviceName("second").set_api_version(VK_API_VERSION_1_1));
3346+
3347+
icd.physical_device_groups.emplace_back(0);
3348+
icd.physical_device_groups.emplace_back(1);
3349+
3350+
InstWrapper inst{env.vulkan_functions};
3351+
inst.CheckCreate();
3352+
3353+
uint32_t group_count = 0;
3354+
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &group_count, nullptr));
3355+
std::vector<VkPhysicalDeviceGroupProperties> groups{
3356+
group_count, VkPhysicalDeviceGroupProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES}};
3357+
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDeviceGroups(inst, &group_count, groups.data()));
3358+
ASSERT_EQ(group_count, 2U);
3359+
}
3360+
32063361
TEST(SettingsFile, DriverConfigurationsInSpecifiedOrder) {
32073362
FrameworkEnvironment env{};
32083363
std::vector<VulkanUUID> uuids{10, VulkanUUID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};

0 commit comments

Comments
 (0)