Add 32 & 64 bit field to json manifests
authorCharles Giessen <charles@lunarg.com>
Mon, 20 Jun 2022 20:38:56 +0000 (15:38 -0500)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Wed, 22 Jun 2022 16:28:18 +0000 (10:28 -0600)
Allows drivers and layers to specify if they are 32 bit or 64 bit in the
manifest file. This makes the loader able to prune manifests without
loading the library and finding that it failed to load.

docs/LoaderDriverInterface.md
docs/LoaderLayerInterface.md
loader/loader.c
tests/framework/test_util.cpp
tests/framework/test_util.h
tests/loader_regression_tests.cpp

index 12c964a587e4d2a3606b5bafbb5e62905baa777c..1021dd41d29c3b9c251738b8e46ed4c9ac418c54 100644 (file)
@@ -516,6 +516,7 @@ Here is an example driver JSON Manifest file:
    "ICD": {
       "library_path": "path to driver library",
       "api_version": "1.2.205",
+      "library_arch" : "64",
       "is_portability_driver": false
    }
 }
@@ -550,6 +551,14 @@ Here is an example driver JSON Manifest file:
         other than it should end with the appropriate suffix (".DLL" on
         Windows, ".so" on Linux and ".dylib" on macOS).</td>
   </tr>
+  <tr>
+    <td>"library_arch"</td>
+    <td>Optional field which specifies the architecture of the binary associated
+        with "library_path". <br />
+        Allows the loader to quickly determine if the architecture of the driver
+        matches that of the running application. <br />
+        The only valid values are "32" and "64".</td>
+  </tr>
   <tr>
     <td>"api_version" </td>
     <td>The major.minor.patch version number of the maximum Vulkan API supported
@@ -574,7 +583,7 @@ Here is an example driver JSON Manifest file:
 versions of text manifest file format versions, it must have separate JSON files
 for each (all of which may point to the same shared library).
 
-#### Driver Manifest File Versions
+### Driver Manifest File Versions
 
 The current highest supported Layer Manifest file format supported is 1.0.1.
 Information about each version is detailed in the following sub-sections:
@@ -596,6 +605,9 @@ they contain VkPhysicalDevices which support the VK_KHR_portability_subset
 extension. This is an optional field. Omitting the field has the same effect as
 setting the field to `false`.
 
+Added the "library\_arch" field to the driver manifest to allow the loader to
+quickly determine if the driver matches the architecture of the current running
+application. This field is optional.
 
 ##  Driver Vulkan Entry Point Discovery
 
index ba9d6afde8488e43da59312e98fb773b4499c32f..36631684ce179a96fd646247d7450c14cc2e7851 100644 (file)
@@ -1437,11 +1437,12 @@ Here is an example layer JSON Manifest file with a single layer:
 
 ```json
 {
-   "file_format_version" : "1.0.0",
+   "file_format_version" : "1.2.1",
    "layer": {
        "name": "VK_LAYER_LUNARG_overlay",
        "type": "INSTANCE",
        "library_path": "vkOverlayLayer.dll",
+       "library_arch" : "64",
        "api_version" : "1.0.5",
        "implementation_version" : "2",
        "description" : "LunarG HUD layer",
@@ -1708,6 +1709,15 @@ Here's an example of a meta-layer manifest file:
     <td>"layer"/"layers"</td>
     <td><small>N/A</small></td>
   </tr>
+  <td>"library_arch"</td>
+    <td>Optional field which specifies the architecture of the binary associated
+        with "library_path". <br />
+        Allows the loader to quickly determine if the architecture of the layer
+        matches that of the running application. <br />       
+        The only valid values are "32" and "64".</td>
+    <td><small>N/A</small></td>
+  </tr>
+  <tr>
   <tr>
     <td>"name"</td>
     <td>The string used to uniquely identify this layer to applications.</td>
@@ -1764,6 +1774,12 @@ Here's an example of a meta-layer manifest file:
 The current highest supported Layer Manifest file format supported is 1.2.0.
 Information about each version is detailed in the following sub-sections:
 
+### Layer Manifest File Version 1.2.1
+
+Added the "library\_arch" field to the layer manifest to allow the loader to
+quickly determine if the layer matches the architecture of the current running
+application.
+
 #### Layer Manifest File Version 1.2.0
 
 The ability to define the layer settings as defined by the
index 6e565f5aabd8be05fe0a21b4699d9477f1e54e65..fd59f199c39a33c28b642baefcd4400e7ac8805f 100644 (file)
@@ -2256,6 +2256,7 @@ static VkResult loader_read_layer_json(const struct loader_instance *inst, struc
 // instance_extensions
 // device_extensions
 // enable_environment (implicit layers only)
+// library_arch
 #define GET_JSON_OBJECT(node, var) \
     { var = cJSON_GetObjectItem(node, #var); }
 #define GET_JSON_ITEM(inst, node, var)                      \
@@ -2282,6 +2283,7 @@ static VkResult loader_read_layer_json(const struct loader_instance *inst, struc
     char *vkNegotiateLoaderLayerInterfaceVersion = NULL;
     char *spec_version = NULL;
     char **entry_array = NULL;
+    char *library_arch = NULL;
     cJSON *app_keys = NULL;
 
     // Layer interface functions
@@ -2511,6 +2513,16 @@ static VkResult loader_read_layer_json(const struct loader_instance *inst, struc
         }
     }
 
+    GET_JSON_ITEM(inst, layer_node, library_arch)
+    if (library_arch != NULL) {
+        if ((strncmp(library_arch, "32", 2) == 0 && sizeof(void *) != 4) ||
+            (strncmp(library_arch, "64", 2) == 0 && sizeof(void *) != 8)) {
+            loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+                       "Layer library architecture doesn't match the current running architecture, skipping this layer");
+            goto out;
+        }
+    }
+
     result = VK_SUCCESS;
 
 out:
@@ -3538,6 +3550,25 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
                     continue;
                 }
 
+                item = cJSON_GetObjectItem(itemICD, "library_arch");
+                if (item != NULL) {
+                    temp = cJSON_Print(item);
+                    if (NULL != temp) {
+                        // cJSON includes the quotes by default, so we need to look for those here
+                        if ((strncmp(temp, "\"32\"", 4) == 0 && sizeof(void *) != 4) ||
+                            (strncmp(temp, "\"64\"", 4) == 0 && sizeof(void *) != 8)) {
+                            loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+                                       "loader_icd_scan: Driver library architecture doesn't match the current running "
+                                       "architecture, skipping this driver");
+                            loader_instance_heap_free(inst, temp);
+                            cJSON_Delete(json);
+                            json = NULL;
+                            continue;
+                        }
+                    }
+                    loader_instance_heap_free(inst, temp);
+                }
+
                 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);
index 3acc64050844f2893eff51a82c1e9c3f76ff61e4..6b796e7ce8da2dd823daff860638ea43ad2c05a1 100644 (file)
@@ -137,7 +137,12 @@ std::string ManifestICD::get_manifest_str() const {
     out += "    \"ICD\": {\n";
     out += "        \"library_path\": \"" + fs::fixup_backslashes_in_path(lib_path) + "\",\n";
     out += "        \"api_version\": \"" + version_to_string(api_version) + "\",\n";
-    out += "        \"is_portability_driver\": " + to_text(is_portability_driver) + "\n";
+    out += "        \"is_portability_driver\": " + to_text(is_portability_driver);
+    if (!library_arch.empty()) {
+        out += ",\n       \"library_arch\": \"" + library_arch + "\"\n";
+    } else {
+        out += "\n";
+    }
     out += "    }\n";
     out += "}\n";
     return out;
@@ -176,7 +181,9 @@ std::string ManifestLayer::LayerDescription::get_manifest_str() const {
     print_vector_of_strings(out, "override_paths", override_paths);
     print_vector_of_strings(out, "app_keys", app_keys);
     print_list_of_t(out, "pre_instance_functions", pre_instance_functions);
-
+    if (!library_arch.empty()) {
+        out += ",\n\t\t\"library_arch\": \"" + library_arch + "\"";
+    }
     out += "\n\t}";
 
     return out;
@@ -664,4 +671,4 @@ VkDeviceCreateInfo* DeviceCreateInfo::get() noexcept {
     dev.queueCreateInfoCount = static_cast<uint32_t>(device_queue_infos.size());
     dev.pQueueCreateInfos = device_queue_infos.data();
     return &dev;
-}
\ No newline at end of file
+}
index 2ab87645fedf02bf33eae74335ba4b3d2e40798d..3766024147bcdc6fdebeef4a097647cd613364b8 100644 (file)
@@ -543,6 +543,7 @@ struct ManifestICD {
     BUILDER_VALUE(ManifestICD, uint32_t, api_version, 0)
     BUILDER_VALUE(ManifestICD, std::string, lib_path, {})
     BUILDER_VALUE(ManifestICD, bool, is_portability_driver, false)
+    BUILDER_VALUE(ManifestICD, std::string, library_arch, "")
     std::string get_manifest_str() const;
 };
 
@@ -589,6 +590,7 @@ struct ManifestLayer {
         BUILDER_VECTOR(LayerDescription, std::string, override_paths, override_path)
         BUILDER_VECTOR(LayerDescription, FunctionOverride, pre_instance_functions, pre_instance_function)
         BUILDER_VECTOR(LayerDescription, std::string, app_keys, app_key)
+        BUILDER_VALUE(LayerDescription, std::string, library_arch, "")
 
         std::string get_manifest_str() const;
         VkLayerProperties get_layer_properties() const;
@@ -963,4 +965,4 @@ static inline std::string test_platform_executable_path() {
     buffer[ret] = '\0';
     return buffer;
 }
-#endif
\ No newline at end of file
+#endif
index 141c1aa796b9f1d45772261cb29b443174024cae..bd8fdeebf9330aeb100f92efd19a74513d6f23b7 100644 (file)
@@ -1303,6 +1303,42 @@ TEST(TryLoadWrongBinaries, BadExplicitAndImplicit) {
     ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" failed to load.")));
 }
 
+TEST(TryLoadWrongBinaries, WrongArchDriver) {
+    FrameworkEnvironment env{};
+    // Intentionally set the wrong arch
+    env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2}.icd_manifest.set_library_arch(sizeof(void*) == 4 ? "64" : "32"));
+
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+    InstWrapper inst{env.vulkan_functions};
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+    inst.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
+    ASSERT_TRUE(log.find(
+        "loader_icd_scan: Driver library architecture doesn't match the current running architecture, skipping this driver"));
+}
+
+TEST(TryLoadWrongBinaries, WrongArchLayer) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2});
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    const char* layer_name = "TestLayer";
+    env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+                                                         .set_name(layer_name)
+                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+                                                         // Intentionally set the wrong arch
+                                                         .set_library_arch(sizeof(void*) == 4 ? "64" : "32")),
+                           "test_layer.json");
+
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+    InstWrapper inst{env.vulkan_functions};
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+    inst.create_info.add_layer(layer_name);
+    inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
+    ASSERT_TRUE(log.find("Layer library architecture doesn't match the current running architecture, skipping this layer"));
+}
+
 TEST(EnumeratePhysicalDeviceGroups, OneCall) {
     FrameworkEnvironment env{};
     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));