diff options
author | Charles Giessen <charles@lunarg.com> | 2022-04-05 09:14:49 +0300 |
---|---|---|
committer | Charles Giessen <46324611+charles-lunarg@users.noreply.github.com> | 2022-04-07 03:25:09 +0300 |
commit | 717697987eeb5614608b95e667e4b6d2def173c4 (patch) | |
tree | d029bbcd965de469e48823c8437e6e7d85eb3e3a | |
parent | 1de26aad69552f2de5ff81f5ad7ee37bef71efa0 (diff) |
Warn if portability_enumeration extension should be enabled
Log an error if an application creates a VkDevice from a physical device which
was enumerated from a driver that is a portability driver but the application
didn't correctly enable the portability enumeration flag & extension.
-rw-r--r-- | loader/loader.c | 32 | ||||
-rw-r--r-- | loader/loader_common.h | 4 | ||||
-rw-r--r-- | loader/trampoline.c | 12 | ||||
-rw-r--r-- | tests/framework/test_util.cpp | 6 | ||||
-rw-r--r-- | tests/framework/test_util.h | 11 | ||||
-rw-r--r-- | tests/loader_layer_tests.cpp | 136 | ||||
-rw-r--r-- | tests/loader_regression_tests.cpp | 199 |
7 files changed, 299 insertions, 101 deletions
diff --git a/loader/loader.c b/loader/loader.c index 96c904fd5..c2d651bf5 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -1169,6 +1169,13 @@ VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance // Traverse loader's extensions, adding non-duplicate extensions to the list debug_utils_AddInstanceExtensions(inst, inst_exts); + static const VkExtensionProperties portability_enumeration_extension_info[] = { + {VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION}}; + + // Add VK_KHR_portability_subset + loader_add_to_ext_list(inst, inst_exts, sizeof(portability_enumeration_extension_info) / sizeof(VkExtensionProperties), + portability_enumeration_extension_info); + out: return res; } @@ -1365,7 +1372,8 @@ static VkResult loader_scanned_icd_init(const struct loader_instance *inst, stru } static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list, - const char *filename, uint32_t api_version, enum loader_layer_library_status *lib_status) { + const char *filename, uint32_t api_version, bool is_portability_driver, + enum loader_layer_library_status *lib_status) { loader_platform_dl_handle handle; PFN_vkCreateInstance fp_create_inst; PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props; @@ -1505,6 +1513,7 @@ static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struc new_scanned_icd->EnumerateAdapterPhysicalDevices = fp_enum_dxgi_adapter_phys_devs; #endif new_scanned_icd->interface_version = interface_vers; + new_scanned_icd->portability_driver = is_portability_driver; new_scanned_icd->lib_name = (char *)loader_instance_heap_alloc(inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (NULL == new_scanned_icd->lib_name) { @@ -3540,9 +3549,18 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t json = NULL; continue; } + bool portability_driver = false; + item = cJSON_GetObjectItem(itemICD, "is_portability_driver"); + if (item != NULL && item->type == cJSON_True) { + portability_driver = true; + // TODO: skip over the driver if the is_portability_driver field is present and true but the portability + // enumeration extension is present. Then emit an error if no drivers are present but a portability driver + // was skipped. + } + VkResult icd_add_res = VK_SUCCESS; enum loader_layer_library_status lib_status; - icd_add_res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath, vers, &lib_status); + icd_add_res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath, vers, portability_driver, &lib_status); if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_add_res) { res = icd_add_res; goto out; @@ -5415,6 +5433,16 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical icd_exts.list = NULL; + // Check if the driver the VkPhysicalDevice comes from is a portability driver and emit a warning if the + // VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR bit isn't set + if (icd_term->scanned_icd->portability_driver && !icd_term->this_instance->portability_enumeration_enabled) { + loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, + "vkCreateDevice: Attempting to create a VkDevice from a VkPhysicalDevice which is from a portability driver " + "without the VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR bit in the VkInstanceCreateInfo flags being set " + "and the VK_KHR_portability_enumeration extension enabled. In future versions of the loader this " + "VkPhysicalDevice will not be enumerated."); + } + if (fpCreateDevice == NULL) { loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "terminator_CreateDevice: No vkCreateDevice command exposed by ICD %s", icd_term->scanned_icd->lib_name); diff --git a/loader/loader_common.h b/loader/loader_common.h index 94b11d523..4a6d6d182 100644 --- a/loader/loader_common.h +++ b/loader/loader_common.h @@ -292,6 +292,8 @@ struct loader_instance { VkAllocationCallbacks alloc_callbacks; + bool portability_enumeration_enabled; + bool wsi_surface_enabled; #ifdef VK_USE_PLATFORM_WIN32_KHR bool wsi_win32_surface_enabled; @@ -425,6 +427,8 @@ struct loader_scanned_icd { #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vk_icdEnumerateAdapterPhysicalDevices EnumerateAdapterPhysicalDevices; #endif + // whether the device is a portability driver + bool portability_driver; }; enum loader_data_files_type { diff --git a/loader/trampoline.c b/loader/trampoline.c index 604d69741..701df9581 100644 --- a/loader/trampoline.c +++ b/loader/trampoline.c @@ -482,6 +482,18 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCr ptr_instance->app_api_version.patch = 0; } + // Check the VkInstanceCreateInfoFlags wether to allow the portability enumeration flag + if ((pCreateInfo->flags & VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR) == 1) { + // Make sure the extension has been enabled + for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { + if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) { + ptr_instance->portability_enumeration_enabled = true; + loader_log(ptr_instance, VULKAN_LOADER_INFO_BIT, 0, + "Portability enumeration bit was set, enumerating portability drivers."); + } + } + } + // Look for one or more VK_EXT_debug_report or VK_EXT_debug_utils create info structures // and setup a callback(s) for each one found. ptr_instance->num_tmp_report_callbacks = 0; diff --git a/tests/framework/test_util.cpp b/tests/framework/test_util.cpp index 2dca441f1..5b8ac6b73 100644 --- a/tests/framework/test_util.cpp +++ b/tests/framework/test_util.cpp @@ -128,13 +128,16 @@ void print_vector_of_strings(std::string& out, const char* object_name, std::vec } } +std::string to_text(bool b) { return b ? std::string("true") : std::string("false"); } + std::string ManifestICD::get_manifest_str() const { std::string out; out += "{\n"; out += " " + file_format_version.get_version_str() + "\n"; out += " \"ICD\": {\n"; out += " \"library_path\": \"" + fs::fixup_backslashes_in_path(lib_path) + "\",\n"; - out += " \"api_version\": \"" + version_to_string(api_version) + "\"\n"; + out += " \"api_version\": \"" + version_to_string(api_version) + "\",\n"; + out += " \"is_portability_driver\": " + to_text(is_portability_driver) + "\n"; out += " }\n"; out += "}\n"; return out; @@ -639,6 +642,7 @@ VkInstanceCreateInfo* InstanceCreateInfo::get() noexcept { application_info.apiVersion = api_version; instance_info.pApplicationInfo = &application_info; } + instance_info.flags = flags; instance_info.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()); instance_info.ppEnabledLayerNames = enabled_layers.data(); instance_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()); diff --git a/tests/framework/test_util.h b/tests/framework/test_util.h index 1e8d47baa..c34c94024 100644 --- a/tests/framework/test_util.h +++ b/tests/framework/test_util.h @@ -536,6 +536,7 @@ struct ManifestICD { BUILDER_VALUE(ManifestICD, ManifestVersion, file_format_version, ManifestVersion()) BUILDER_VALUE(ManifestICD, uint32_t, api_version, 0) BUILDER_VALUE(ManifestICD, std::string, lib_path, {}) + BUILDER_VALUE(ManifestICD, bool, is_portability_driver, false) std::string get_manifest_str() const; }; @@ -762,6 +763,7 @@ struct InstanceCreateInfo { BUILDER_VALUE(InstanceCreateInfo, VkApplicationInfo, application_info, {}) BUILDER_VALUE(InstanceCreateInfo, std::string, app_name, {}) BUILDER_VALUE(InstanceCreateInfo, std::string, engine_name, {}) + BUILDER_VALUE(InstanceCreateInfo, uint32_t, flags, 0) BUILDER_VALUE(InstanceCreateInfo, uint32_t, app_version, 0) BUILDER_VALUE(InstanceCreateInfo, uint32_t, engine_version, 0) BUILDER_VALUE(InstanceCreateInfo, uint32_t, api_version, VK_API_VERSION_1_0) @@ -852,4 +854,13 @@ bool check_permutation(std::initializer_list<const char*> expected, std::vector< if (!found) return false; } return true; +} + +inline bool contains(std::vector<VkExtensionProperties> const& vec, const char* name) { + return std::any_of(std::begin(vec), std::end(vec), + [name](VkExtensionProperties const& elem) { return string_eq(name, elem.extensionName); }); +} +inline bool contains(std::vector<VkLayerProperties> const& vec, const char* name) { + return std::any_of(std::begin(vec), std::end(vec), + [name](VkLayerProperties const& elem) { return string_eq(name, elem.layerName); }); }
\ No newline at end of file diff --git a/tests/loader_layer_tests.cpp b/tests/loader_layer_tests.cpp index c89a968fb..2b1ad9b0c 100644 --- a/tests/loader_layer_tests.cpp +++ b/tests/loader_layer_tests.cpp @@ -315,13 +315,13 @@ TEST(MetaLayers, InvalidComponentLayer) { EXPECT_TRUE(string_eq(layer_props.layerName, regular_layer_name)); uint32_t extension_count = 0; - std::array<VkExtensionProperties, 2> extensions; + std::array<VkExtensionProperties, 3> extensions; EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - EXPECT_EQ(extension_count, 2U); // return debug report & debug utils + EXPECT_EQ(extension_count, 3U); // return debug report & debug utils & portability enumeration EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data())); - EXPECT_EQ(extension_count, 2U); + EXPECT_EQ(extension_count, 3U); InstWrapper inst{env.vulkan_functions}; inst.create_info.add_layer(meta_layer_name); @@ -360,13 +360,13 @@ TEST(MetaLayers, ExplicitMetaLayer) { EXPECT_TRUE(check_permutation({regular_layer_name, meta_layer_name}, layer_props)); uint32_t extension_count = 0; - std::array<VkExtensionProperties, 2> extensions; + std::array<VkExtensionProperties, 3> extensions; EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - EXPECT_EQ(extension_count, 2U); // return debug report & debug utils + EXPECT_EQ(extension_count, 3U); // return debug report & debug utils & portability enumeration EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data())); - EXPECT_EQ(extension_count, 2U); + EXPECT_EQ(extension_count, 3U); } { // don't enable the layer, shouldn't find any layers when calling vkEnumerateDeviceLayerProperties InstWrapper inst{env.vulkan_functions}; @@ -423,13 +423,13 @@ TEST(MetaLayers, MetaLayerNameInComponentLayers) { EXPECT_TRUE(string_eq(layer_props.layerName, regular_layer_name)); uint32_t extension_count = 0; - std::array<VkExtensionProperties, 2> extensions; + std::array<VkExtensionProperties, 3> extensions; EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - EXPECT_EQ(extension_count, 2U); // return debug report & debug utils + EXPECT_EQ(extension_count, 3U); // return debug report & debug utils & portability enumeration EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data())); - EXPECT_EQ(extension_count, 2U); + EXPECT_EQ(extension_count, 3U); InstWrapper inst{env.vulkan_functions}; inst.create_info.add_layer(meta_layer_name); @@ -472,13 +472,13 @@ TEST(MetaLayers, MetaLayerWhichAddsMetaLayer) { EXPECT_TRUE(check_permutation({regular_layer_name, meta_layer_name, meta_meta_layer_name}, layer_props)); uint32_t extension_count = 0; - std::array<VkExtensionProperties, 2> extensions; + std::array<VkExtensionProperties, 3> extensions; EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - EXPECT_EQ(extension_count, 2U); // return debug report & debug utils + EXPECT_EQ(extension_count, 3U); // return debug report & debug utils & portability enumeration EXPECT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data())); - EXPECT_EQ(extension_count, 2U); + EXPECT_EQ(extension_count, 3U); InstWrapper inst{env.vulkan_functions}; inst.create_info.add_layer(meta_layer_name); @@ -1318,24 +1318,22 @@ TEST(LayerExtensions, ImplicitNoAdditionalInstanceExtension) { ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr)); ASSERT_EQ(count, 1U); - // // set enable env-var, layer should load + // set enable env-var, layer should load set_env_var(enable_env_var, "1"); CheckLogForLayerString(env, implicit_layer_name, true); uint32_t extension_count = 0; std::vector<VkExtensionProperties> extension_props; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - if (extension_count > 0) { - extension_props.resize(extension_count); - ASSERT_EQ(VK_SUCCESS, - env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); - // Make sure the extensions that are implemented only in the test layers is not present. - for (uint32_t ext = 0; ext < extension_count; ++ext) { - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); - } - } + extension_props.resize(extension_count); + ASSERT_EQ(VK_SUCCESS, + env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); + ASSERT_EQ(extension_count, 3U); // debug_utils, debug_report, and portability enumeration + + // Make sure the extensions that are implemented only in the test layers is not present. + ASSERT_FALSE(contains(extension_props, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); + ASSERT_FALSE(contains(extension_props, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); InstWrapper inst{env.vulkan_functions}; inst.CheckCreate(); @@ -1381,20 +1379,15 @@ TEST(LayerExtensions, ImplicitDirDispModeInstanceExtension) { uint32_t extension_count = 0; std::vector<VkExtensionProperties> extension_props; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - ASSERT_EQ(extension_count, 3U); // the instance extension, debug_utils, and debug_report + ASSERT_EQ(extension_count, 4U); // the instance extension, debug_utils, debug_report, and portability enumeration extension_props.resize(extension_count); ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); + ASSERT_EQ(extension_count, 4U); // Make sure the extensions that are implemented only in the test layers is not present. - bool found = false; - for (uint32_t ext = 0; ext < extension_count; ++ext) { - if (!strcmp(extension_props[ext].extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)) { - found = true; - } - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); - } - ASSERT_EQ(true, found); + ASSERT_TRUE(contains(extension_props, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); + ASSERT_FALSE(contains(extension_props, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extension(VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME); @@ -1441,20 +1434,15 @@ TEST(LayerExtensions, ImplicitDispSurfCountInstanceExtension) { uint32_t extension_count = 0; std::vector<VkExtensionProperties> extension_props; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - ASSERT_EQ(extension_count, 3U); // the instance extension, debug_utils, and debug_report + ASSERT_EQ(extension_count, 4U); // the instance extension, debug_utils, debug_report, and portability enumeration extension_props.resize(extension_count); ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); + ASSERT_EQ(extension_count, 4U); // Make sure the extensions that are implemented only in the test layers is not present. - bool found = false; - for (uint32_t ext = 0; ext < extension_count; ++ext) { - if (!strcmp(extension_props[ext].extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)) { - found = true; - } - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); - } - ASSERT_EQ(true, found); + ASSERT_FALSE(contains(extension_props, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); + ASSERT_TRUE(contains(extension_props, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extension(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME); @@ -1503,24 +1491,15 @@ TEST(LayerExtensions, ImplicitBothInstanceExtensions) { uint32_t extension_count = 0; std::vector<VkExtensionProperties> extension_props; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - ASSERT_EQ(extension_count, 4U); // the two instance extension plus debug_utils and debug_report + ASSERT_EQ(extension_count, 5U); // the two instance extension plus debug_utils, debug_report, portability enumeration extension_props.resize(extension_count); ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); + ASSERT_EQ(extension_count, 5U); // Make sure the extensions that are implemented only in the test layers is not present. - bool found[2] = {false, false}; - for (uint32_t ext = 0; ext < extension_count; ++ext) { - if (!strcmp(extension_props[ext].extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)) { - found[0] = true; - } - if (!strcmp(extension_props[ext].extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)) { - found[1] = true; - } - } - for (uint32_t ext = 0; ext < 2; ++ext) { - ASSERT_EQ(true, found[ext]); - } + ASSERT_TRUE(contains(extension_props, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); + ASSERT_TRUE(contains(extension_props, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); InstWrapper inst{env.vulkan_functions}; inst.create_info.add_extension(VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME) @@ -1556,16 +1535,16 @@ TEST(LayerExtensions, ExplicitNoAdditionalInstanceExtension) { uint32_t extension_count = 0; std::vector<VkExtensionProperties> extension_props; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - if (extension_count > 0) { - extension_props.resize(extension_count); - ASSERT_EQ(VK_SUCCESS, - env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); + ASSERT_EQ(extension_count, 3U); // debug utils, debug report, portability enumeration + extension_props.resize(extension_count); + ASSERT_EQ(VK_SUCCESS, + env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); + ASSERT_EQ(extension_count, 3U); - // Make sure the extensions are not present - for (uint32_t ext = 0; ext < extension_count; ++ext) { - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); - } + // Make sure the extensions are not present + for (const auto& ext : extension_props) { + ASSERT_FALSE(string_eq(ext.extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); + ASSERT_FALSE(string_eq(ext.extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); } // Now query by layer name. @@ -1573,17 +1552,7 @@ TEST(LayerExtensions, ExplicitNoAdditionalInstanceExtension) { extension_props.clear(); ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(explicit_layer_name, &extension_count, nullptr)); - if (extension_count > 0) { - extension_props.resize(extension_count); - ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(explicit_layer_name, &extension_count, - extension_props.data())); - - // Make sure the extensions still aren't present in this layer - for (uint32_t ext = 0; ext < extension_count; ++ext) { - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); - } - } + ASSERT_EQ(extension_count, 0U); InstWrapper inst{env.vulkan_functions}; inst.CheckCreate(); @@ -1618,16 +1587,15 @@ TEST(LayerExtensions, ExplicitDirDispModeInstanceExtension) { uint32_t extension_count = 0; std::vector<VkExtensionProperties> extension_props; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - if (extension_count > 0) { - extension_props.resize(extension_count); - ASSERT_EQ(VK_SUCCESS, - env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); - - // Make sure the extensions are not present - for (uint32_t ext = 0; ext < extension_count; ++ext) { - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); - ASSERT_NE(0, strcmp(extension_props[ext].extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); - } + ASSERT_EQ(extension_count, 3U); // debug utils, debug report, portability enumeration + extension_props.resize(extension_count); + ASSERT_EQ(VK_SUCCESS, + env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_props.data())); + ASSERT_EQ(extension_count, 3U); + // Make sure the extensions are not present + for (const auto& ext : extension_props) { + ASSERT_FALSE(string_eq(ext.extensionName, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)); + ASSERT_FALSE(string_eq(ext.extensionName, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)); } // Now query by layer name. diff --git a/tests/loader_regression_tests.cpp b/tests/loader_regression_tests.cpp index c5bc2080e..dca30f480 100644 --- a/tests/loader_regression_tests.cpp +++ b/tests/loader_regression_tests.cpp @@ -189,32 +189,34 @@ TEST(EnumerateInstanceExtensionProperties, UsageChecks) { env.reset_icd().add_instance_extensions({first_ext, second_ext}); { // One Pass - uint32_t extension_count = 4; - std::array<VkExtensionProperties, 4> extensions; + uint32_t extension_count = 5; + std::array<VkExtensionProperties, 5> extensions; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data())); - ASSERT_EQ(extension_count, 4U); // return debug report & debug utils + our two extensions + ASSERT_EQ(extension_count, 5U); // return debug report & debug utils & portability enumeration + our two extensions // loader always adds the debug report & debug utils extensions ASSERT_TRUE(first_ext.extensionName == extensions[0].extensionName); ASSERT_TRUE(second_ext.extensionName == extensions[1].extensionName); ASSERT_TRUE(string_eq("VK_EXT_debug_report", extensions[2].extensionName)); ASSERT_TRUE(string_eq("VK_EXT_debug_utils", extensions[3].extensionName)); + ASSERT_TRUE(string_eq("VK_KHR_portability_enumeration", extensions[4].extensionName)); } { // Two Pass uint32_t extension_count = 0; - std::array<VkExtensionProperties, 4> extensions; + std::array<VkExtensionProperties, 5> extensions; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - ASSERT_EQ(extension_count, 4U); // return debug report & debug utils + our two extensions + ASSERT_EQ(extension_count, 5U); // return debug report & debug utils + our two extensions ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data())); - ASSERT_EQ(extension_count, 4U); + ASSERT_EQ(extension_count, 5U); // loader always adds the debug report & debug utils extensions ASSERT_TRUE(first_ext.extensionName == extensions[0].extensionName); ASSERT_TRUE(second_ext.extensionName == extensions[1].extensionName); ASSERT_TRUE(string_eq("VK_EXT_debug_report", extensions[2].extensionName)); ASSERT_TRUE(string_eq("VK_EXT_debug_utils", extensions[3].extensionName)); + ASSERT_TRUE(string_eq("VK_KHR_portability_enumeration", extensions[4].extensionName)); } } @@ -226,7 +228,7 @@ TEST(EnumerateInstanceExtensionProperties, PropertyCountLessThanAvailable) { std::array<VkExtensionProperties, 2> extensions; { // use nullptr for null string ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr)); - ASSERT_EQ(extension_count, 2U); // return debug report & debug utils + ASSERT_EQ(extension_count, 3U); // return debug report & debug utils & portability enumeration extension_count = 1; // artificially remove one extension ASSERT_EQ(VK_INCOMPLETE, @@ -237,7 +239,7 @@ TEST(EnumerateInstanceExtensionProperties, PropertyCountLessThanAvailable) { } { // use "" for null string ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties("", &extension_count, nullptr)); - ASSERT_EQ(extension_count, 2U); // return debug report & debug utils + ASSERT_EQ(extension_count, 3U); // return debug report & debug utils & portability enumeration extension_count = 1; // artificially remove one extension ASSERT_EQ(VK_INCOMPLETE, @@ -258,31 +260,33 @@ TEST(EnumerateInstanceExtensionProperties, FilterUnkownInstanceExtensions) { { uint32_t extension_count = 0; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties("", &extension_count, nullptr)); - ASSERT_EQ(extension_count, 2U); // return debug report & debug utils + ASSERT_EQ(extension_count, 3U); // return debug report & debug utils & portability enumeration - std::array<VkExtensionProperties, 2> extensions; + std::array<VkExtensionProperties, 3> extensions; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties("", &extension_count, extensions.data())); - ASSERT_EQ(extension_count, 2U); + ASSERT_EQ(extension_count, 3U); // loader always adds the debug report & debug utils extensions ASSERT_TRUE(string_eq(extensions[0].extensionName, "VK_EXT_debug_report")); ASSERT_TRUE(string_eq(extensions[1].extensionName, "VK_EXT_debug_utils")); + ASSERT_TRUE(string_eq(extensions[2].extensionName, "VK_KHR_portability_enumeration")); } { // Disable unknown instance extension filtering set_env_var("VK_LOADER_DISABLE_INST_EXT_FILTER", "1"); uint32_t extension_count = 0; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties("", &extension_count, nullptr)); - ASSERT_EQ(extension_count, 4U); + ASSERT_EQ(extension_count, 5U); - std::array<VkExtensionProperties, 4> extensions; + std::array<VkExtensionProperties, 5> extensions; ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties("", &extension_count, extensions.data())); - ASSERT_EQ(extension_count, 4U); + ASSERT_EQ(extension_count, 5U); ASSERT_EQ(extensions[0], first_ext.get()); ASSERT_EQ(extensions[1], second_ext.get()); // Loader always adds these two extensions ASSERT_TRUE(string_eq(extensions[2].extensionName, "VK_EXT_debug_report")); ASSERT_TRUE(string_eq(extensions[3].extensionName, "VK_EXT_debug_utils")); + ASSERT_TRUE(string_eq(extensions[4].extensionName, "VK_KHR_portability_enumeration")); } } @@ -3110,3 +3114,170 @@ TEST(SortedPhysicalDevices, DeviceGroupsSortedDisabled) { } #endif // __linux__ || __FreeBSD__ + +const char* portability_driver_warning = + "vkCreateDevice: Attempting to create a VkDevice from a VkPhysicalDevice which is from a portability driver " + "without the VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR bit in the VkInstanceCreateInfo flags being set " + "and the VK_KHR_portability_enumeration extension enabled. In future versions of the loader this " + "VkPhysicalDevice will not be enumerated."; + +TEST(PortabilityICDConfiguration, PortabilityICDOnly) { + FrameworkEnvironment env{}; + env.add_icd( + TestICDDetails(ManifestICD{}.set_lib_path(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA).set_is_portability_driver(true))); + + auto& driver = env.get_test_icd(); + driver.physical_devices.emplace_back("physical_device_0"); + driver.max_icd_interface_version = 1; + // TODO - Fix tests when portability devices are not longer enumerated by default + { // enable portability extension and flag + InstWrapper inst{env.vulkan_functions}; + inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + inst.create_info.add_extension("VK_KHR_portability_enumeration"); + inst.create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + + inst.CheckCreate(); + DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + CreateDebugUtilsMessenger(log); + + auto phys_dev = inst.GetPhysDev(); + handle_assert_has_value(phys_dev); + + DeviceWrapper dev_info{inst}; + dev_info.CheckCreate(phys_dev); + ASSERT_FALSE(log.find(portability_driver_warning)); + } + { // enable portability flag but not extension - shouldn't be able to create an instance when filtering is enabled + InstWrapper inst{env.vulkan_functions}; + inst.create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + inst.CheckCreate(); + DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + CreateDebugUtilsMessenger(log); + + auto phys_dev = inst.GetPhysDev(); + handle_assert_has_value(phys_dev); + + DeviceWrapper dev_info{inst}; + dev_info.CheckCreate(phys_dev); + ASSERT_TRUE(log.find(portability_driver_warning)); + } + { // enable portability extension but not flag - shouldn't be able to create an instance when filtering is enabled + InstWrapper inst{env.vulkan_functions}; + inst.create_info.add_extension("VK_KHR_portability_enumeration"); + inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + inst.CheckCreate(); + DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + CreateDebugUtilsMessenger(log); + + auto phys_dev = inst.GetPhysDev(); + handle_assert_has_value(phys_dev); + + DeviceWrapper dev_info{inst}; + dev_info.CheckCreate(phys_dev); + ASSERT_TRUE(log.find(portability_driver_warning)); + } + { // enable neither the portability extension or the flag - shouldn't be able to create an instance when filtering is enabled + InstWrapper inst{env.vulkan_functions}; + inst.create_info.flags = 0; // make sure its 0 - no portability + inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + inst.CheckCreate(); + DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + CreateDebugUtilsMessenger(log); + + auto phys_dev = inst.GetPhysDev(); + handle_assert_has_value(phys_dev); + + DeviceWrapper dev_info{inst}; + dev_info.CheckCreate(phys_dev); + ASSERT_TRUE(log.find(portability_driver_warning)); + } +} + +TEST(PortabilityICDConfiguration, PortabilityAndRegularICD) { + FrameworkEnvironment env{}; + env.add_icd(TestICDDetails(ManifestICD{}.set_lib_path(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA))); + env.add_icd( + TestICDDetails(ManifestICD{}.set_lib_path(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA).set_is_portability_driver(true))); + + auto& driver0 = env.get_test_icd(0); + auto& driver1 = env.get_test_icd(1); + + driver0.physical_devices.emplace_back("physical_device_0"); + driver0.max_icd_interface_version = 1; + + driver1.physical_devices.emplace_back("portability_physical_device_1"); + driver1.max_icd_interface_version = 1; + // TODO - Fix tests when portability devices are not longer enumerated by default + { // enable portability extension and flag + InstWrapper inst{env.vulkan_functions}; + inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + inst.create_info.add_extension("VK_KHR_portability_enumeration"); + inst.create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + inst.CheckCreate(); + DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + CreateDebugUtilsMessenger(log); + + auto phys_devs = inst.GetPhysDevs(2); + for (const auto& phys_dev : phys_devs) { + handle_assert_has_value(phys_dev); + } + DeviceWrapper dev_info_0{inst}; + DeviceWrapper dev_info_1{inst}; + dev_info_0.CheckCreate(phys_devs[0]); + dev_info_1.CheckCreate(phys_devs[1]); + ASSERT_FALSE(log.find(portability_driver_warning)); + } + { // enable portability extension but not flag - should only enumerate 1 physical device when filtering is enabled + InstWrapper inst{env.vulkan_functions}; + inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + inst.create_info.add_extension("VK_KHR_portability_enumeration"); + inst.CheckCreate(); + DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + CreateDebugUtilsMessenger(log); + + auto phys_devs = inst.GetPhysDevs(2); + for (const auto& phys_dev : phys_devs) { + handle_assert_has_value(phys_dev); + } + DeviceWrapper dev_info_0{inst}; + DeviceWrapper dev_info_1{inst}; + dev_info_0.CheckCreate(phys_devs[0]); + dev_info_1.CheckCreate(phys_devs[1]); + ASSERT_TRUE(log.find(portability_driver_warning)); + } + { // enable portability flag but not extension - should only enumerate 1 physical device when filtering is enabled + InstWrapper inst{env.vulkan_functions}; + inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + inst.create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + inst.CheckCreate(); + DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + CreateDebugUtilsMessenger(log); + + auto phys_devs = inst.GetPhysDevs(2); + for (const auto& phys_dev : phys_devs) { + handle_assert_has_value(phys_dev); + } + DeviceWrapper dev_info_0{inst}; + DeviceWrapper dev_info_1{inst}; + dev_info_0.CheckCreate(phys_devs[0]); + dev_info_1.CheckCreate(phys_devs[1]); + ASSERT_TRUE(log.find(portability_driver_warning)); + } + { // do not enable portability extension or flag - should only enumerate 1 physical device when filtering is enabled + InstWrapper inst{env.vulkan_functions}; + inst.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + inst.CheckCreate(); + DebugUtilsWrapper log{inst, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}; + CreateDebugUtilsMessenger(log); + auto phys_devs = inst.GetPhysDevs(2); + for (const auto& phys_dev : phys_devs) { + handle_assert_has_value(phys_dev); + } + DeviceWrapper dev_info_0{inst}; + DeviceWrapper dev_info_1{inst}; + dev_info_0.CheckCreate(phys_devs[0]); + dev_info_1.CheckCreate(phys_devs[1]); + ASSERT_TRUE(log.find(portability_driver_warning)); + } +} |