mirror of
https://github.com/openharmony/third_party_vulkan-loader.git
synced 2026-07-18 16:14:33 -04:00
3f7fe7b7b4
Signed-off-by: andrew0229 <zhangzhao62@huawei.com> Change-Id: Ifc4224db2c6ea7c159d3cabe8f075475d47a41a8
2007 lines
83 KiB
Markdown
2007 lines
83 KiB
Markdown
<!-- markdownlint-disable MD041 -->
|
||
[![Khronos Vulkan][1]][2]
|
||
|
||
[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
|
||
[2]: https://www.khronos.org/vulkan/
|
||
|
||
# Driver interface to the Vulkan Loader <!-- omit from toc -->
|
||
[![Creative Commons][3]][4]
|
||
|
||
<!-- Copyright © 2015-2023 LunarG, Inc. -->
|
||
|
||
[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
|
||
[4]: https://creativecommons.org/licenses/by-nd/4.0/
|
||
|
||
|
||
## Table of Contents <!-- omit from toc -->
|
||
|
||
- [Overview](#overview)
|
||
- [Driver Discovery](#driver-discovery)
|
||
- [Overriding the Default Driver Discovery](#overriding-the-default-driver-discovery)
|
||
- [Additional Driver Discovery](#additional-driver-discovery)
|
||
- [Driver Filtering](#driver-filtering)
|
||
- [Driver Select Filtering](#driver-select-filtering)
|
||
- [Driver Disable Filtering](#driver-disable-filtering)
|
||
- [Exception for Elevated Privileges](#exception-for-elevated-privileges)
|
||
- [Examples](#examples)
|
||
- [On Windows](#on-windows)
|
||
- [On Linux](#on-linux)
|
||
- [On macOS](#on-macos)
|
||
- [Driver Manifest File Usage](#driver-manifest-file-usage)
|
||
- [Driver Discovery on Windows](#driver-discovery-on-windows)
|
||
- [Driver Discovery on Linux](#driver-discovery-on-linux)
|
||
- [Example Linux Driver Search Path](#example-linux-driver-search-path)
|
||
- [Driver Discovery on Fuchsia](#driver-discovery-on-fuchsia)
|
||
- [Driver Discovery on macOS](#driver-discovery-on-macos)
|
||
- [Example macOS Driver Search Path](#example-macos-driver-search-path)
|
||
- [Additional Settings For Driver Debugging](#additional-settings-for-driver-debugging)
|
||
- [Driver Discovery using the`VK_LUNARG_direct_driver_loading` extension](#driver-discovery-using-thevk_lunarg_direct_driver_loading-extension)
|
||
- [How to use `VK_LUNARG_direct_driver_loading`](#how-to-use-vk_lunarg_direct_driver_loading)
|
||
- [Interactions with other driver discovery mechanisms](#interactions-with-other-driver-discovery-mechanisms)
|
||
- [Limitations of `VK_LUNARG_direct_driver_loading`](#limitations-of-vk_lunarg_direct_driver_loading)
|
||
- [Using Pre-Production ICDs or Software Drivers](#using-pre-production-icds-or-software-drivers)
|
||
- [Driver Discovery on Android](#driver-discovery-on-android)
|
||
- [Driver Manifest File Format](#driver-manifest-file-format)
|
||
- [Driver Manifest File Versions](#driver-manifest-file-versions)
|
||
- [Driver Manifest File Version 1.0.0](#driver-manifest-file-version-100)
|
||
- [Driver Manifest File Version 1.0.1](#driver-manifest-file-version-101)
|
||
- [Driver Vulkan Entry Point Discovery](#driver-vulkan-entry-point-discovery)
|
||
- [Driver API Version](#driver-api-version)
|
||
- [Mixed Driver Instance Extension Support](#mixed-driver-instance-extension-support)
|
||
- [Filtering Out Instance Extension Names](#filtering-out-instance-extension-names)
|
||
- [Loader Instance Extension Emulation Support](#loader-instance-extension-emulation-support)
|
||
- [Driver Unknown Physical Device Extensions](#driver-unknown-physical-device-extensions)
|
||
- [Reason for adding `vk_icdGetPhysicalDeviceProcAddr`](#reason-for-adding-vk_icdgetphysicaldeviceprocaddr)
|
||
- [Physical Device Sorting](#physical-device-sorting)
|
||
- [Driver Dispatchable Object Creation](#driver-dispatchable-object-creation)
|
||
- [Handling KHR Surface Objects in WSI Extensions](#handling-khr-surface-objects-in-wsi-extensions)
|
||
- [Loader and Driver Interface Negotiation](#loader-and-driver-interface-negotiation)
|
||
- [Windows, Linux and macOS Driver Negotiation](#windows-linux-and-macos-driver-negotiation)
|
||
- [Version Negotiation Between the Loader and Drivers](#version-negotiation-between-the-loader-and-drivers)
|
||
- [Interfacing With Legacy Drivers or Loaders](#interfacing-with-legacy-drivers-or-loaders)
|
||
- [Loader and Driver Interface Version 7 Requirements](#loader-and-driver-interface-version-7-requirements)
|
||
- [Loader and Driver Interface Version 6 Requirements](#loader-and-driver-interface-version-6-requirements)
|
||
- [Loader and Driver Interface Version 5 Requirements](#loader-and-driver-interface-version-5-requirements)
|
||
- [Loader and Driver Interface Version 4 Requirements](#loader-and-driver-interface-version-4-requirements)
|
||
- [Loader and Driver Interface Version 3 Requirements](#loader-and-driver-interface-version-3-requirements)
|
||
- [Loader and Driver Interface Version 2 Requirements](#loader-and-driver-interface-version-2-requirements)
|
||
- [Loader and Driver Interface Version 1 Requirements](#loader-and-driver-interface-version-1-requirements)
|
||
- [Loader and Driver Interface Version 0 Requirements](#loader-and-driver-interface-version-0-requirements)
|
||
- [Additional Interface Notes:](#additional-interface-notes)
|
||
- [Android Driver Negotiation](#android-driver-negotiation)
|
||
- [Loader implementation of VK\_KHR\_portability\_enumeration](#loader-implementation-of-vk_khr_portability_enumeration)
|
||
- [Loader and Driver Policy](#loader-and-driver-policy)
|
||
- [Number Format](#number-format)
|
||
- [Android Differences](#android-differences)
|
||
- [Requirements of Well-Behaved Drivers](#requirements-of-well-behaved-drivers)
|
||
- [Removed Driver Policies](#removed-driver-policies)
|
||
- [Requirements of a Well-Behaved Loader](#requirements-of-a-well-behaved-loader)
|
||
|
||
|
||
## Overview
|
||
|
||
This is the Driver-centric view of working with the Vulkan loader.
|
||
For the complete overview of all sections of the loader, please refer to the
|
||
[LoaderInterfaceArchitecture.md](LoaderInterfaceArchitecture.md) file.
|
||
|
||
**NOTE:** While many of the interfaces still use the "icd" sub-string to
|
||
identify various behavior associated with drivers, this is purely
|
||
historical and should not indicate that the implementing code do so through
|
||
the traditional ICD interface.
|
||
Granted, the majority of drivers to this date are ICD drivers
|
||
targeting specific GPU hardware.
|
||
|
||
## Driver Discovery
|
||
|
||
Vulkan allows multiple drivers each with one or more devices
|
||
(represented by a Vulkan `VkPhysicalDevice` object) to be used collectively.
|
||
The loader is responsible for discovering available Vulkan drivers on
|
||
the system.
|
||
Given a list of available drivers, the loader can enumerate all the
|
||
physical devices available for an application and return this information to the
|
||
application.
|
||
The process in which the loader discovers the available drivers on a
|
||
system is platform-dependent.
|
||
Windows, Linux, Android, and macOS Driver Discovery details are listed
|
||
below.
|
||
|
||
### Overriding the Default Driver Discovery
|
||
|
||
There may be times that a developer wishes to force the loader to use a specific
|
||
Driver.
|
||
This could be for many reasons including using a beta driver, or forcing the
|
||
loader to skip a problematic driver.
|
||
In order to support this, the loader can be forced to look at specific
|
||
drivers with either the `VK_DRIVER_FILES` or the older `VK_ICD_FILENAMES`
|
||
environment variable.
|
||
Both these environment variables behave the same, but `VK_ICD_FILENAMES`
|
||
should be considered deprecated.
|
||
If both `VK_DRIVER_FILES` and `VK_ICD_FILENAMES` environment variables are
|
||
present, then the newer `VK_DRIVER_FILES` will be used, and the values in
|
||
`VK_ICD_FILENAMES` will be ignored.
|
||
|
||
The `VK_DRIVER_FILES` environment variable is a list of paths to Driver Manifest
|
||
files, containing the full path to the driver JSON Manifest file, and/or paths
|
||
to folders containing Driver Manifest files.
|
||
This list is colon-separated on Linux and macOS, and semicolon-separated on
|
||
Windows.
|
||
Typically, `VK_DRIVER_FILES` will only contain a full pathname to one info
|
||
file for a single driver.
|
||
A separator (colon or semicolon) is only used if more than one driver is needed.
|
||
|
||
### Additional Driver Discovery
|
||
|
||
There may be times that a developer wishes to force the loader to use a specific
|
||
Driver in addition to the standard drivers (without replacing the standard
|
||
search paths.
|
||
The `VK_ADD_DRIVER_FILES` environment variable can be used to add a list of
|
||
Driver Manifest files, containing the full path to the driver JSON Manifest
|
||
file, and/or paths to folders containing Driver Manifest files.
|
||
This list is colon-separated on Linux and macOS, and semicolon-separated on
|
||
Windows.
|
||
It will be added prior to the standard driver search files.
|
||
If `VK_DRIVER_FILES` or `VK_ICD_FILENAMES` is present, then
|
||
`VK_ADD_DRIVER_FILES` will not be used by the loader and any values will be
|
||
ignored.
|
||
|
||
### Driver Filtering
|
||
|
||
**NOTE:** This functionality is only available with Loaders built with version
|
||
1.3.234 of the Vulkan headers and later.
|
||
|
||
The loader supports filter environment variables which can forcibly select and
|
||
disable known drivers.
|
||
Known driver manifests are those files that are already found by the loader
|
||
taking into account default search paths and other environment variables (like
|
||
`VK_ICD_FILENAMES` or `VK_ADD_DRIVER_FILES`).
|
||
|
||
The filter variables will be compared against the driver's manifest filename.
|
||
|
||
The filters must also follow the behaviors define in the
|
||
[Filter Environment Variable Behaviors](LoaderInterfaceArchitecture.md#filter-environment-variable-behaviors)
|
||
section of the [LoaderLayerInterface](LoaderLayerInterface.md) document.
|
||
|
||
#### Driver Select Filtering
|
||
|
||
The driver select environment variable `VK_LOADER_DRIVERS_SELECT` is a
|
||
comma-delimited list of globs to search for in known drivers.
|
||
|
||
If a driver is not selected when using the `VK_LOADER_DRIVERS_SELECT` filter,
|
||
and loader logging is set to emit either warnings or driver messages, then a
|
||
message will show for each driver that has been ignored.
|
||
This message will look like the following:
|
||
|
||
```
|
||
WARNING | DRIVER: Driver "intel_icd.x86_64.json" ignored because not selected by env var 'VK_LOADER_DRIVERS_SELECT'
|
||
```
|
||
|
||
If no drivers are found with a manifest filename that matches any of the
|
||
provided globs, then no driver is enabled and may result in failures for
|
||
any Vulkan application that is run.
|
||
|
||
#### Driver Disable Filtering
|
||
|
||
The driver disable environment variable `VK_LOADER_DRIVERS_DISABLE` is a
|
||
comma-delimited list of globs to search for in known drivers.
|
||
|
||
When a driver is disabled using the `VK_LOADER_DRIVERS_DISABLE` filter, and
|
||
loader logging is set to emit either warnings or driver messages, then a message
|
||
will show for each driver that has been forcibly disabled.
|
||
This message will look like the following:
|
||
|
||
```
|
||
WARNING | DRIVER: Driver "radeon_icd.x86_64.json" ignored because it was disabled by env var 'VK_LOADER_DRIVERS_DISABLE'
|
||
```
|
||
|
||
If no drivers are found with a manifest filename that matches any of the
|
||
provided globs, then no driver is disabled.
|
||
|
||
### Exception for Elevated Privileges
|
||
|
||
For security reasons, `VK_ICD_FILENAMES`, `VK_DRIVER_FILES`, and
|
||
`VK_ADD_DRIVER_FILES` are all ignored if running the Vulkan application
|
||
with elevated privileges.
|
||
This is because they may insert new libraries into the executable process that
|
||
are not normally found by the loader.
|
||
Because of this, these environment variables can only be used for applications
|
||
that do not use elevated privileges.
|
||
|
||
For more information see
|
||
[Elevated Privilege Caveats](LoaderInterfaceArchitecture.md#elevated-privilege-caveats)
|
||
in the top-level
|
||
[LoaderInterfaceArchitecture.md](LoaderInterfaceArchitecture.md) document.
|
||
|
||
#### Examples
|
||
|
||
In order to use the setting, simply set it to a properly delimited list of
|
||
Driver Manifest files.
|
||
In this case, please provide the global path to these files to reduce issues.
|
||
|
||
For example:
|
||
|
||
##### On Windows
|
||
|
||
```
|
||
set VK_DRIVER_FILES=\windows\system32\nv-vk64.json
|
||
```
|
||
|
||
This is an example which is using the `VK_DRIVER_FILES` override on Windows to
|
||
point to the Nvidia Vulkan Driver's Manifest file.
|
||
|
||
```
|
||
set VK_ADD_DRIVER_FILES=\windows\system32\nv-vk64.json
|
||
```
|
||
|
||
This is an example which is using the `VK_ADD_DRIVER_FILES` on Windows to
|
||
point to the Nvidia Vulkan Driver's Manifest file which will be loaded first
|
||
before all other drivers.
|
||
|
||
##### On Linux
|
||
|
||
```
|
||
export VK_DRIVER_FILES=/home/user/dev/mesa/share/vulkan/icd.d/intel_icd.x86_64.json
|
||
```
|
||
|
||
This is an example which is using the `VK_DRIVER_FILES` override on Linux to
|
||
point to the Intel Mesa Driver's Manifest file.
|
||
|
||
```
|
||
export VK_ADD_DRIVER_FILES=/home/user/dev/mesa/share/vulkan/icd.d/intel_icd.x86_64.json
|
||
```
|
||
|
||
This is an example which is using the `VK_ADD_DRIVER_FILES` on Linux to
|
||
point to the Intel Mesa Driver's Manifest file which will be loaded first
|
||
before all other drivers.
|
||
|
||
##### On macOS
|
||
|
||
```
|
||
export VK_DRIVER_FILES=/home/user/MoltenVK/Package/Latest/MoltenVK/macOS/MoltenVK_icd.json
|
||
```
|
||
|
||
This is an example which is using the `VK_DRIVER_FILES` override on macOS to
|
||
point to an installation and build of the MoltenVK GitHub repository that
|
||
contains the MoltenVK driver.
|
||
|
||
See the
|
||
[Table of Debug Environment Variables](LoaderInterfaceArchitecture.md#table-of-debug-environment-variables)
|
||
in the [LoaderInterfaceArchitecture.md document](LoaderInterfaceArchitecture.md)
|
||
for more details
|
||
|
||
|
||
### Driver Manifest File Usage
|
||
|
||
As with layers, on Windows, Linux and macOS systems, JSON-formatted manifest
|
||
files are used to store driver information.
|
||
In order to find system-installed drivers, the Vulkan loader will read the JSON
|
||
files to identify the names and attributes of each driver.
|
||
Notice that Driver Manifest files are much simpler than the corresponding
|
||
layer Manifest files.
|
||
|
||
See the
|
||
[Current Driver Manifest File Format](#driver-manifest-file-format)
|
||
section for more details.
|
||
|
||
|
||
### Driver Discovery on Windows
|
||
|
||
In order to find available drivers (including installed ICDs), the
|
||
loader scans through registry keys specific to Display Adapters and all Software
|
||
Components associated with these adapters for the locations of JSON manifest
|
||
files.
|
||
These keys are located in device keys created during driver installation and
|
||
contain configuration information for base settings, including OpenGL and
|
||
Direct3D locations.
|
||
|
||
The Device Adapter and Software Component key paths will be obtained by first
|
||
enumerating DXGI adapters.
|
||
Should that fail it will use the PnP Configuration Manager API.
|
||
The `000X` key will be a numbered key, where each device is assigned a different
|
||
number.
|
||
|
||
```
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{Adapter GUID}\000X\VulkanDriverName
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{SoftwareComponent GUID}\000X\VulkanDriverName
|
||
```
|
||
|
||
In addition, on 64-bit systems there may be another set of registry values,
|
||
listed below.
|
||
These values record the locations of 32-bit layers on 64-bit operating systems,
|
||
in the same way as the Windows-on-Windows functionality.
|
||
|
||
```
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{Adapter GUID}\000X\VulkanDriverNameWow
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{SoftwareComponent GUID}\000X\VulkanDriverNameWow
|
||
```
|
||
|
||
If any of the above values exist and is of type `REG_SZ`, the loader will open
|
||
the JSON manifest file specified by the key value.
|
||
Each value must be a full absolute path to a JSON manifest file.
|
||
The values may also be of type `REG_MULTI_SZ`, in which case the value will be
|
||
interpreted as a list of paths to JSON manifest files.
|
||
|
||
Additionally, the Vulkan loader will scan the values in the following Windows
|
||
registry key:
|
||
|
||
```
|
||
HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\Drivers
|
||
```
|
||
|
||
For 32-bit applications on 64-bit Windows, the loader scan's the 32-bit
|
||
registry location:
|
||
|
||
```
|
||
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Khronos\Vulkan\Drivers
|
||
```
|
||
|
||
Every driver in these locations should be given as a DWORD, with value 0, where
|
||
the name of the value is the full path to a JSON manifest file.
|
||
The Vulkan loader will attempt to open each manifest file to obtain the
|
||
information about a driver's shared library (".dll") file.
|
||
|
||
For example, let us assume the registry contains the following data:
|
||
|
||
```
|
||
[HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\Drivers\]
|
||
|
||
"C:\vendor a\vk_vendor_a.json"=dword:00000000
|
||
"C:\windows\system32\vendor_b_vk.json"=dword:00000001
|
||
"C:\windows\system32\vendor_c_icd.json"=dword:00000000
|
||
```
|
||
|
||
In this case, the loader will step through each entry, and check the value.
|
||
If the value is 0, then the loader will attempt to load the file.
|
||
In this case, the loader will open the first and last listings, but not the
|
||
middle.
|
||
This is because the value of 1 for vendor_b_vk.json disables the driver.
|
||
|
||
Additionally, the Vulkan loader will scan the system for well-known Windows
|
||
AppX/MSIX packages.
|
||
If a package is found, the loader will scan the root directory of this installed
|
||
package for JSON manifest files. At this time, the only package that is known is
|
||
Microsoft's
|
||
[OpenCL™ and OpenGL® Compatibility Pack](https://apps.microsoft.com/store/detail/9NQPSL29BFFF?hl=en-us&gl=US).
|
||
|
||
The Vulkan loader will open each enabled manifest file found to obtain the name
|
||
or pathname of a driver's shared library (".DLL") file.
|
||
|
||
Drivers should use the registry locations from the PnP Configuration
|
||
Manager wherever practical.
|
||
Typically, this is most important for drivers, and the location clearly
|
||
ties the driver to a given device.
|
||
The `SOFTWARE\Khronos\Vulkan\Drivers` location is the older method for locating
|
||
drivers, but is the primary location for software based drivers.
|
||
|
||
See the
|
||
[Driver Manifest File Format](#driver-manifest-file-format)
|
||
section for more details.
|
||
|
||
|
||
### Driver Discovery on Linux
|
||
|
||
On Linux, the Vulkan loader will scan for Driver Manifest files using
|
||
environment variables or corresponding fallback values if the corresponding
|
||
environment variable is not defined:
|
||
|
||
<table style="width:100%">
|
||
<tr>
|
||
<th>Search Order</th>
|
||
<th>Directory/Environment Variable</th>
|
||
<th>Fallback</th>
|
||
<th>Additional Notes</th>
|
||
</tr>
|
||
<tr>
|
||
<td>1</td>
|
||
<td>$XDG_CONFIG_HOME</td>
|
||
<td>$HOME/.config</td>
|
||
<td><b>This path is ignored when running with elevated privileges such as
|
||
setuid, setgid, or filesystem capabilities</b>.<br/>
|
||
This is done because under these scenarios it is not safe to trust
|
||
that the environment variables are non-malicious.<br/>
|
||
See <a href="LoaderInterfaceArchitecture.md#elevated-privilege-caveats">
|
||
Elevated Privilege Caveats</a> for more information.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>1</td>
|
||
<td>$XDG_CONFIG_DIRS</td>
|
||
<td>/etc/xdg</td>
|
||
<td></td>
|
||
</tr>
|
||
<tr>
|
||
<td>2</td>
|
||
<td>SYSCONFDIR</td>
|
||
<td>/etc</td>
|
||
<td>Compile-time option set to possible location of drivers
|
||
installed from non-Linux-distribution-provided packages.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>3</td>
|
||
<td>EXTRASYSCONFDIR</td>
|
||
<td>/etc</td>
|
||
<td>Compile-time option set to possible location of drivers
|
||
installed from non-Linux-distribution-provided packages.
|
||
Typically only set if SYSCONFDIR is set to something other than /etc
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>4</td>
|
||
<td>$XDG_DATA_HOME</td>
|
||
<td>$HOME/.local/share</td>
|
||
<td><b>This path is ignored when running with elevated privileges such as
|
||
setuid, setgid, or filesystem capabilities</b>.<br/>
|
||
This is done because under these scenarios it is not safe to trust
|
||
that the environment variables are non-malicious.<br/>
|
||
See <a href="LoaderInterfaceArchitecture.md#elevated-privilege-caveats">
|
||
Elevated Privilege Caveats</a> for more information.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>5</td>
|
||
<td>$XDG_DATA_DIRS</td>
|
||
<td>/usr/local/share/:/usr/share/</td>
|
||
<td></td>
|
||
</tr>
|
||
</table>
|
||
|
||
The directory lists are concatenated together using the standard platform path
|
||
separator (:).
|
||
The loader then selects each path, and applies the "/vulkan/icd.d" suffix onto
|
||
each and looks in that specific folder for manifest files.
|
||
|
||
The Vulkan loader will open each manifest file found to obtain the name or
|
||
pathname of a driver's shared library (".so") file.
|
||
|
||
**NOTE** While the order of folders searched for manifest files is well
|
||
defined, the order contents are read by the loader in each directory is
|
||
[random due to the behavior of readdir](https://www.ibm.com/support/pages/order-directory-contents-returned-calls-readdir).
|
||
|
||
See the
|
||
[Driver Manifest File Format](#driver-manifest-file-format)
|
||
section for more details.
|
||
|
||
It is also important to note that while `VK_DRIVER_FILES` will point the loader
|
||
to finding the manifest files, it does not guarantee the library files mentioned
|
||
by the manifest will immediately be found.
|
||
Often, the Driver Manifest file will point to the library file using a
|
||
relative or absolute path.
|
||
When a relative or absolute path is used, the loader can typically find the
|
||
library file without querying the operating system.
|
||
However, if a library is listed only by name, the loader may not find it,
|
||
unless the driver is installed placing the library in an operating system
|
||
searchable default location.
|
||
If problems occur finding a library file associated with a driver, try updating
|
||
the `LD_LIBRARY_PATH` environment variable to point at the location of the
|
||
corresponding `.so` file.
|
||
|
||
|
||
#### Example Linux Driver Search Path
|
||
|
||
For a fictional user "me" the Driver Manifest search path might look
|
||
like the following:
|
||
|
||
```
|
||
/home/me/.config/vulkan/icd.d
|
||
/etc/xdg/vulkan/icd.d
|
||
/usr/local/etc/vulkan/icd.d
|
||
/etc/vulkan/icd.d
|
||
/home/me/.local/share/vulkan/icd.d
|
||
/usr/local/share/vulkan/icd.d
|
||
/usr/share/vulkan/icd.d
|
||
```
|
||
|
||
|
||
### Driver Discovery on Fuchsia
|
||
|
||
On Fuchsia, the Vulkan loader will scan for manifest files using environment
|
||
variables or corresponding fallback values if the corresponding environment
|
||
variable is not defined in the same way as
|
||
[Linux](#linux-driver-discovery).
|
||
The **only** difference is that Fuchsia does not allow fallback values for
|
||
*$XDG_DATA_DIRS* or *$XDG_HOME_DIRS*.
|
||
|
||
|
||
### Driver Discovery on macOS
|
||
|
||
On macOS, the Vulkan loader will scan for Driver Manifest files using
|
||
the application resource folder as well as environment variables or
|
||
corresponding fallback values if the corresponding environment variable is not
|
||
defined.
|
||
The order is similar to the search path on Linux with the exception that
|
||
the application's bundle resources are searched first:
|
||
`(bundle)/Contents/Resources/`.
|
||
|
||
System installed drivers will be ignored if drivers are found inside of the app
|
||
bundle.
|
||
This is because there is not a standard mechanism in which to distinguish drivers
|
||
that happen to be duplicates.
|
||
For example, MoltenVK is commonly placed inside application bundles.
|
||
If there exists a system installed MoltenVK, the loader will load both the app
|
||
bundled and the system installed MoltenVK, leading to potential issues or crashes.
|
||
Drivers found through environment variables, such as `VK_DRIVER_FILES`, will be
|
||
used regardless of whether there are bundled drivers present or not.
|
||
|
||
|
||
#### Example macOS Driver Search Path
|
||
|
||
For a fictional user "Me" the Driver Manifest search path might look
|
||
like the following:
|
||
|
||
```
|
||
<bundle>/Contents/Resources/vulkan/icd.d
|
||
/Users/Me/.config/vulkan/icd.d
|
||
/etc/xdg/vulkan/icd.d
|
||
/usr/local/etc/vulkan/icd.d
|
||
/etc/vulkan/icd.d
|
||
/Users/Me/.local/share/vulkan/icd.d
|
||
/usr/local/share/vulkan/icd.d
|
||
/usr/share/vulkan/icd.d
|
||
```
|
||
|
||
|
||
#### Additional Settings For Driver Debugging
|
||
|
||
Sometimes, the driver may encounter issues when loading.
|
||
A useful option may be to enable the `LD_BIND_NOW` environment variable
|
||
to debug the issue.
|
||
This forces every dynamic library's symbols to be fully resolved on load.
|
||
If there is a problem with a driver missing symbols on the current system, this
|
||
will expose it and cause the Vulkan loader to fail on loading the driver.
|
||
It is recommended that `LD_BIND_NOW` along with `VK_LOADER_DEBUG=error,warn`
|
||
to expose any issues.
|
||
|
||
### Driver Discovery using the`VK_LUNARG_direct_driver_loading` extension
|
||
|
||
The `VK_LUNARG_direct_driver_loading` extension allows for applications to
|
||
provide a driver or drivers to the Loader during vkCreateInstance.
|
||
This allows drivers to be included with an application without requiring
|
||
installation and is capable of being used in any execution environment, such as
|
||
a process running with elevated privileges.
|
||
|
||
When calling `vkEnumeratePhysicalDevices` with the
|
||
`VK_LUNARG_direct_driver_loading` extension enabled, the `VkPhysicalDevice`s
|
||
from system installed drivers and environment variable specified drivers will
|
||
appear before any `VkPhysicalDevice`s that originate from drivers from the
|
||
`VkDirectDriverLoadingListLUNARG::pDrivers` list.
|
||
|
||
#### How to use `VK_LUNARG_direct_driver_loading`
|
||
|
||
To use this extension, it must first be enabled on the VkInstance.
|
||
This requires enabling the `VK_LUNARG_direct_driver_loading` extension through
|
||
the `enabledExtensionCount` and `ppEnabledExtensionNames`members of
|
||
`VkInstanceCreateInfo`.
|
||
|
||
```c
|
||
const char* extensions[] = {VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME, <other extensions>};
|
||
VkInstanceCreateInfo instance_create_info = {};
|
||
instance_create_info.enabledExtensionCount = <size of extension list>;
|
||
instance_create_info.ppEnabledExtensionNames = extensions;
|
||
```
|
||
|
||
The `VkDirectDriverLoadingInfoLUNARG` structure contains a
|
||
`VkDirectDriverLoadingFlagsLUNARG` member (reserved for future use) and a
|
||
`PFN_vkGetInstanceProcAddrLUNARG` member which provides the loader with the
|
||
function pointer for the driver's `vkGetInstanceProcAddr`.
|
||
|
||
The `VkDirectDriverLoadingListLUNARG` structure contains a count and pointer
|
||
members which provide the size of and pointer to an application provided array of
|
||
`VkDirectDriverLoadingInfoLUNARG` structures.
|
||
|
||
Creating those structures looks like the following
|
||
```c
|
||
VkDirectDriverLoadingInfoLUNARG direct_loading_info = {};
|
||
direct_loading_info.sType = VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG
|
||
direct_loading_info.pfnGetInstanceProcAddr = <put the PFN_vkGetInstanceProcAddr of the driver here>
|
||
|
||
VkDirectDriverLoadingListLUNARG direct_driver_list = {};
|
||
direct_driver_list.sType = VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG;
|
||
direct_driver_list.mode = VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG; // or VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG
|
||
direct_driver_list.driverCount = 1;
|
||
direct_driver_list.pDrivers = &direct_loading_info; // can include multiple drivers here if so desired
|
||
```
|
||
|
||
The `VkDirectDriverLoadingListLUNARG` structure contains the enum
|
||
`VkDirectDriverLoadingModeLUNARG`.
|
||
There are two modes:
|
||
* `VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG` - specifies that the only drivers
|
||
to be loaded will come from the `VkDirectDriverLoadingListLUNARG` structure.
|
||
* `VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG` - specifies that drivers
|
||
from the `VkDirectDriverLoadingModeLUNARG` structure will be used in addition to
|
||
any system installed drivers and environment variable specified drivers.
|
||
|
||
|
||
|
||
Then, the `VkDirectDriverLoadingListLUNARG` structure *must* be appended to the
|
||
`pNext` chain of `VkInstanceCreateInfo`.
|
||
|
||
```c
|
||
instance_create_info.pNext = (const void*)&direct_driver_list;
|
||
```
|
||
|
||
Finally, create the instance like normal.
|
||
|
||
#### Interactions with other driver discovery mechanisms
|
||
|
||
If the `VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG` mode is specified in the
|
||
`VkDirectDriverLoadingListLUNARG` structure, then no system installed drivers
|
||
are loaded.
|
||
This applies equally to all platforms.
|
||
Additionally, the following environment variables have no effect:
|
||
|
||
* `VK_DRIVER_FILES`
|
||
* `VK_ICD_FILENAMES`
|
||
* `VK_ADD_DRIVER_FILES`
|
||
* `VK_LOADER_DRIVERS_SELECT`
|
||
* `VK_LOADER_DRIVERS_DISABLE`
|
||
|
||
Exclusive mode will also disable MacOS bundle manifest discovery of drivers.
|
||
|
||
#### Limitations of `VK_LUNARG_direct_driver_loading`
|
||
|
||
Because `VkDirectDriverLoadingListLUNARG` is provided to the loader at instance
|
||
creation, there is no mechanism for the loader to query the list of instance
|
||
extensions that originate from `VkDirectDriverLoadingListLUNARG` drivers during
|
||
`vkEnumerateInstanceExtensionProperties`.
|
||
Applications can instead manually load the `vkEnumerateInstanceExtensionProperties`
|
||
function pointer directly from the drivers the application provides to the loader
|
||
using the `pfnGetInstanceProcAddrLUNARG` for each driver.
|
||
Then the application can call each driver's
|
||
`vkEnumerateInstanceExtensionProperties` and append non-duplicate entriees to the
|
||
list from the loader's `vkEnumerateInstanceExtensionProperties` to get the full
|
||
list of supported instance extensions.
|
||
Alternatively, because the Application is providing drivers, it is reasonable for
|
||
the application to already know which instance extensions are available with the
|
||
provided drivers, preventing the need to manually query them.
|
||
|
||
However, there are limitations.
|
||
If there are any active implicit layers which intercept
|
||
`vkEnumerateInstanceExtensionProperties` to remove unsupported extensions, then
|
||
those layers will not be able to remove unsupported extensions from drivers that
|
||
are provided by the application.
|
||
This is due to `vkEnumerateInstanceExtensionProperties` not having a mechanism
|
||
to extend it.
|
||
|
||
|
||
### Using Pre-Production ICDs or Software Drivers
|
||
|
||
Both software and pre-production ICDs can use an alternative mechanism to
|
||
detect their drivers.
|
||
Independent Hardware Vendor (IHV) may not want to fully install a pre-production
|
||
ICD and so it can't be found in the standard location.
|
||
For example, a pre-production ICD may simply be a shared library in the
|
||
developer's build tree.
|
||
In this case, there should be a way to allow developers to point to such an
|
||
ICD without modifying the system-installed ICD(s) on their system.
|
||
|
||
This need is met with the use of the `VK_DRIVER_FILES` environment variable,
|
||
which will override the mechanism used for finding system-installed
|
||
drivers.
|
||
|
||
In other words, only the drivers listed in `VK_DRIVER_FILES` will be
|
||
used.
|
||
|
||
See
|
||
[Overriding the Default Driver Discovery](#overriding-the-default-driver-discovery)
|
||
for more information on this.
|
||
|
||
|
||
### Driver Discovery on Android
|
||
|
||
The Android loader lives in the system library folder.
|
||
The location cannot be changed.
|
||
The loader will load the driver via `hw_get_module` with the ID of "vulkan".
|
||
**Due to security policies in Android, none of this can be modified under**
|
||
**normal use.**
|
||
|
||
|
||
## Driver Manifest File Format
|
||
|
||
The following section discusses the details of the Driver Manifest JSON file
|
||
format.
|
||
The JSON file itself does not have any requirements for naming.
|
||
The only requirement is that the extension suffix of the file is ".json".
|
||
|
||
Here is an example driver JSON Manifest file:
|
||
|
||
```json
|
||
{
|
||
"file_format_version": "1.0.1",
|
||
"ICD": {
|
||
"library_path": "path to driver library",
|
||
"api_version": "1.2.205",
|
||
"library_arch" : "64",
|
||
"is_portability_driver": false
|
||
}
|
||
}
|
||
```
|
||
|
||
<table style="width:100%">
|
||
<tr>
|
||
<th>Field Name</th>
|
||
<th>Field Value</th>
|
||
</tr>
|
||
<tr>
|
||
<td>"file_format_version"</td>
|
||
<td>The JSON format major.minor.patch version number of this file.<br/>
|
||
Supported versions are: 1.0.0 and 1.0.1.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>"ICD"</td>
|
||
<td>The identifier used to group all driver information together.
|
||
<br/>
|
||
<b>NOTE:</b> Even though this is labelled <i>ICD</i> it is historical
|
||
and just as accurate to use for other drivers.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>"library_path"</td>
|
||
<td>The "library_path" specifies either a filename, a relative pathname, or
|
||
a full pathname to a driver shared library file. <br />
|
||
If "library_path" specifies a relative pathname, it is relative to the
|
||
path of the JSON manifest file. <br />
|
||
If "library_path" specifies a filename, the library must live in the
|
||
system's shared object search path. <br />
|
||
There are no rules about the name of the driver's shared library 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
|
||
by the driver.
|
||
However, just because the driver supports the specific Vulkan API
|
||
version, it does not guarantee that the hardware on a user's system can
|
||
support that version.
|
||
Information on what the underlying physical device can support must be
|
||
queried by the user using the <i>vkGetPhysicalDeviceProperties</i> API
|
||
call.<br/>
|
||
For example: 1.0.33.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>"is_portability_driver" </td>
|
||
<td>Defines whether the driver contains any VkPhysicalDevices which
|
||
implement the VK_KHR_portability_subset extension.<br/>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
**NOTE:** If the same driver shared library supports multiple, incompatible
|
||
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
|
||
|
||
The current highest supported Layer Manifest file format supported is 1.0.1.
|
||
Information about each version is detailed in the following sub-sections:
|
||
|
||
#### Driver Manifest File Version 1.0.0
|
||
|
||
The initial version of the Driver Manifest file specified the basic
|
||
format and fields of a layer JSON file.
|
||
The fields supported in version 1.0.0 of the file format include:
|
||
* "file\_format\_version"
|
||
* "ICD"
|
||
* "library\_path"
|
||
* "api\_version"
|
||
|
||
#### Driver Manifest File Version 1.0.1
|
||
|
||
Added the `is_portability_driver` boolean field for drivers to self report that
|
||
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
|
||
|
||
The Vulkan symbols exported by a driver must not clash with the loader's
|
||
exported Vulkan symbols.
|
||
Because of this, all drivers must export the following function that is
|
||
used for discovery of driver Vulkan entry-points.
|
||
This entry-point is not a part of the Vulkan API itself, only a private
|
||
interface between the loader and drivers for version 1 and higher
|
||
interfaces.
|
||
|
||
```cpp
|
||
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
|
||
vk_icdGetInstanceProcAddr(
|
||
VkInstance instance,
|
||
const char* pName);
|
||
```
|
||
|
||
This function has very similar semantics to `vkGetInstanceProcAddr`.
|
||
`vk_icdGetInstanceProcAddr` returns valid function pointers for all the
|
||
global-level and instance-level Vulkan functions, and also for
|
||
`vkGetDeviceProcAddr`.
|
||
Global-level functions are those which contain no dispatchable object as the
|
||
first parameter, such as `vkCreateInstance` and
|
||
`vkEnumerateInstanceExtensionProperties`.
|
||
The driver must support querying global-level entry points by calling
|
||
`vk_icdGetInstanceProcAddr` with a NULL `VkInstance` parameter.
|
||
Instance-level functions are those that have either `VkInstance`, or
|
||
`VkPhysicalDevice` as the first parameter dispatchable object.
|
||
Both core entry points and any instance extension entry points the
|
||
driver supports should be available via `vk_icdGetInstanceProcAddr`.
|
||
Future Vulkan instance extensions may define and use new instance-level
|
||
dispatchable objects other than `VkInstance` and `VkPhysicalDevice`, in which
|
||
case extension entry points using these newly defined dispatchable objects must
|
||
be queryable via `vk_icdGetInstanceProcAddr`.
|
||
|
||
All other Vulkan entry points must either:
|
||
* NOT be exported directly from the driver library
|
||
* or NOT use the official Vulkan function names if they are exported
|
||
|
||
This requirement is for driver libraries that include other functionality (such
|
||
as OpenGL) and thus could be loaded by the application prior to when the Vulkan
|
||
loader library is loaded by the application.
|
||
|
||
Beware of interposing by dynamic OS library loaders if the official Vulkan
|
||
names are used.
|
||
On Linux, if official names are used, the driver library must be linked with
|
||
`-Bsymbolic`.
|
||
|
||
|
||
## Driver API Version
|
||
|
||
When an application calls `vkCreateInstance`, it can optionally include a
|
||
`VkApplicationInfo` struct, which includes an `apiVersion` field.
|
||
A Vulkan 1.0 driver was required to return `VK_ERROR_INCOMPATIBLE_DRIVER` if it
|
||
did not support the API version that the user passed.
|
||
Beginning with Vulkan 1.1, drivers are not allowed to return this error
|
||
for any value of `apiVersion`.
|
||
This creates a problem when working with multiple drivers, where one is
|
||
a 1.0 driver and another is newer.
|
||
|
||
A loader that is newer than 1.0 will always give the version it supports when
|
||
the application calls `vkEnumerateInstanceVersion`, regardless of the API
|
||
version supported by the drivers on the system.
|
||
This means that when the application calls `vkCreateInstance`, the loader will
|
||
be forced to pass a copy of the `VkApplicationInfo` struct where `apiVersion` is
|
||
1.0 to any 1.0 drivers in order to prevent an error.
|
||
To determine if this must be done, the loader will perform the following steps:
|
||
|
||
1. Check the driver's JSON manifest file for the "api_version" field.
|
||
2. If the JSON version is greater than or equal to 1.1, Load the driver's
|
||
dynamic library
|
||
3. Call the driver's `vkGetInstanceProcAddr` command to get a pointer to
|
||
`vkEnumerateInstanceVersion`
|
||
4. If the pointer to `vkEnumerateInstanceVersion` is not `NULL`, it will be
|
||
called to get the driver's supported API version
|
||
|
||
The driver will be treated as a 1.0 driver if any of the following conditions
|
||
are met:
|
||
|
||
- The JSON manifest's "api_version" field is less that version 1.1
|
||
- The function pointer to `vkEnumerateInstanceVersion` is `NULL`
|
||
- The version returned by `vkEnumerateInstanceVersion` is less than 1.1
|
||
- `vkEnumerateInstanceVersion` returns anything other than `VK_SUCCESS`
|
||
|
||
If the driver only supports Vulkan 1.0, the loader will ensure that any
|
||
`VkApplicationInfo` struct that is passed to the driver will have an
|
||
`apiVersion` field set to Vulkan 1.0.
|
||
Otherwise, the loader will pass the struct to the driver without any
|
||
changes.
|
||
|
||
|
||
## Mixed Driver Instance Extension Support
|
||
|
||
On a system with more than one driver, a special case can arise.
|
||
Some drivers may expose an instance extension that the loader is already
|
||
aware of.
|
||
Other drivers on that same system may not support the same instance
|
||
extension.
|
||
|
||
In that scenario, the loader has some additional responsibilities:
|
||
|
||
|
||
### Filtering Out Instance Extension Names
|
||
|
||
During a call to `vkCreateInstance`, the list of requested instance extensions
|
||
is passed down to each driver.
|
||
Since the driver may not support one or more of these instance extensions, the
|
||
loader will filter out any instance extensions that are not supported by the
|
||
driver.
|
||
This is done per driver since different drivers may support different instance
|
||
extensions.
|
||
|
||
|
||
### Loader Instance Extension Emulation Support
|
||
|
||
In the same scenario, the loader must emulate the instance extension
|
||
entry-points, to the best of its ability, for each driver that does not support
|
||
an instance extension directly.
|
||
This must work correctly when combined with calling into the other
|
||
drivers which do support the extension natively.
|
||
In this fashion, the application will be unaware of what drivers are
|
||
missing support for this extension.
|
||
|
||
|
||
## Driver Unknown Physical Device Extensions
|
||
|
||
Drivers that implement entrypoints which take a `VkPhysicalDevice` as the first
|
||
parameter *should* support `vk_icdGetPhysicalDeviceProcAddr`.
|
||
This function is added to the Loader and Driver Driver Interface Version 4,
|
||
allowing the loader to distinguish between entrypoints which take `VkDevice`
|
||
and `VkPhysicalDevice` as the first parameter.
|
||
This allows the loader to properly support entrypoints that are unknown to it
|
||
gracefully.
|
||
This entry point is not a part of the Vulkan API itself, only a private
|
||
interface between the loader and drivers.
|
||
Note: Loader and Driver Interface Version 7 makes exporting
|
||
`vk_icdGetPhysicalDeviceProcAddr` optional.
|
||
Instead, drivers *must* expose it through `vk_icdGetInstanceProcAddr`.
|
||
|
||
```cpp
|
||
PFN_vkVoidFunction
|
||
vk_icdGetPhysicalDeviceProcAddr(
|
||
VkInstance instance,
|
||
const char* pName);
|
||
```
|
||
|
||
This function behaves similar to `vkGetInstanceProcAddr` and
|
||
`vkGetDeviceProcAddr` except it should only return values for physical device
|
||
extension entry points.
|
||
In this way, it compares "pName" to every physical device function supported in
|
||
the driver.
|
||
|
||
Implementations of the function should have the following behavior:
|
||
* If `pName` is the name of a Vulkan API entrypoint that takes a
|
||
`VkPhysicalDevice` as its primary dispatch handle, and the driver supports the
|
||
entrypoint, then the driver **must** return the valid function pointer to the
|
||
driver's implementation of that entrypoint.
|
||
* If `pName` is the name of a Vulkan API entrypoint that takes something other
|
||
than a `VkPhysicalDevice` as its primary dispatch handle, then the driver
|
||
**must** return `NULL`.
|
||
* If the driver is unaware of any entrypoint with the name `pName`, it **must**
|
||
return `NULL`.
|
||
|
||
If a driver intends to support functions that take VkPhysicalDevice as the
|
||
dispatchable parameter, then the driver should support
|
||
`vk_icdGetPhysicalDeviceProcAddr`. This is because if these functions aren't
|
||
known to the loader, such as those from unreleased extensions or because
|
||
the loader is an older build thus doesn't know about them _yet_, the loader
|
||
won't be able to distinguish whether this is a device or physical device
|
||
function.
|
||
|
||
If a driver does implement this support, it must export the function from the
|
||
driver library using the name `vk_icdGetPhysicalDeviceProcAddr` so that the
|
||
symbol can be located through the platform's dynamic linking utilities, or if
|
||
the driver supports Loader and Driver Interface Version 7, exposed through
|
||
`vk_icdGetInstanceProcAddr` instead.
|
||
|
||
The behavior of the loader's `vkGetInstanceProcAddr` with support for the
|
||
`vk_icdGetPhysicalDeviceProcAddr` function is as follows:
|
||
1. Check if core function:
|
||
- If it is, return the function pointer
|
||
2. Check if known instance or device extension function:
|
||
- If it is, return the function pointer
|
||
3. Call the layer/driver `GetPhysicalDeviceProcAddr`
|
||
- If it returns `non-NULL`, return a trampoline to a generic physical device
|
||
function, and set up a generic terminator which will pass it to the proper
|
||
driver.
|
||
4. Call down using `GetInstanceProcAddr`
|
||
- If it returns non-NULL, treat it as an unknown logical device command.
|
||
This means setting up a generic trampoline function that takes in a `VkDevice`
|
||
as the first parameter and adjusting the dispatch table to call the
|
||
driver/layer's function after getting the dispatch table from the
|
||
`VkDevice`.
|
||
Then, return the pointer to the corresponding trampoline function.
|
||
5. Return `NULL`
|
||
|
||
The result is that if the command gets promoted to Vulkan core later, it will no
|
||
longer be set up using `vk_icdGetPhysicalDeviceProcAddr`.
|
||
Additionally, if the loader adds direct support for the extension, it will no
|
||
longer get to step 3, because step 2 will return a valid function pointer.
|
||
However, the driver should continue to support the command query via
|
||
`vk_icdGetPhysicalDeviceProcAddr`, until at least a Vulkan version bump, because
|
||
an older loader may still be attempting to use the commands.
|
||
|
||
### Reason for adding `vk_icdGetPhysicalDeviceProcAddr`
|
||
|
||
Originally, when the loader's `vkGetInstanceProcAddr` was called, it would
|
||
result in the following behavior:
|
||
1. The loader would check if it was a core function:
|
||
- If so, it would return the function pointer
|
||
2. The loader would check if it was a known extension function:
|
||
- If so, it would return the function pointer
|
||
3. If the loader knew nothing about it, it would call down using
|
||
`GetInstanceProcAddr`
|
||
- If it returned `non-NULL`, treat it as an unknown logical device command.
|
||
- This meant setting up a generic trampoline function that takes in a
|
||
VkDevice as the first parameter and adjusting the dispatch table to call the
|
||
driver/layer's function after getting the dispatch table from the
|
||
`VkDevice`.
|
||
4. If all the above failed, the loader would return `NULL` to the application.
|
||
|
||
This caused problems when a driver attempted to expose new physical device
|
||
extensions the loader knew nothing about, but an application was aware of.
|
||
Because the loader knew nothing about it, the loader would get to step 3 in the
|
||
above process and would treat the function as an unknown logical device command.
|
||
The problem is, this would create a generic `VkDevice` trampoline function
|
||
which, on the first call, would attempt to dereference the VkPhysicalDevice as a
|
||
`VkDevice`.
|
||
This would lead to a crash or corruption.
|
||
|
||
## Physical Device Sorting
|
||
|
||
When an application selects a GPU to use, it must enumerate physical devices or
|
||
physical device groups.
|
||
These API functions do not specify which order the physical devices or physical
|
||
device groups will be presented in.
|
||
On Windows, the loader will attempt to sort these objects so that the system
|
||
preference will be listed first.
|
||
This mechanism does not force an application to use any particular GPU —
|
||
it merely changes the order in which they are presented.
|
||
|
||
This mechanism requires that a driver provide The Loader and Driver Interface
|
||
Version 6.
|
||
This version defines a new exported function, `vk_icdEnumerateAdapterPhysicalDevices`,
|
||
detailed below, that Drivers may provide on Windows.
|
||
This entry point is not a part of the Vulkan API itself, only a private
|
||
interface between the loader and drivers.
|
||
Note: Loader and Driver Interface Version 7 makes exporting
|
||
`vk_icdEnumerateAdapterPhysicalDevices` optional.
|
||
Instead, drivers *must* expose it through `vk_icdGetInstanceProcAddr`.
|
||
|
||
```c
|
||
VKAPI_ATTR VkResult VKAPI_CALL
|
||
vk_icdEnumerateAdapterPhysicalDevices(
|
||
VkInstance instance,
|
||
LUID adapterLUID,
|
||
uint32_t* pPhysicalDeviceCount,
|
||
VkPhysicalDevice* pPhysicalDevices);
|
||
```
|
||
|
||
|
||
This function takes an adapter LUID as input, and enumerates all Vulkan physical
|
||
devices that are associated with that LUID.
|
||
This works in the same way as other Vulkan enumerations — if
|
||
`pPhysicalDevices` is `NULL`, then the count will be provided.
|
||
Otherwise, the physical devices associated with the queried adapter will be
|
||
provided.
|
||
The function must provide multiple physical devices when the LUID refers to a
|
||
linked adapter.
|
||
This allows the loader to translate the adapter into Vulkan physical device
|
||
groups.
|
||
|
||
While the loader attempts to match the system's preference for GPU ordering,
|
||
there are some limitations.
|
||
Because this feature requires a new driver interface, only physical devices from
|
||
drivers that support this function will be sorted.
|
||
All unsorted physical devices will be listed at the end of the list, in an
|
||
indeterminate order.
|
||
Furthermore, only physical devices that correspond to an adapter may be sorted.
|
||
This means that a software driver would likely not be sorted.
|
||
Finally, this API only applies to Windows systems and will only work on versions
|
||
of Windows 10 that support GPU selection through the OS.
|
||
Other platforms may be included in the future, but they will require separate
|
||
platform-specific interfaces.
|
||
|
||
A requirement of `vk_icdEnumerateAdapterPhysicalDevices` is that it *must*
|
||
return the same `VkPhysicalDevice` handle values for the same physical
|
||
devices that are returned by `vkEnumeratePhysicalDevices`.
|
||
This is because the loader calls both functions on the driver then
|
||
de-duplicates the physical devices using the `VkPhysicalDevice` handles.
|
||
Since not all physical devices in a driver will have a LUID, such as for
|
||
software implementations, this step is necessary to allow drivers to
|
||
enumerate all available physical devices.
|
||
|
||
## Driver Dispatchable Object Creation
|
||
|
||
As previously covered, the loader requires dispatch tables to be accessible
|
||
within Vulkan dispatchable objects, such as: `VkInstance`, `VkPhysicalDevice`,
|
||
`VkDevice`, `VkQueue`, and `VkCommandBuffer`.
|
||
The specific requirements on all dispatchable objects created by drivers
|
||
are as follows:
|
||
|
||
- All dispatchable objects created by a driver can be cast to void \*\*
|
||
- The loader will replace the first entry with a pointer to the dispatch table
|
||
which is owned by the loader.
|
||
This implies three things for drivers:
|
||
1. The driver must return a pointer for the opaque dispatchable object handle
|
||
2. This pointer points to a regular C structure with the first entry being a
|
||
pointer.
|
||
* **NOTE:** For any C\++ drivers that implement VK objects directly
|
||
as C\++ classes:
|
||
* The C\++ compiler may put a vtable at offset zero if the class is
|
||
non-POD due to the use of a virtual function.
|
||
* In this case use a regular C structure (see below).
|
||
3. The loader checks for a magic value (ICD\_LOADER\_MAGIC) in all the created
|
||
dispatchable objects, as follows (see `include/vulkan/vk_icd.h`):
|
||
|
||
```cpp
|
||
#include "vk_icd.h"
|
||
|
||
union _VK_LOADER_DATA {
|
||
uintptr loadermagic;
|
||
void * loaderData;
|
||
} VK_LOADER_DATA;
|
||
|
||
vkObj
|
||
alloc_icd_obj()
|
||
{
|
||
vkObj *newObj = alloc_obj();
|
||
...
|
||
// Initialize pointer to loader's dispatch table with ICD_LOADER_MAGIC
|
||
|
||
set_loader_magic_value(newObj);
|
||
...
|
||
return newObj;
|
||
}
|
||
```
|
||
|
||
|
||
## Handling KHR Surface Objects in WSI Extensions
|
||
|
||
Normally, drivers handle object creation and destruction for various Vulkan
|
||
objects.
|
||
The WSI surface extensions for Linux, Windows, macOS, and QNX
|
||
("VK\_KHR\_win32\_surface", "VK\_KHR\_xcb\_surface", "VK\_KHR\_xlib\_surface",
|
||
"VK\_KHR\_wayland\_surface", "VK\_MVK\_macos\_surface",
|
||
"VK\_QNX\_screen\_surface" and "VK\_KHR\_surface") are handled differently.
|
||
For these extensions, the `VkSurfaceKHR` object creation and destruction may be
|
||
handled by either the loader or a driver.
|
||
|
||
If the loader handles the management of the `VkSurfaceKHR` objects:
|
||
1. The loader will handle the calls to `vkCreateXXXSurfaceKHR` and
|
||
`vkDestroySurfaceKHR`
|
||
functions without involving the drivers.
|
||
* Where XXX stands for the Windowing System name:
|
||
* Wayland
|
||
* XCB
|
||
* Xlib
|
||
* Windows
|
||
* Android
|
||
* MacOS (`vkCreateMacOSSurfaceMVK`)
|
||
* QNX (`vkCreateScreenSurfaceQNX`)
|
||
2. The loader creates a `VkIcdSurfaceXXX` object for the corresponding
|
||
`vkCreateXXXSurfaceKHR` call.
|
||
* The `VkIcdSurfaceXXX` structures are defined in `include/vulkan/vk_icd.h`.
|
||
3. Drivers can cast any `VkSurfaceKHR` object to a pointer to the
|
||
appropriate `VkIcdSurfaceXXX` structure.
|
||
4. The first field of all the `VkIcdSurfaceXXX` structures is a
|
||
`VkIcdSurfaceBase` enumerant that indicates whether the
|
||
surface object is Win32, XCB, Xlib, Wayland, or Screen.
|
||
|
||
The driver may choose to handle `VkSurfaceKHR` object creation instead.
|
||
If a driver desires to handle creating and destroying it must do the following:
|
||
1. Support Loader and Driver Interface Version 3 or newer.
|
||
2. Expose and handle all functions that take in a `VkSurfaceKHR` object,
|
||
including:
|
||
* `vkCreateXXXSurfaceKHR`
|
||
* `vkGetPhysicalDeviceSurfaceSupportKHR`
|
||
* `vkGetPhysicalDeviceSurfaceCapabilitiesKHR`
|
||
* `vkGetPhysicalDeviceSurfaceFormatsKHR`
|
||
* `vkGetPhysicalDeviceSurfacePresentModesKHR`
|
||
* `vkCreateSwapchainKHR`
|
||
* `vkDestroySurfaceKHR`
|
||
|
||
Because the `VkSurfaceKHR` object is an instance-level object, one object can be
|
||
associated with multiple drivers.
|
||
Therefore, when the loader receives the `vkCreateXXXSurfaceKHR` call, it still
|
||
creates an internal `VkSurfaceIcdXXX` object.
|
||
This object acts as a container for each driver's version of the
|
||
`VkSurfaceKHR` object.
|
||
If a driver does not support the creation of its own `VkSurfaceKHR` object, the
|
||
loader's container stores a NULL for that driver.
|
||
On the other hand, if the driver does support `VkSurfaceKHR` creation, the
|
||
loader will make the appropriate `vkCreateXXXSurfaceKHR` call to the
|
||
driver, and store the returned pointer in its container object.
|
||
The loader then returns the `VkSurfaceIcdXXX` as a `VkSurfaceKHR` object back up
|
||
the call chain.
|
||
Finally, when the loader receives the `vkDestroySurfaceKHR` call, it
|
||
subsequently calls `vkDestroySurfaceKHR` for each driver whose internal
|
||
`VkSurfaceKHR` object is not NULL.
|
||
Then the loader destroys the container object before returning.
|
||
|
||
|
||
## Loader and Driver Interface Negotiation
|
||
|
||
Generally, for functions issued by an application, the loader can be viewed as a
|
||
pass through.
|
||
That is, the loader generally doesn't modify the functions or their parameters,
|
||
but simply calls the driver's entry point for that function.
|
||
There are specific additional interface requirements a driver needs to comply
|
||
with that are not part of any requirements from the Vulkan specification.
|
||
These additional requirements are versioned to allow flexibility in the future.
|
||
|
||
|
||
### Windows, Linux and macOS Driver Negotiation
|
||
|
||
|
||
#### Version Negotiation Between the Loader and Drivers
|
||
|
||
All drivers supporting Loader and Driver Interface Version 2 or higher must
|
||
export the following function that is used for determination of the interface
|
||
version that will be used.
|
||
This entry point is not a part of the Vulkan API itself, only a private
|
||
interface between the loader and drivers.
|
||
Note: Loader and Driver Interface Version 7 makes exporting
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion` optional.
|
||
Instead, drivers *must* expose it through `vk_icdGetInstanceProcAddr`.
|
||
|
||
```cpp
|
||
VKAPI_ATTR VkResult VKAPI_CALL
|
||
vk_icdNegotiateLoaderICDInterfaceVersion(
|
||
uint32_t* pSupportedVersion);
|
||
```
|
||
|
||
This function allows the loader and driver to agree on an interface version to
|
||
use.
|
||
The "pSupportedVersion" parameter is both an input and output parameter.
|
||
"pSupportedVersion" is filled in by the loader with the desired latest interface
|
||
version supported by the loader (typically the latest).
|
||
The driver receives this and returns back the version it desires in the same
|
||
field.
|
||
Because it is setting up the interface version between the loader and
|
||
driver, this should be the first call made by a loader to the driver (even prior
|
||
to any calls to `vk_icdGetInstanceProcAddr`).
|
||
|
||
If the driver receiving the call no longer supports the interface version
|
||
provided by the loader (due to deprecation), then it should report a
|
||
`VK_ERROR_INCOMPATIBLE_DRIVER` error.
|
||
Otherwise it sets the value pointed by "pSupportedVersion" to the latest
|
||
interface version supported by both the driver and the loader and returns
|
||
`VK_SUCCESS`.
|
||
|
||
The driver should report `VK_SUCCESS` in case the loader-provided interface
|
||
version is newer than that supported by the driver, as it's the loader's
|
||
responsibility to determine whether it can support the older interface version
|
||
supported by the driver.
|
||
The driver should also report `VK_SUCCESS` in the case its interface version is
|
||
greater than the loader's, but return the loader's version.
|
||
Thus, upon return of `VK_SUCCESS` the "pSupportedVersion" will contain the
|
||
desired interface version to be used by the driver.
|
||
|
||
If the loader receives an interface version from the driver that the loader no
|
||
longer supports (due to deprecation), or it receives a
|
||
`VK_ERROR_INCOMPATIBLE_DRIVER` error instead of `VK_SUCCESS`, then the loader
|
||
will treat the driver as incompatible and will not load it for use.
|
||
In this case, the application will not see the driver's `vkPhysicalDevice`
|
||
during enumeration.
|
||
|
||
#### Interfacing With Legacy Drivers or Loaders
|
||
|
||
If a loader sees that a driver does not export or expose the
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion` function, then the loader assumes the
|
||
corresponding driver only supports either interface version 0 or 1.
|
||
|
||
From the other side of the interface, if a driver sees a call to
|
||
`vk_icdGetInstanceProcAddr` before a call to
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion`, then the loader is either a legacy
|
||
loader with only support for interface version 0 or 1, or the loader is using
|
||
interface version 7 or newer.
|
||
|
||
If the first call to `vk_icdGetInstanceProcAddr` is to query for
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion`, then that means the loader is using
|
||
interface version 7.
|
||
This only occurs when the driver does not export
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion`.
|
||
Drivers which export `vk_icdNegotiateLoaderICDInterfaceVersion` will have it
|
||
called first.
|
||
|
||
If the first call to `vk_icdGetInstanceProcAddr` is **not** querying for
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion`, then loader is a legacy loader only
|
||
which supports version 0 or 1.
|
||
In this case, if the loader calls `vk_icdGetInstanceProcAddr` first, it supports
|
||
at least interface version 1.
|
||
Otherwise, the loader only supports version 0.
|
||
|
||
#### Loader and Driver Interface Version 7 Requirements
|
||
|
||
Version 7 relaxes the requirement that Loader and Driver Interface functions
|
||
must be exported.
|
||
Instead, it only requires that those functions be queryable through
|
||
`vk_icdGetInstanceProcAddr`.
|
||
The functions are:
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion`
|
||
`vk_icdGetPhysicalDeviceProcAddr`
|
||
`vk_icdEnumerateAdapterPhysicalDevices` (Windows only)
|
||
These functions are considered global for the purposes of retrieval, so the
|
||
`VkInstance` parameter of `vk_icdGetInstanceProcAddr` will be **NULL**.
|
||
While exporting these functions is no longer a requirement, drivers may still
|
||
export them for compatibility with older loaders.
|
||
The changes in this version allow drivers provided through the
|
||
`VK_LUNARG_direct_driver_loading` extension to support the entire Loader and
|
||
Driver Interface.
|
||
|
||
#### Loader and Driver Interface Version 6 Requirements
|
||
|
||
Version 6 provides a mechanism to allow the loader to sort physical devices.
|
||
The loader will only attempt to sort physical devices on a driver if version 6
|
||
of the interface is supported.
|
||
This version provides the `vk_icdEnumerateAdapterPhysicalDevices` function
|
||
defined earlier in this document.
|
||
|
||
#### Loader and Driver Interface Version 5 Requirements
|
||
|
||
This interface version has no changes to the actual interface.
|
||
If the loader requests interface version 5 or greater, it is simply
|
||
an indication to drivers that the loader is now evaluating whether 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 driver that the loader is ignorant of the API version being
|
||
requested.
|
||
Because of this, it falls on the driver to validate that the API Version is not
|
||
greater than major = 1 and minor = 0.
|
||
If it is, then the driver 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:
|
||
|
||
<table style="width:100%">
|
||
<tr>
|
||
<th>Loader Supports I/f Version</th>
|
||
<th>Driver Supports I/f Version</th>
|
||
<th>Result</th>
|
||
</tr>
|
||
<tr>
|
||
<td>4 or Earlier</td>
|
||
<td>Any Version</td>
|
||
<td>Driver <b>must fail</b> with <b>VK_ERROR_INCOMPATIBLE_DRIVER</b>
|
||
for all vkCreateInstance calls with apiVersion set to > Vulkan 1.0
|
||
because the loader is still at interface version <= 4.<br/>
|
||
Otherwise, the driver should behave as normal.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>5 or Newer</td>
|
||
<td>4 or Earlier</td>
|
||
<td>Loader <b>must fail</b> with <b>VK_ERROR_INCOMPATIBLE_DRIVER</b> if it
|
||
can't handle the apiVersion.
|
||
Driver may pass for all apiVersions, but since its interface is
|
||
<= 4, it is best if it assumes it needs to do the work of rejecting
|
||
anything > Vulkan 1.0 and fail with <b>VK_ERROR_INCOMPATIBLE_DRIVER</b>.
|
||
<br/>
|
||
Otherwise, the driver should behave as normal.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>5 or Newer</td>
|
||
<td>5 or Newer</td>
|
||
<td>Loader <b>must fail</b> with <b>VK_ERROR_INCOMPATIBLE_DRIVER</b> if it
|
||
can't handle the apiVersion, and drivers should fail with
|
||
<b>VK_ERROR_INCOMPATIBLE_DRIVER</b> <i>only if</i> they can not support
|
||
the specified apiVersion. <br/>
|
||
Otherwise, the driver should behave as normal.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
#### Loader and Driver Interface Version 4 Requirements
|
||
|
||
The major change to version 4 of this interface version is the support of
|
||
[Unknown Physical Device Extensions](#driver-unknown-physical-device-extensions)
|
||
using the `vk_icdGetPhysicalDeviceProcAddr` function.
|
||
This function is purely optional.
|
||
However, if a driver supports a physical device extension, it must provide a
|
||
`vk_icdGetPhysicalDeviceProcAddr` function.
|
||
Otherwise, the loader will continue to treat any unknown functions as VkDevice
|
||
functions and cause invalid behavior.
|
||
|
||
|
||
#### Loader and Driver Interface Version 3 Requirements
|
||
|
||
The primary change that occurred in this interface version is to allow a driver
|
||
to handle creation and destruction of their own KHR_surfaces.
|
||
Up until this point, the loader created a surface object that was used by all
|
||
drivers.
|
||
However, some drivers *may* want to provide their own surface handles.
|
||
If a driver chooses to enable this support, it must support Loader and Driver
|
||
Interface Version 3, as well as any Vulkan function that uses a `VkSurfaceKHR`
|
||
handle, such as:
|
||
- `vkCreateXXXSurfaceKHR` (where XXX is the platform-specific identifier [i.e.
|
||
`vkCreateWin32SurfaceKHR` for Windows])
|
||
- `vkDestroySurfaceKHR`
|
||
- `vkCreateSwapchainKHR`
|
||
- `vkGetPhysicalDeviceSurfaceSupportKHR`
|
||
- `vkGetPhysicalDeviceSurfaceCapabilitiesKHR`
|
||
- `vkGetPhysicalDeviceSurfaceFormatsKHR`
|
||
- `vkGetPhysicalDeviceSurfacePresentModesKHR`
|
||
|
||
A driver which does not participate in this functionality can opt out by
|
||
simply not exposing the above `vkCreateXXXSurfaceKHR` and
|
||
`vkDestroySurfaceKHR` functions.
|
||
|
||
|
||
#### Loader and Driver Interface Version 2 Requirements
|
||
|
||
Interface Version 2 requires that drivers export
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion`.
|
||
For more information, see [Version Negotiation Between Loader and Drivers](#version-negotiation-between-loader-and-drivers).
|
||
|
||
Additional, version 2 requires that Vulkan dispatchable objects created by
|
||
drivers must be created in accordance to the
|
||
[Driver Dispatchable Object Creation](#driver-dispatchable-object-creation)
|
||
section.
|
||
|
||
|
||
#### Loader and Driver Interface Version 1 Requirements
|
||
|
||
Version 1 of the interface added the driver-specific entry-point
|
||
`vk_icdGetInstanceProcAddr`.
|
||
Since this is before the creation of the
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion` entry-point, the loader has no
|
||
negotiation process for determine what interface version the driver
|
||
supports.
|
||
Because of this, the loader detects support for version 1 of the interface
|
||
by the absence of the negotiate function, but the presence of the
|
||
`vk_icdGetInstanceProcAddr`.
|
||
No other entry-points need to be exported by the driver as the loader will query
|
||
the appropriate function pointers using that.
|
||
|
||
|
||
#### Loader and Driver Interface Version 0 Requirements
|
||
|
||
Version 0 does not support either `vk_icdGetInstanceProcAddr` or
|
||
`vk_icdNegotiateLoaderICDInterfaceVersion`.
|
||
Because of this, the loader will assume the driver supports only version 0 of
|
||
the interface unless one of those functions exists.
|
||
|
||
Additionally, for Version 0, the driver must expose at least the following core
|
||
Vulkan entry-points so the loader may build up the interface to the driver:
|
||
|
||
- The function `vkGetInstanceProcAddr` **must be exported** in the driver
|
||
library and returns valid function pointers for all the Vulkan API entry points.
|
||
- `vkCreateInstance` **must be exported** by the driver library.
|
||
- `vkEnumerateInstanceExtensionProperties` **must be exported** by the driver
|
||
library.
|
||
|
||
|
||
#### Additional Interface Notes:
|
||
|
||
- The loader will filter out extensions requested in `vkCreateInstance` and
|
||
`vkCreateDevice` before calling into the driver; filtering will be of extensions
|
||
advertised by entities (e.g. layers) different from the driver in question.
|
||
- The loader will not call the driver for `vkEnumerate*LayerProperties`
|
||
as layer properties are obtained from the layer libraries and layer JSON files.
|
||
- If a driver library author wants to implement a layer, it can do so by having
|
||
the appropriate layer JSON manifest file refer to the driver library file.
|
||
- The loader will not call the driver for `vkEnumerate*ExtensionProperties` if
|
||
"pLayerName" is not equal to `NULL`.
|
||
- Drivers creating new dispatchable objects via device extensions need
|
||
to initialize the created dispatchable object.
|
||
The loader has generic *trampoline* code for unknown device extensions.
|
||
This generic *trampoline* code doesn't initialize the dispatch table within the
|
||
newly created object.
|
||
See the
|
||
[Driver Dispatchable Object Creation](#driver-dispatchable-object-creation)
|
||
section for more information on how to initialize created dispatchable objects
|
||
for extensions non known by the loader.
|
||
|
||
|
||
### Android Driver Negotiation
|
||
|
||
The Android loader uses the same protocol for initializing the dispatch table as
|
||
described above.
|
||
The only difference is that the Android loader queries layer and extension
|
||
information directly from the respective libraries and does not use the JSON
|
||
manifest files used by the Windows, Linux and macOS loaders.
|
||
|
||
|
||
## Loader implementation of VK_KHR_portability_enumeration
|
||
|
||
The loader implements the `VK_KHR_portability_enumeration` instance extension,
|
||
which filters out any drivers that report support for the portability subset
|
||
device extension. Unless the application explicitly requests enumeration of
|
||
portability devices by setting the
|
||
`VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` bit in the
|
||
VkInstanceCreateInfo::flags, the loader does not load any drivers that declare
|
||
themselves to be portability drivers.
|
||
|
||
Drivers declare whether they are portability drivers or not in the Driver
|
||
Manifest Json file, with the `is_portability_driver` boolean field.
|
||
[More information here](#driver-manifest-file-version-101)
|
||
|
||
The initial support for this extension only reported errors when an application
|
||
did not enable the portability enumeration feature. It did not filter out
|
||
portability drivers. This was done to give a grace period for applications to
|
||
update their instance creation logic without outright breaking the application.
|
||
|
||
## Loader and Driver Policy
|
||
|
||
This section is intended to define proper behavior expected between the loader
|
||
and drivers.
|
||
Much of this section is additive to the Vulkan spec, and necessary for
|
||
maintaining consistency across platforms.
|
||
In fact, much of the language can be found throughout this document, but is
|
||
summarized here for convenience.
|
||
Additionally, there should be a way to identify bad or non-conformant behavior
|
||
in a driver and remedy it as soon as possible.
|
||
Therefore, a policy numbering system is provided to clearly identify each
|
||
policy statement in a unique way.
|
||
|
||
Finally, based on the goal of making the loader efficient and performant,
|
||
some of these policy statements defining proper driver behavior may not
|
||
be testable (and therefore aren't enforceable by the loader).
|
||
However, that should not detract from the requirement in order to provide the
|
||
best experience to end-users and developers.
|
||
|
||
|
||
### Number Format
|
||
|
||
Loader and Driver policy items start with the prefix `LDP_` (short for
|
||
Loader and Driver Policy) which is followed by an identifier based on what
|
||
component the policy is targeted against.
|
||
In this case there are only two possible components:
|
||
- Drivers: which will have the string `DRIVER_` as part of the policy number.
|
||
- The Loader: which will have the string `LOADER_` as part of the policy
|
||
number.
|
||
|
||
|
||
### Android Differences
|
||
|
||
As stated before, the Android Loader is actually separate from the Khronos
|
||
Loader.
|
||
Because of this and other platform requirements, not all of these policy
|
||
statements apply to Android.
|
||
Each table also has a column titled "Applicable to Android?"
|
||
which indicates which policy statements apply to drivers that are focused
|
||
only on Android support.
|
||
Further information on the Android loader can be found in the
|
||
<a href="https://source.android.com/devices/graphics/implement-vulkan">
|
||
Android Vulkan documentation</a>.
|
||
|
||
|
||
### Requirements of Well-Behaved Drivers
|
||
|
||
<table style="width:100%">
|
||
<tr>
|
||
<th>Requirement Number</th>
|
||
<th>Requirement Description</th>
|
||
<th>Result of Non-Compliance</th>
|
||
<th>Applicable to Android?</th>
|
||
<th>Enforceable by Loader?</th>
|
||
<th>Reference Section</th>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_1</b></small></td>
|
||
<td>A driver <b>must not</b> cause other drivers to fail, crash, or
|
||
otherwise misbehave.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td>No</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_2</b></small></td>
|
||
<td>A driver <b>must not</b> crash if it detects that there are no supported
|
||
Vulkan Physical Devices (<i>VkPhysicalDevice</i>) on the system when a
|
||
call to that driver is made using any Vulkan instance of physical device
|
||
API.<br/>
|
||
This is because some devices can be hot-plugged.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td>No<br/>
|
||
The loader has no direct knowledge of what devices (virtual or physical)
|
||
may be supported by a given driver.</td>
|
||
<td><small>N/A</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_3</b></small></td>
|
||
<td>A driver <b>must</b> be able to negotiate a supported version of the
|
||
Loader and Driver Interface with the loader in accordance with the stated
|
||
negotiation process.
|
||
</td>
|
||
<td>The driver will not be loaded.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#loader-and-driver-interface-negotiation">
|
||
Interface Negotiation</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_4</b></small></td>
|
||
<td>A driver <b>must</b> have a valid JSON manifest file for the loader to
|
||
process that ends with the ".json" suffix.
|
||
</td>
|
||
<td>The driver will not be loaded.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#driver-manifest-file-format">Manifest File Format</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_5</b></small></td>
|
||
<td>A driver <b>must</b> pass conformance with the results submitted,
|
||
verified, and approved by Khronos before reporting a conformance version
|
||
through any mechanism provided by Vulkan (examples include inside the
|
||
<i>VkPhysicalDeviceVulkan12Properties</i> and the
|
||
<i>VkPhysicalDeviceDriverProperties</i> structs).<br/>
|
||
Otherwise, when such a structure containing a conformance version is
|
||
encountered, the driver <b>must</b> return a conformance version
|
||
of 0.0.0.0 to indicate it hasn't been so verified and approved.
|
||
</td>
|
||
<td>Yes</td>
|
||
<td>No</td>
|
||
<td>The loader and/or the application may make assumptions about the
|
||
capabilities of the driver resulting in undefined behavior
|
||
possibly including crashes or corruption.
|
||
</td>
|
||
<td><small>
|
||
<a href="https://github.com/KhronosGroup/VK-GL-CTS/blob/main/external/openglcts/README.md">
|
||
Vulkan CTS Documentation</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_6</b></small></td>
|
||
<td>Removed - See
|
||
<a href="#removed-driver-policies">Removed Driver Policies</a>
|
||
</td>
|
||
<td>-</td>
|
||
<td>-</td>
|
||
<td>-</td>
|
||
<td>-</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_7</b></small></td>
|
||
<td>If a driver desires to support Vulkan API 1.1 or newer, it <b>must</b>
|
||
expose support for Loader and Driver Interface Version 5 or newer.
|
||
</td>
|
||
<td>The driver will be used when it shouldn't be and will cause
|
||
undefined behavior possibly including crashes or corruption.
|
||
</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#loader-version-5-interface-requirements">
|
||
Version 5 Interface Requirements</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_8</b></small></td>
|
||
<td>If a driver wishes to handle its own <i>VkSurfaceKHR</i> object
|
||
creation, it <b>must</b> implement the Loader and Driver Interface Version 3 or
|
||
newer and support querying all the relevant surface functions via
|
||
<i>vk_icdGetInstanceProcAddr</i>.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#handling-khr-surface-objects-in-wsi-extensions">
|
||
Handling KHR Surface Objects</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_9</b></small></td>
|
||
<td>If version negotiation results in a driver using the Loader
|
||
and Driver Interface Version 4 or earlier, the driver <b>must</b> verify
|
||
that the Vulkan API version passed into <i>vkCreateInstance</i> (through
|
||
<i>VkInstanceCreateInfo</i>’s <i>VkApplicationInfo</i>'s
|
||
<i>apiVersion</i>) is supported.
|
||
If the requested Vulkan API version can not be supported by the driver,
|
||
it <b>must</b> return <b>VK_ERROR_INCOMPATIBLE_DRIVER</b>. <br/>
|
||
This is not required if the interface version is 5 or newer because the
|
||
loader is responsible for this check.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#loader-version-5-interface-requirements">
|
||
Version 5 Interface Requirements</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_10</b></small></td>
|
||
<td>If version negotiation results in a driver using the Loader and Driver Interface
|
||
Version 5 or newer, the driver <b>must</b> not return
|
||
<b>VK_ERROR_INCOMPATIBLE_DRIVER</b> if the Vulkan API version
|
||
passed into <i>vkCreateInstance</i> (through
|
||
<i>VkInstanceCreateInfo</i>’s <i>VkApplicationInfo</i>'s
|
||
<i>apiVersion</i>) is not supported by the driver. This check is performed
|
||
by the loader on the drivers behalf.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#loader-version-5-interface-requirements">
|
||
Version 5 Interface Requirements</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_11</b></small></td>
|
||
<td>A driver <b>must</b> remove all Manifest files and references to those
|
||
files (i.e. Registry entries on Windows) when uninstalling.
|
||
<br/>
|
||
Similarly, on updating the driver files, the old files <b>must</b> be
|
||
all updated or removed.
|
||
</td>
|
||
<td>If an old file is left pointing to an incorrect library, it will
|
||
result in undefined behavior which may include crashes or corruption.
|
||
</td>
|
||
<td>No</td>
|
||
<td>No<br/>
|
||
The loader has no idea what driver files are new, old, or incorrect.
|
||
Any type of driver file verification would quickly become very complex
|
||
since it would require the loader to maintain an internal database
|
||
tracking badly behaving drivers based on the driver vendor, driver
|
||
version, targeted platform(s), and possibly other criteria.
|
||
</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_12</b></small></td>
|
||
<td>To work properly with the public Khronos Loader, a driver
|
||
<b>must not</b> expose platform interface extensions without first
|
||
publishing them with Khronos.<br/>
|
||
Platforms under development may use modified versions of the Khronos
|
||
Loader until the design because stable and/or public.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes (specifically for Android extensions)</td>
|
||
<td>No</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
</table>
|
||
|
||
#### Removed Driver Policies
|
||
|
||
These policies were in the loader source at some point but later removed.
|
||
They are documented here for reference.
|
||
|
||
<table>
|
||
<tr>
|
||
<th>Requirement Number</th>
|
||
<th>Requirement Description</th>
|
||
<th>Removal Reason</th>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_DRIVER_6</b></small></td>
|
||
<td>A driver supporting Loader and Driver Interface Version 1 or newer <b>must
|
||
not</b> directly export standard Vulkan entry-points.
|
||
<br/>
|
||
Instead, it <b>must</b> export only the loader interface functions
|
||
required by the interface versions it does support (for example
|
||
<i>vk_icdGetInstanceProcAddr</i>). <br/>
|
||
This is because the dynamic linking on some platforms has been
|
||
problematic in the past and incorrectly links to exported functions from
|
||
the wrong dynamic library at times. <br/>
|
||
<b>NOTE:</b> This is actually true for all exports.
|
||
When in doubt, don't export any items from a driver that could cause
|
||
conflicts in other libraries.<br/>
|
||
</td>
|
||
<td>
|
||
This policy has been removed due to there being valid circumstances for
|
||
drivers to export core entrypoints.
|
||
Additionally, it was not found that dynamic linking would cause many
|
||
issues in practice.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
### Requirements of a Well-Behaved Loader
|
||
|
||
<table style="width:100%">
|
||
<tr>
|
||
<th>Requirement Number</th>
|
||
<th>Requirement Description</th>
|
||
<th>Result of Non-Compliance</th>
|
||
<th>Applicable to Android?</th>
|
||
<th>Reference Section</th>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_1</b></small></td>
|
||
<td>A loader <b>must</b> return <b>VK_ERROR_INCOMPATIBLE_DRIVER</b> if it
|
||
fails to find and load a valid Vulkan driver on the system.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_2</b></small></td>
|
||
<td>A loader <b>must</b> attempt to load any driver's Manifest file it
|
||
discovers and determines is formatted in accordance with this document.
|
||
<br/>
|
||
The <b>only</b> exception is on platforms which determines driver
|
||
location and functionality through some other mechanism.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#driver-discovery">Driver Discovery</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_3</b></small></td>
|
||
<td>A loader <b>must</b> support a mechanism to load driver in one or more
|
||
non-standard locations.<br/>
|
||
This is to allow support for fully software drivers as well as
|
||
evaluating in-development ICDs. <br/>
|
||
The <b>only</b> exception to this rule is if the OS does not wish to
|
||
support this due to security policies.
|
||
</td>
|
||
<td>It will be more difficult to use a Vulkan loader by certain
|
||
tools and driver developers.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#using-pre-production-icds-or-software-drivers">
|
||
Pre-Production ICDs or SW</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_4</b></small></td>
|
||
<td>A loader <b>must not</b> load a Vulkan driver which defines an API
|
||
version that is incompatible with itself.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#driver-discovery">Driver Discovery</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_5</b></small></td>
|
||
<td>A loader <b>must</b> ignore any driver for which a compatible
|
||
Loader and Driver Interface Version can not be negotiated.
|
||
</td>
|
||
<td>The loader would load a driver improperly resulting in undefined
|
||
behavior possibly including crashes or corruption.
|
||
</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#loader-and-driver-interface-negotiation">
|
||
Interface Negotiation</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_6</b></small></td>
|
||
<td>If a driver negotiation results in the loader using Loader and Driver
|
||
Interface Version 5 or newer, a loader <b>must</b> verify that the Vulkan
|
||
API version passed into <i>vkCreateInstance</i> (through
|
||
<i>VkInstanceCreateInfo</i>’s <i>VkApplicationInfo</i>'s
|
||
<i>apiVersion</i>) is supported by at least one driver.
|
||
If the requested Vulkan API version can not be supported by any
|
||
driver, the loader <b>must</b> return
|
||
<b>VK_ERROR_INCOMPATIBLE_DRIVER</b>.<br/>
|
||
This is not required if the Loader and Driver Interface Version is 4 or
|
||
earlier because the responsibility for this check falls on the drivers.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#loader-version-5-interface-requirements">
|
||
Version 5 Interface Requirements</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_7</b></small></td>
|
||
<td>If there exist more than one driver on a system, and some of those
|
||
drivers support <i>only</i> Vulkan API version 1.0 while other drivers
|
||
support a newer Vulkan API version, then a loader <b>must</b> adjust
|
||
the <i>apiVersion</i> field of the <i>VkInstanceCreateInfo</i>’s
|
||
<i>VkApplicationInfo</i> to version 1.0 for all the drivers that are
|
||
only aware of Vulkan API version 1.0.<br/>
|
||
Otherwise, the drivers that support Vulkan API version 1.0 will
|
||
return <b>VK_ERROR_INCOMPATIBLE_DRIVER</b> during
|
||
<i>vkCreateInstance</i> since 1.0 drivers were not aware of future
|
||
versions.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#driver-api-version">Driver API Version</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_8</b></small></td>
|
||
<td>If more than one driver is present, and at least one driver <i>does not
|
||
support</i> instance-level functionality that other drivers support;
|
||
then a loader <b>must</b> support the instance-level functionality in
|
||
some fashion for the non-supporting drivers.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#loader-instance-extension-emulation-support">
|
||
Loader Instance Extension Emulation Support</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_9</b></small></td>
|
||
<td>A loader <b>must</b> filter out instance extensions from the
|
||
<i>VkInstanceCreateInfo</i> structure's <i>ppEnabledExtensionNames</i>
|
||
field that the driver does not support during a call to the driver's
|
||
<i>vkCreateInstance</i>.<br/>
|
||
This is because the application has no way of knowing which
|
||
drivers support which extensions.<br/>
|
||
This ties in directly with <i>LDP_LOADER_8</i> above.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#filtering-out-instance-extension-names">
|
||
Filtering Out Instance Extension Names</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_10</b></small></td>
|
||
<td>A loader <b>must</b> support creating <i>VkSurfaceKHR</i> handles
|
||
that <b>may</b> be shared by all underlying drivers.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#handling-khr-surface-objects-in-wsi-extensions">
|
||
Handling KHR Surface Objects</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_11</b></small></td>
|
||
<td>If a driver exposes the appropriate <i>VkSurfaceKHR</i>
|
||
creation/handling entry-points, a loader <b>must</b> support creating
|
||
the driver-specific surface object handle and provide it, and not the
|
||
shared <i>VkSurfaceKHR</i> handle, back to that driver when requested.
|
||
<br/>
|
||
Otherwise, a loader <b>must</b> provide the loader created
|
||
<i>VkSurfaceKHR</i> handle.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#handling-khr-surface-objects-in-wsi-extensions">
|
||
Handling KHR Surface Objects</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_12</b></small></td>
|
||
<td>A loader <b>must not</b> call any <i>vkEnumerate*ExtensionProperties</i>
|
||
entry-points in a driver if <i>pLayerName</i> is not <b>NULL</b>.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#additional-interface-notes">
|
||
Additional Interface Notes</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LDP_LOADER_13</b></small></td>
|
||
<td>A loader <b>must</b> not load from user-defined paths (including the
|
||
use of any of <i>VK_ICD_FILENAMES</i>, <i>VK_DRIVER_FILES</i>, or
|
||
<i>VK_ADD_DRIVER_FILES</i> environment variables) when running elevated
|
||
(Administrator/Super-user) applications.<br/>
|
||
<b>This is for security reasons.</b>
|
||
</td>
|
||
<td>The behavior is undefined and may result in computer security lapses,
|
||
crashes or corruption.
|
||
</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#exception-for-administrator-and-super-user-mode">
|
||
Exception for Administrator and Super-User mode
|
||
</a></small>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<br/>
|
||
|
||
[Return to the top-level LoaderInterfaceArchitecture.md file.](LoaderInterfaceArchitecture.md)
|