loader: Add validation for apiVersion
authorMark Young <marky@lunarg.com>
Wed, 19 Apr 2017 01:52:18 +0000 (19:52 -0600)
committerMark Young <marky@lunarg.com>
Thu, 29 Jun 2017 17:08:04 +0000 (11:08 -0600)
Add a check to determine if the API version being requested can be
handled by the loader.  If it can't, then we return incompatible driver.
If we can, we continue along our merry way.

An addendum is that we also bumped the Loader/ICD interface version.
This was requested by Nvidia so that the ICDs know that we pay attention
to the version in the loader.  If they don't see the new Loader/ICD
interface version, they will handle the failing on all non-1.0 API
requests.

Change-Id: Icb7dd45e754c9f6a6c8186198333bacc68077b93

include/vulkan/vk_icd.h
loader/LoaderAndLayerInterface.md
loader/loader.c
loader/loader.h
loader/trampoline.c

index 668a4d1..1983e5d 100644 (file)
 //   Version 3 - Add ICD creation/destruction of KHR_surface objects.
 //   Version 4 - Add unknown physical device extension qyering via
 //               vk_icdGetPhysicalDeviceProcAddr.
-#define CURRENT_LOADER_ICD_INTERFACE_VERSION 4
+//   Version 5 - Tells ICDs that the loader is now paying attention to the
+//               application version of Vulkan passed into the ApplicationInfo
+//               structure during vkCreateInstance.  This will tell the ICD
+//               that if the loader is older, it should automatically fail a
+//               call for any API version > 1.0.  Otherwise, the loader will
+//               manually determine if it can support the expected version.
+#define CURRENT_LOADER_ICD_INTERFACE_VERSION 5
 #define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0
 #define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4
 typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion);
index fa8c1d0..cf3f4c6 100644 (file)
@@ -398,6 +398,7 @@ extension or core device entry-points.
 
 
 ##### ABI Versioning
+
 The Vulkan loader library will be distributed in various ways including Vulkan
 SDKs, OS package distributions and Independent Hardware Vendor (IHV) driver
 packages. These details are beyond the scope of this document. However, the name
@@ -1821,6 +1822,7 @@ ICD to properly hand-shake.
     * [Windows and Linux ICD Negotiation](#windows-and-linux-icd-negotiation)
       * [Version Negotiation Between Loader and ICDs](#version-negotiation-between-loader-and-icds)
         * [Interfacing With Legacy ICDs or Loader](#interfacing-with-legacy-icds-or-loader)
+      * [Loader Version 5 Interface Requirements](#loader-version-5-interface-requirements)
       * [Loader Version 4 Interface Requirements](#loader-version-4-interface-requirements)
       * [Loader Version 3 Interface Requirements](#loader-version-3-interface-requirements)
       * [Loader Version 2 Interface Requirements](#loader-version-2-interface-requirements)
@@ -2333,6 +2335,31 @@ is a legacy loader supporting version 0 or 1.  If the loader calls
 the loader only supports version 0.
 
 
+##### Loader Version 5 Interface Requirements
+
+Version 5 of the loader/ICD interface has no changes to the actual interface.
+If the loader requests interface version 5 or greater, it is simply
+an indication to ICDs that the loader is now evaluating if the API Version info
+passed into vkCreateInstance is a valid version for the loader.  If it is not,
+the loader will catch this during vkCreateInstance and fail with a
+VK_ERROR_INCOMPATIBLE_DRIVER error.
+
+On the other hand, if version 5 or newer is not requested by the loader, then it
+indicates to the ICD that the loader is ignorant of the API version being
+requested.  Because of this, it falls on the ICD to validate that the API
+Version is not greater than major = 1 and minor = 0.  If it is, then the ICD
+should automatically fail with a VK_ERROR_INCOMPATIBLE_DRIVER error since the
+loader is a 1.0 loader, and is unaware of the version.
+
+Here is a table of the expected behaviors:
+
+| Loader Supports I/f Version  |  ICD Supports I/f Version  |    Result        |
+| :---: |:---:|------------------------|
+|           <= 4               |           <= 4             | ICD must fail with `VK_ERROR_INCOMPATIBLE_DRIVER` for all vkCreateInstance calls with apiVersion set to > Vulkan 1.0 because both the loader and ICD support interface version <= 4. Otherwise, the ICD should behave as normal. |
+|           <= 4               |           >= 5             | ICD must fail with `VK_ERROR_INCOMPATIBLE_DRIVER` for all vkCreateInstance calls with apiVersion set to > Vulkan 1.0 because the loader is still at interface version <= 4. Otherwise, the ICD should behave as normal.  |
+|           >= 5               |           <= 4             | Loader will fail with `VK_ERROR_INCOMPATIBLE_DRIVER` if it can't handle the apiVersion.  ICD may pass for all apiVersions, but since it's interface is <= 4, it is best if it assumes it needs to do the work of rejecting anything > Vulkan 1.0 and fail with `VK_ERROR_INCOMPATIBLE_DRIVER`. Otherwise, the ICD should behave as normal.  |
+|           >= 5               |           >= 5             | Loader will fail with `VK_ERROR_INCOMPATIBLE_DRIVER` if it can't handle the apiVersion, and ICDs should fail with `VK_ERROR_INCOMPATIBLE_DRIVER` **only if** they can not support the specified apiVersion. Otherwise, the ICD should behave as normal.  |
+
 ##### Loader Version 4 Interface Requirements
 
 The major change to version 4 of the loader/ICD interface is the support of
@@ -2425,7 +2452,7 @@ Loader.  These are referenced throughout the text, but collected here for ease
 of discovery.
 
 | Environment Variable              | Behavior |  Example Format  |
-|----------------|---------------------|----------------------|
+|:---:|---------------------|----------------------|
 | VK_ICD_FILENAMES                  | Force the loader to use the specific ICD JSON files.  The value should contain a list of delimited full path listings to ICD JSON Manifest files.  **NOTE:** If you fail to use the global path to a JSON file, you may encounter issues.  |  `export VK_ICD_FILENAMES=<folder_a>\intel.json:<folder_b>\amd.json`<br/><br/>`set VK_ICD_FILENAMES=<folder_a>\nvidia.json;<folder_b>\mesa.json` |
 | VK_INSTANCE_LAYERS                | Force the loader to add the given layers to the list of Enabled layers normally passed into `vkCreateInstance`.  These layers are added first, and the loader will remove any duplicate layers that appear in both this list as well as that passed into `ppEnabledLayerNames`. | `export VK_INSTANCE_LAYERS=<layer_a>:<layer_b>`<br/><br/>`set VK_INSTANCE_LAYERS=<layer_a>;<layer_b>` |
 | VK_LAYER_PATH                     | Override the loader's standard Layer library search folders and use the provided delimited folders to search for layer Manifest files. | `export VK_LAYER_PATH=<path_a>:<path_b>`<br/><br/>`set VK_LAYER_PATH=<path_a>;<pathb>` |
@@ -2435,7 +2462,7 @@ of discovery.
 ## Glossary of Terms
 
 | Field Name | Field Value |
-|----------------|--------------------|
+|:---:|--------------------|
 | Android Loader | The loader designed to work primarily for the Android OS.  This is generated from a different code-base than the desktop loader.  But, in all important aspects, should be functionally equivalent. |
 | Desktop Loader | The loader designed to work on both Windows and Linux.  This is generated from a different [code-base](#https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers) than the Android loader.  But in all important aspects, should be functionally equivalent. |
 | Core Function | A function that is already part of the Vulkan core specification and not an extension.  For example, vkCreateDevice(). |
index 05183b3..a3f4a59 100644 (file)
@@ -716,8 +716,8 @@ static VkResult loader_add_instance_extensions(const struct loader_instance *ins
 
         bool ext_unsupported = wsi_unsupported_instance_extension(&ext_props[i]);
         if (!ext_unsupported) {
-            (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_MAJOR(ext_props[i].specVersion),
-                           VK_MINOR(ext_props[i].specVersion), VK_PATCH(ext_props[i].specVersion));
+            (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
+                           VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
             loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Instance Extension: %s (%s) version %s", ext_props[i].extensionName,
                        lib_name, spec_version);
 
@@ -751,9 +751,8 @@ static VkResult loader_init_device_extensions(const struct loader_instance *inst
 
     for (i = 0; i < count; i++) {
         char spec_version[64];
-
-        (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_MAJOR(ext_props[i].specVersion),
-                       VK_MINOR(ext_props[i].specVersion), VK_PATCH(ext_props[i].specVersion));
+        (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
+                       VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
         loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
                    phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
         res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
@@ -786,9 +785,8 @@ VkResult loader_add_device_extensions(const struct loader_instance *inst,
         }
         for (i = 0; i < count; i++) {
             char spec_version[64];
-
-            (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_MAJOR(ext_props[i].specVersion),
-                           VK_MINOR(ext_props[i].specVersion), VK_PATCH(ext_props[i].specVersion));
+            (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
+                           VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
             loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
                        lib_name, spec_version);
             res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
index 2c65923..3a80657 100644 (file)
@@ -48,9 +48,6 @@
 #define DEBUG_DISABLE_APP_ALLOCATORS 0
 
 #define MAX_STRING_SIZE 1024
-#define VK_MAJOR(version) (version >> 22)
-#define VK_MINOR(version) ((version >> 12) & 0x3ff)
-#define VK_PATCH(version) (version & 0xfff)
 
 // This is defined in vk_layer.h, but if there's problems we need to create the define
 // here.
index b03ebda..1d6105d 100644 (file)
@@ -227,6 +227,22 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCr
 
     loader_platform_thread_once(&once_init, loader_initialize);
 
+    // Fail if the requested Vulkan apiVersion is > 1.0 since the loader only supports 1.0.
+    // Having pCreateInfo == NULL, pCreateInfo->pApplication == NULL, or
+    // pCreateInfo->pApplicationInfo->apiVersion == 0 all indicate that the application is
+    // only requesting a 1.0 instance, which this loader will always support.
+    uint32_t loader_major_version = 1;
+    uint32_t loader_minor_version = 0;
+    if (NULL != pCreateInfo && NULL != pCreateInfo->pApplicationInfo &&
+        pCreateInfo->pApplicationInfo->apiVersion >= VK_MAKE_VERSION(loader_major_version, loader_minor_version + 1, 0)) {
+        loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "vkCreateInstance:  Called with invalid API version %d.%d.  Loader only supports %d.%d",
+                   VK_VERSION_MAJOR(pCreateInfo->pApplicationInfo->apiVersion),
+                   VK_VERSION_MINOR(pCreateInfo->pApplicationInfo->apiVersion), loader_major_version, loader_minor_version);
+        res = VK_ERROR_INCOMPATIBLE_DRIVER;
+        goto out;
+    }
+
 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
     {
 #else