uint32_t idx = 0;
// Copy over everything found through sorted enumeration
-#if defined(_WIN32)
- struct loader_phys_dev_per_icd *phys_dev_array = sorted_phys_dev_array;
- for (uint32_t i = 0; i < sorted_count; ++i) {
-#else
struct loader_phys_dev_per_icd *phys_dev_array = icd_phys_dev_array;
- for (uint32_t i = 0; i < inst->total_icd_count; ++i) {
+ uint32_t max_count = inst->total_icd_count;
+#if defined(_WIN32)
+ if (sorted_count > 0) {
+ phys_dev_array = sorted_phys_dev_array;
+ max_count = sorted_count;
+ }
#endif
+ for (uint32_t i = 0; i < max_count; ++i) {
for (uint32_t j = 0; j < phys_dev_array[i].device_count; ++j) {
// Check if this physical device is already in the old buffer
if (NULL != inst->phys_devs_term) {
if (NULL != pPhysicalDevices) {
if (copy_count > *pPhysicalDeviceCount) {
copy_count = *pPhysicalDeviceCount;
+ loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+ "terminator_EnumeratePhysicalDevices : Trimming device count from %d to %d.", inst->total_gpu_count,
+ copy_count);
res = VK_INCOMPLETE;
}
uint32_t cur_icd_group_count = 0;
VkPhysicalDeviceGroupPropertiesKHR **new_phys_dev_groups = NULL;
struct loader_physical_device_group_term *local_phys_dev_groups = NULL;
- bool *local_phys_dev_group_sorted = NULL;
PFN_vkEnumeratePhysicalDeviceGroups fpEnumeratePhysicalDeviceGroups = NULL;
struct loader_phys_dev_per_icd *sorted_phys_dev_array = NULL;
uint32_t sorted_count = 0;
// Create a temporary array (on the stack) to keep track of the
// returned VkPhysicalDevice values.
local_phys_dev_groups = loader_stack_alloc(sizeof(struct loader_physical_device_group_term) * total_count);
- local_phys_dev_group_sorted = loader_stack_alloc(sizeof(bool) * total_count);
- if (NULL == local_phys_dev_groups || NULL == local_phys_dev_group_sorted) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
- "terminator_EnumeratePhysicalDeviceGroups: Failed to allocate local physical device group array of size %d",
- total_count);
- res = VK_ERROR_OUT_OF_HOST_MEMORY;
- goto out;
- }
// Initialize the memory to something valid
memset(local_phys_dev_groups, 0, sizeof(struct loader_physical_device_group_term) * total_count);
- memset(local_phys_dev_group_sorted, 0, sizeof(bool) * total_count);
#if defined(_WIN32)
// Get the physical devices supported by platform sorting mechanism into a separate list
for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
uint32_t count_this_time = total_count - cur_icd_group_count;
- // Check if this group can be sorted
-#if defined(VK_USE_PLATFORM_WIN32_KHR)
- bool icd_sorted = sorted_count && (icd_term->scanned_icd->EnumerateAdapterPhysicalDevices != NULL);
-#else
- bool icd_sorted = false;
-#endif
-
// Get the function pointer to use to call into the ICD. This could be the core or KHR version
if (inst->enabled_known_extensions.khr_device_group_creation) {
fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR;
local_phys_dev_groups[cur_index].icd_index = icd_idx;
local_phys_dev_groups[cur_index].group_props.physicalDeviceCount = 1;
local_phys_dev_groups[cur_index].group_props.physicalDevices[0] = phys_dev_array[indiv_gpu];
- local_phys_dev_group_sorted[cur_index] = icd_sorted;
}
} else {
goto out;
}
if (cur_icd_group_count + count_this_time < *pPhysicalDeviceGroupCount) {
- // Can just use passed in structs
+ // The total amount is still less than the amount of phsyical device group data passed in
+ // by the callee. Therefore, we don't have to allocate any temporary structures and we
+ // can just use the data that was passed in.
res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time,
&pPhysicalDeviceGroupProperties[cur_icd_group_count]);
if (res != VK_SUCCESS) {
for (uint32_t group = 0; group < count_this_time; ++group) {
uint32_t cur_index = group + cur_icd_group_count;
local_phys_dev_groups[cur_index].group_props = pPhysicalDeviceGroupProperties[cur_index];
- local_phys_dev_group_sorted[cur_index] = icd_sorted;
local_phys_dev_groups[cur_index].this_icd_term = icd_term;
local_phys_dev_groups[cur_index].icd_index = icd_idx;
}
} else {
- // Have to use a temporary copy
+ // There's not enough space in the callee's allocated pPhysicalDeviceGroupProperties structs,
+ // so we have to allocate temporary versions to collect all the data. However, we need to make
+ // sure that at least the ones we do query utilize any pNext data in the callee's version.
VkPhysicalDeviceGroupProperties *tmp_group_props =
loader_stack_alloc(count_this_time * sizeof(VkPhysicalDeviceGroupProperties));
for (uint32_t group = 0; group < count_this_time; group++) {
for (uint32_t group = 0; group < count_this_time; ++group) {
uint32_t cur_index = group + cur_icd_group_count;
local_phys_dev_groups[cur_index].group_props = tmp_group_props[group];
- local_phys_dev_group_sorted[cur_index] = icd_sorted;
local_phys_dev_groups[cur_index].this_icd_term = icd_term;
local_phys_dev_groups[cur_index].icd_index = icd_idx;
}
#ifdef LOADER_ENABLE_LINUX_SORT
if (is_linux_sort_enabled(inst)) {
// Get the physical devices supported by platform sorting mechanism into a separate list
- res = linux_read_sorted_physical_device_groups(inst, total_count, local_phys_dev_groups);
+ res = linux_sort_physical_device_groups(inst, total_count, local_phys_dev_groups);
+ }
+#elif defined(_WIN32)
+ // The Windows sorting information is only on physical devices. We need to take that and convert it to the group
+ // information if it's present.
+ if (sorted_count > 0) {
+ res =
+ windows_sort_physical_device_groups(inst, total_count, local_phys_dev_groups, sorted_count, sorted_phys_dev_array);
}
#endif // LOADER_ENABLE_LINUX_SORT
- // Replace all the physical device IDs with the proper loader values
+ // Just to be safe, make sure we successfully completed setup_loader_term_phys_devs above
+ // before attempting to do the following. By verifying that setup_loader_term_phys_devs ran
+ // first, it guarantees that each physical device will have a loader-specific handle.
if (NULL != inst->phys_devs_term) {
for (uint32_t group = 0; group < total_count; group++) {
for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].group_props.physicalDeviceCount;
uint32_t idx = 0;
-#if defined(_WIN32)
- // Copy over everything found through sorted enumeration
- for (uint32_t i = 0; i < sorted_count; ++i) {
- // Find the VkPhysicalDeviceGroupProperties object in local_phys_dev_groups
- VkPhysicalDeviceGroupProperties *group_properties = NULL;
- for (uint32_t group = 0; group < total_count; group++) {
- if (sorted_phys_dev_array[i].device_count != local_phys_dev_groups[group].group_props.physicalDeviceCount) {
- continue;
- }
-
- bool match = true;
- for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].group_props.physicalDeviceCount;
- group_gpu++) {
- if (sorted_phys_dev_array[i].physical_devices[group_gpu] !=
- ((struct loader_physical_device_term *)local_phys_dev_groups[group].group_props.physicalDevices[group_gpu])
- ->phys_dev) {
- match = false;
- break;
- }
- }
-
- if (match) {
- group_properties = &local_phys_dev_groups[group].group_props;
- }
- }
-#else // ! WIN32
- // Copy or create everything to fill the new array of physical device groups
- for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
+ // Copy or create everything to fill the new array of physical device groups
+ for (uint32_t group = 0; group < total_count; group++) {
// Skip groups which have been included through sorting
- if (local_phys_dev_group_sorted[new_idx] || local_phys_dev_groups[new_idx].group_props.physicalDeviceCount == 0) {
+ if (local_phys_dev_groups[group].group_props.physicalDeviceCount == 0) {
continue;
}
// Find the VkPhysicalDeviceGroupProperties object in local_phys_dev_groups
- VkPhysicalDeviceGroupProperties *group_properties = &local_phys_dev_groups[new_idx].group_props;
-#endif
+ VkPhysicalDeviceGroupProperties *group_properties = &local_phys_dev_groups[group].group_props;
// Check if this physical device group with the same contents is already in the old buffer
for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
if (NULL != pPhysicalDeviceGroupProperties) {
if (copy_count > *pPhysicalDeviceGroupCount) {
copy_count = *pPhysicalDeviceGroupCount;
+ loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+ "terminator_EnumeratePhysicalDeviceGroups : Trimming device count from %d to %d.",
+ inst->phys_dev_group_count_term, copy_count);
res = VK_INCOMPLETE;
}
return res;
}
-// This function allocates an array in sorted_devices which must be freed by the caller if not null
-VkResult linux_read_sorted_physical_device_groups(struct loader_instance *inst, uint32_t group_count,
- struct loader_physical_device_group_term *sorted_group_term) {
+// This function sorts an array of physical device groups
+VkResult linux_sort_physical_device_groups(struct loader_instance *inst, uint32_t group_count,
+ struct loader_physical_device_group_term *sorted_group_term) {
VkResult res = VK_SUCCESS;
bool is_vulkan_1_1 = false;
if (inst->app_api_major_version >= 1 && inst->app_api_minor_version >= 1) {
is_vulkan_1_1 = true;
}
- loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
- "linux_read_sorted_physical_device_groups: Original order:");
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "linux_sort_physical_device_groups: Original order:");
for (uint32_t group = 0; group < group_count; ++group) {
loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, " Group %u", group);
// Match the externally used physical device list with the sorted physical device list for this group.
for (uint32_t dev = 0; dev < sorted_group_term[group].group_props.physicalDeviceCount; ++dev) {
- sorted_group_term[group].group_props.physicalDevices[dev] = sorted_group_term[group].internal_device_info[dev].physical_device;
+ sorted_group_term[group].group_props.physicalDevices[dev] =
+ sorted_group_term[group].internal_device_info[dev].physical_device;
}
}
qsort(sorted_group_term, group_count, sizeof(struct loader_physical_device_group_term), compare_device_groups);
if (loader_get_debug_level() & (VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT)) {
- loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
- "linux_read_sorted_physical_device_groups: Sorted order:");
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "linux_sort_physical_device_groups: Sorted order:");
for (uint32_t group = 0; group < group_count; ++group) {
loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, " Group %u", group);
for (uint32_t gpu = 0; gpu < sorted_group_term[group].group_props.physicalDeviceCount; ++gpu) {
struct loader_phys_dev_per_icd *icd_devices,
struct loader_physical_device_term **sorted_device_term);
-// This function allocates an array in sorted_devices which must be freed by the caller if not null
-VkResult linux_read_sorted_physical_device_groups(struct loader_instance *inst, uint32_t group_count,
- struct loader_physical_device_group_term *sorted_group_term);
+// This function sorts an array in physical device groups
+VkResult linux_sort_physical_device_groups(struct loader_instance *inst, uint32_t group_count,
+ struct loader_physical_device_group_term *sorted_group_term);
#endif // LOADER_ENABLE_LINUX_SORT
\ No newline at end of file
return feature_flags;
}
+// Sort the VkPhysicalDevices that are part of the current group with the list passed in from the sorted list.
+// Multiple groups could have devices out of the same sorted list, however, a single group's devices must all come
+// from the same sorted list.
+void windows_sort_devices_in_group(struct loader_instance *inst, struct VkPhysicalDeviceGroupProperties *group_props,
+ struct loader_phys_dev_per_icd *icd_sorted_list) {
+ uint32_t cur_index = 0;
+ for (uint32_t dev = 0; dev < icd_sorted_list->device_count; ++dev) {
+ for (uint32_t grp_dev = cur_index; grp_dev < group_props->physicalDeviceCount; ++grp_dev) {
+ if (icd_sorted_list->physical_devices[dev] == group_props->physicalDevices[grp_dev]) {
+ if (cur_index != grp_dev) {
+ VkPhysicalDevice swap_dev = group_props->physicalDevices[cur_index];
+ group_props->physicalDevices[cur_index] = group_props->physicalDevices[grp_dev];
+ group_props->physicalDevices[grp_dev] = swap_dev;
+ }
+ cur_index++;
+ break;
+ }
+ }
+ }
+ if (cur_index == 0) {
+ loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
+ "windows_sort_devices_in_group: Never encountered a device in the sorted list group");
+ }
+}
+
+// This function sorts an array in physical device groups based on the sorted physical device information
+VkResult windows_sort_physical_device_groups(struct loader_instance *inst, const uint32_t group_count,
+ struct loader_physical_device_group_term *sorted_group_term,
+ const uint32_t sorted_device_count,
+ struct loader_phys_dev_per_icd *sorted_phys_dev_array) {
+ if (0 == group_count || NULL == sorted_group_term) {
+ loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
+ "windows_sort_physical_device_groups: Called with invalid information (Group count %d, Sorted Info %p)",
+ group_count, sorted_group_term);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ uint32_t new_index = 0;
+ for (uint32_t icd = 0; icd < sorted_device_count; ++icd) {
+ for (uint32_t dev = 0; dev < sorted_phys_dev_array[icd].device_count; ++dev) {
+ // Find a group associated with a given device
+ for (uint32_t group = new_index; group < group_count; ++group) {
+ bool device_found = false;
+ // Look for the current sorted device in a group and put it in the correct location if it isn't already
+ for (uint32_t grp_dev = 0; grp_dev < sorted_group_term[group].group_props.physicalDeviceCount; ++grp_dev) {
+ if (sorted_group_term[group].group_props.physicalDevices[grp_dev] ==
+ sorted_phys_dev_array[icd].physical_devices[dev]) {
+ // First, sort devices inside of group to be in priority order
+ windows_sort_devices_in_group(inst, &sorted_group_term[group].group_props, &sorted_phys_dev_array[icd]);
+
+ // Second, move the group up in priority if it needs to be
+ if (new_index != group) {
+ struct loader_physical_device_group_term tmp = sorted_group_term[new_index];
+ sorted_group_term[new_index] = sorted_group_term[group];
+ sorted_group_term[group] = tmp;
+ }
+ device_found = true;
+ new_index++;
+ break;
+ }
+ }
+ if (device_found) {
+ break;
+ }
+ }
+ }
+ }
+ return VK_SUCCESS;
+}
+
#endif // _WIN32
\ No newline at end of file
VkResult windows_read_sorted_physical_devices(struct loader_instance *inst, struct loader_phys_dev_per_icd **sorted_devices,
uint32_t *sorted_count);
+// This function sorts an array in physical device groups based on the sorted physical device information
+VkResult windows_sort_physical_device_groups(struct loader_instance *inst, const uint32_t group_count,
+ struct loader_physical_device_group_term *sorted_group_term,
+ const uint32_t sorted_device_count,
+ struct loader_phys_dev_per_icd *sorted_phys_dev_array);
+
// Creates a DXGI factory
// Returns VkLoaderFeatureFlags containing VK_LOADER_FEATURE_PHYSICAL_DEVICE_SORTING if successful, otherwise 0
VkLoaderFeatureFlags windows_initialize_dxgi(void);
uint32_t group_count = 0;
if (0 == icd.physical_device_groups.size()) {
- group_count = icd.physical_devices.size();
+ group_count = static_cast<uint32_t>(icd.physical_devices.size());
for (size_t device_group = 0; device_group < icd.physical_devices.size(); device_group++) {
if (device_group >= *pPhysicalDeviceGroupCount) {
group_count = *pPhysicalDeviceGroupCount;
icd.physical_devices[device_group].vk_physical_device.handle;
}
} else {
- group_count = icd.physical_device_groups.size();
+ group_count = static_cast<uint32_t>(icd.physical_device_groups.size());
for (size_t device_group = 0; device_group < icd.physical_device_groups.size(); device_group++) {
if (device_group >= *pPhysicalDeviceGroupCount) {
group_count = *pPhysicalDeviceGroupCount;
uint32_t* pPhysicalDeviceCount,
VkPhysicalDevice* pPhysicalDevices) {
icd.called_enumerate_adapter_physical_devices = CalledEnumerateAdapterPhysicalDevices::called;
- return test_vkEnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
-
- return VK_SUCCESS;
+ VkResult res = test_vkEnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
+ // For this testing, flip order intentaionlly
+ if (nullptr != pPhysicalDevices) {
+ for (uint32_t lower = 0; lower < *pPhysicalDeviceCount; ++lower) {
+ uint32_t upper = *pPhysicalDeviceCount - lower - 1;
+ // In case of odd numbered list we don't want to waste resources flipping itself
+ if (upper == lower) {
+ break;
+ }
+ VkPhysicalDevice temp = pPhysicalDevices[lower];
+ pPhysicalDevices[lower] = pPhysicalDevices[upper];
+ pPhysicalDevices[upper] = temp;
+ }
+ }
+ return res;
}
#endif // defined(WIN32)
#endif // TEST_ICD_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES
#if TEST_PHYSDEV_LAYER_ADD
// Insert a new device in the beginning, middle, and end
- uint32_t middle = tmp_vector.size() / 2;
+ uint32_t middle = static_cast<uint32_t>(tmp_vector.size() / 2);
VkPhysicalDevice new_phys_dev = reinterpret_cast<VkPhysicalDevice>((size_t)(0xABCD0000));
layer.added_physical_devices.push_back(new_phys_dev);
tmp_vector.insert(tmp_vector.begin(), new_phys_dev);
#if TEST_PHYSDEV_LAYER_REORDER
// Flip the order of items
- for (int32_t dev = tmp_vector.size() - 1; dev >= 0; --dev) {
+ for (int32_t dev = static_cast<int32_t>(tmp_vector.size() - 1); dev >= 0; --dev) {
layer.complete_physical_devices.push_back(tmp_vector[dev]);
}
#else // !TEST_PHYSDEV_LAYER_REORDER
}
if (nullptr == pPhysicalDevices) {
- *pPhysicalDeviceCount = layer.complete_physical_devices.size();
+ *pPhysicalDeviceCount = static_cast<uint32_t>(layer.complete_physical_devices.size());
} else {
- uint32_t adj_count = layer.complete_physical_devices.size();
+ uint32_t adj_count = static_cast<uint32_t>(layer.complete_physical_devices.size());
if (*pPhysicalDeviceCount < adj_count) {
adj_count = *pPhysicalDeviceCount;
res = VK_INCOMPLETE;
#if TEST_PHYSDEV_LAYER_REORDER
// Flip the order of items
- for (int32_t dev = tmp_vector.size() - 1; dev >= 0; --dev) {
+ for (int32_t dev = static_cast<int32_t>(tmp_vector.size() - 1); dev >= 0; --dev) {
layer.complete_physical_device_groups.push_back(tmp_vector[dev]);
}
#else // !TEST_PHYSDEV_LAYER_REORDER
}
if (nullptr == pPhysicalDeviceGroupProperties) {
- *pPhysicalDeviceGroupCount = layer.complete_physical_device_groups.size();
+ *pPhysicalDeviceGroupCount = static_cast<uint32_t>(layer.complete_physical_device_groups.size());
} else {
- uint32_t adj_count = layer.complete_physical_device_groups.size();
+ uint32_t adj_count = static_cast<uint32_t>(layer.complete_physical_device_groups.size());
if (*pPhysicalDeviceGroupCount < adj_count) {
adj_count = *pPhysicalDeviceGroupCount;
res = VK_INCOMPLETE;
// Test report created outside of vkCreateInstance with info in vkEnumeratePhysicalDevices.
// This should not be logged because type is wrong.
TEST_F(SeparateReport, InfoInEnumDevsIgnored) {
- expected_message = "Trimming device count down by application request";
+ expected_message = "Trimming device count from 6 to 5";
expected_object_type = VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT;
expected_flag = VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
// Test report created outside of vkCreateInstance with info in vkEnumeratePhysicalDevices.
// This should be logged because type is correct.
TEST_F(SeparateReport, InfoInEnumDevs) {
- expected_message = "Trimming device count down by application request";
+ expected_message = "Trimming device count from 6 to 5";
expected_object_type = VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT;
expected_flag = VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
// Test debug utils created outside of vkCreateInstance with info in vkEnumeratePhysicalDevices.
// This should not be logged because type is wrong.
TEST_F(SeparateMessenger, InfoInEnumDevsIgnoredType) {
- expected_message = "Trimming device count down by application request";
+ expected_message = "Trimming device count from 6 to 5";
expected_object_type = VK_OBJECT_TYPE_INSTANCE;
expected_message_flags = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
expected_severity_flags = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
// Test debug utils created outside of vkCreateInstance with info in vkEnumeratePhysicalDevices.
// This should not be logged because severity is wrong.
TEST_F(SeparateMessenger, InfoInEnumDevsIgnoredSeverity) {
- expected_message = "Trimming device count down by application request";
+ expected_message = "Trimming device count from 6 to 5";
expected_object_type = VK_OBJECT_TYPE_INSTANCE;
expected_message_flags = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
expected_severity_flags = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
// Test debug utils created outside of vkCreateInstance with info in vkEnumeratePhysicalDevices.
TEST_F(SeparateMessenger, InfoInEnumDevs) {
- expected_message = "Trimming device count down by application request";
+ expected_message = "Trimming device count from 6 to 5";
expected_object_type = VK_OBJECT_TYPE_INSTANCE;
expected_message_flags = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
expected_severity_flags = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
physical_device_handles.data()));
ASSERT_EQ(physical_count, returned_physical_count);
}
+
+TEST_F(ICDInterfaceVersion2PlusEnumerateAdapterPhysicalDevices, VerifyPhysDevResults) {
+ auto& driver = env->get_test_icd();
+ driver.min_icd_interface_version = 6;
+ driver.set_icd_api_version(VK_API_VERSION_1_1);
+ driver.physical_devices.emplace_back("physical_device_4");
+ driver.physical_devices.emplace_back("physical_device_3");
+ driver.physical_devices.emplace_back("physical_device_2");
+ driver.physical_devices.emplace_back("physical_device_1");
+ driver.physical_devices.emplace_back("physical_device_0");
+
+ InstWrapper inst1{env->vulkan_functions};
+ inst1.CheckCreate();
+
+ const uint32_t phys_dev_count = 5;
+ uint32_t count = phys_dev_count;
+ std::array<VkPhysicalDevice, phys_dev_count> original_pds;
+ std::array<std::string, phys_dev_count> original_pds_name;
+ ASSERT_EQ(VK_SUCCESS, env->vulkan_functions.vkEnumeratePhysicalDevices(inst1.inst, &count, original_pds.data()));
+ ASSERT_EQ(phys_dev_count, count);
+
+ for (uint32_t dev = 0; dev < phys_dev_count; ++dev) {
+ VkPhysicalDeviceProperties props;
+ env->vulkan_functions.vkGetPhysicalDeviceProperties(original_pds[dev], &props);
+ original_pds_name[dev] = props.deviceName;
+ }
+
+ uint32_t driver_index = 2; // which drive this test pretends to be
+ auto& known_driver = known_driver_list.at(2);
+ DXGI_ADAPTER_DESC1 desc1{};
+ wcsncpy_s(&desc1.Description[0], 128, L"TestDriver1", 128);
+ desc1.VendorId = known_driver.vendor_id;
+ desc1.AdapterLuid;
+ desc1.Flags = DXGI_ADAPTER_FLAG_NONE;
+ env->platform_shim->add_dxgi_adapter(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES, GpuType::discrete,
+ driver_index, desc1);
+
+ InstWrapper inst2{env->vulkan_functions};
+ inst2.CheckCreate();
+
+ // For the test ICD, when the D3D Adapter mechanism is enabled, it should completely swap the order of devices.
+ // Since we can't compare VkPhysicalDevice handles because they will be different per VkInstance, we will
+ // compare the property names returned, which should still be equal.
+
+ std::array<VkPhysicalDevice, phys_dev_count> adapter_pds;
+ std::array<std::string, phys_dev_count> adapter_pds_name;
+ ASSERT_EQ(VK_SUCCESS, env->vulkan_functions.vkEnumeratePhysicalDevices(inst1.inst, &count, adapter_pds.data()));
+ ASSERT_EQ(phys_dev_count, count);
+
+ for (uint32_t dev = 0; dev < phys_dev_count; ++dev) {
+ VkPhysicalDeviceProperties props;
+ env->vulkan_functions.vkGetPhysicalDeviceProperties(adapter_pds[dev], &props);
+ adapter_pds_name[dev] = props.deviceName;
+ }
+
+ for (uint32_t lower = 0; lower < phys_dev_count; ++lower) {
+ uint32_t upper = phys_dev_count - lower - 1;
+ ASSERT_EQ(true, string_eq(adapter_pds_name[upper].c_str(), original_pds_name[lower].c_str()));
+ }
+}
+
+TEST_F(ICDInterfaceVersion2PlusEnumerateAdapterPhysicalDevices, VerifyGroupResults) {
+ auto& driver = env->get_test_icd();
+ driver.min_icd_interface_version = 6;
+ driver.set_icd_api_version(VK_API_VERSION_1_1);
+ driver.physical_devices.emplace_back("physical_device_4");
+ driver.physical_devices.emplace_back("physical_device_3");
+ driver.physical_devices.emplace_back("physical_device_2");
+ driver.physical_devices.emplace_back("physical_device_1");
+ driver.physical_devices.emplace_back("physical_device_0");
+ 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]);
+ driver.physical_device_groups.emplace_back(driver.physical_devices[3]);
+ driver.physical_device_groups.back().use_physical_device(driver.physical_devices[4]);
+
+ InstWrapper inst1{env->vulkan_functions};
+ inst1.CheckCreate();
+
+ const uint32_t actual_group_count = 3;
+ uint32_t count = actual_group_count;
+ std::array<VkPhysicalDeviceGroupProperties, actual_group_count> original_groups{};
+ std::vector<std::vector<std::string>> original_strings;
+ original_strings.resize(actual_group_count);
+ for (uint32_t group = 0; group < actual_group_count; ++group) {
+ original_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
+ original_groups[group].pNext = nullptr;
+ }
+ ASSERT_EQ(VK_SUCCESS, inst1->vkEnumeratePhysicalDeviceGroups(inst1, &count, original_groups.data()));
+ ASSERT_EQ(actual_group_count, count);
+
+ for (uint32_t group = 0; group < actual_group_count; ++group) {
+ original_strings[group].resize(original_groups[group].physicalDeviceCount);
+ for (uint32_t dev = 0; dev < original_groups[group].physicalDeviceCount; ++dev) {
+ VkPhysicalDeviceProperties props;
+ env->vulkan_functions.vkGetPhysicalDeviceProperties(original_groups[group].physicalDevices[dev], &props);
+ original_strings[group][dev] = props.deviceName;
+ }
+ }
+
+ uint32_t driver_index = 2; // which drive this test pretends to be
+ auto& known_driver = known_driver_list.at(2);
+ DXGI_ADAPTER_DESC1 desc1{};
+ wcsncpy_s(&desc1.Description[0], 128, L"TestDriver1", 128);
+ desc1.VendorId = known_driver.vendor_id;
+ desc1.AdapterLuid;
+ desc1.Flags = DXGI_ADAPTER_FLAG_NONE;
+ env->platform_shim->add_dxgi_adapter(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_ENUMERATE_ADAPTER_PHYSICAL_DEVICES, GpuType::discrete,
+ driver_index, desc1);
+
+ InstWrapper inst2{env->vulkan_functions};
+ inst2.CheckCreate();
+
+ // For the test ICD, when the D3D Adapter mechanism is enabled, it should completely swap the order of devices.
+ // Since we can't compare VkPhysicalDevice handles because they will be different per VkInstance, we will
+ // compare the property names returned, which should still be equal.
+ // And, since this is device groups, the groups themselves should also be in reverse order with the devices
+ // inside each group in revers order.
+
+ std::array<VkPhysicalDeviceGroupProperties, actual_group_count> adapter_groups{};
+ std::vector<std::vector<std::string>> adapter_strings;
+ adapter_strings.resize(actual_group_count);
+
+ for (uint32_t group = 0; group < actual_group_count; ++group) {
+ adapter_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
+ adapter_groups[group].pNext = nullptr;
+ }
+ ASSERT_EQ(VK_SUCCESS, inst2->vkEnumeratePhysicalDeviceGroups(inst2, &count, adapter_groups.data()));
+ ASSERT_EQ(actual_group_count, count);
+
+ for (uint32_t group = 0; group < actual_group_count; ++group) {
+ adapter_strings[group].resize(adapter_groups[group].physicalDeviceCount);
+ for (uint32_t dev = 0; dev < adapter_groups[group].physicalDeviceCount; ++dev) {
+ VkPhysicalDeviceProperties props;
+ env->vulkan_functions.vkGetPhysicalDeviceProperties(adapter_groups[group].physicalDevices[dev], &props);
+ adapter_strings[group][dev] = props.deviceName;
+ }
+ }
+
+ for (uint32_t lower_group = 0; lower_group < actual_group_count; ++lower_group) {
+ uint32_t upper_group = actual_group_count - lower_group - 1;
+ ASSERT_EQ(original_groups[lower_group].physicalDeviceCount, adapter_groups[upper_group].physicalDeviceCount);
+ for (uint32_t lower_dev = 0; lower_dev < original_groups[lower_group].physicalDeviceCount; ++lower_dev) {
+ uint32_t upper_dev = original_groups[lower_group].physicalDeviceCount - lower_dev - 1;
+ ASSERT_EQ(true,
+ string_eq(adapter_strings[upper_group][upper_dev].c_str(), original_strings[lower_group][lower_dev].c_str()));
+ }
+ }
+}
+
#endif // defined(WIN32)
TEST(MultipleICDConfig, Basic) {