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
795 lines
33 KiB
Markdown
795 lines
33 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/
|
|
|
|
# Application Interface to 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)
|
|
- [Interfacing with Vulkan Functions](#interfacing-with-vulkan-functions)
|
|
- [Vulkan Direct Exports](#vulkan-direct-exports)
|
|
- [Directly Linking to the Loader](#directly-linking-to-the-loader)
|
|
- [Dynamic Linking](#dynamic-linking)
|
|
- [Static Linking](#static-linking)
|
|
- [Indirectly Linking to the Loader](#indirectly-linking-to-the-loader)
|
|
- [Best Application Performance Setup](#best-application-performance-setup)
|
|
- [ABI Versioning](#abi-versioning)
|
|
- [Windows Dynamic Library Usage](#windows-dynamic-library-usage)
|
|
- [Linux Dynamic Library Usage](#linux-dynamic-library-usage)
|
|
- [MacOs Dynamic Library Usage](#macos-dynamic-library-usage)
|
|
- [Bundling the Loader With An Application](#bundling-the-loader-with-an-application)
|
|
- [Application Layer Usage](#application-layer-usage)
|
|
- [Meta-Layers](#meta-layers)
|
|
- [Implicit vs Explicit Layers](#implicit-vs-explicit-layers)
|
|
- [Override Layer](#override-layer)
|
|
- [Forcing Layer Source Folders](#forcing-layer-source-folders)
|
|
- [Exception for Elevated Privileges](#exception-for-elevated-privileges)
|
|
- [Forcing Layers to be Enabled on Windows, Linux and macOS](#forcing-layers-to-be-enabled-on-windows-linux-and-macos)
|
|
- [Overall Layer Ordering](#overall-layer-ordering)
|
|
- [Debugging Possible Layer Issues](#debugging-possible-layer-issues)
|
|
- [Application Usage of Extensions](#application-usage-of-extensions)
|
|
- [Instance and Device Extensions](#instance-and-device-extensions)
|
|
- [WSI Extensions](#wsi-extensions)
|
|
- [Unknown Extensions](#unknown-extensions)
|
|
- [Filtering Out Unknown Instance Extension Names](#filtering-out-unknown-instance-extension-names)
|
|
- [Physical Device Ordering](#physical-device-ordering)
|
|
|
|
## Overview
|
|
|
|
This is the Application-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.
|
|
|
|
## Interfacing with Vulkan Functions
|
|
|
|
There are several ways Vulkan functions may be interfaced through the loader:
|
|
|
|
|
|
### Vulkan Direct Exports
|
|
|
|
The loader library on Windows, Linux, Android, and macOS will export all core
|
|
Vulkan entry-points and all appropriate Window System Interface (WSI)
|
|
entry-points.
|
|
This is done to make it simpler to get started with Vulkan development.
|
|
When an application links directly to the loader library in this way, the
|
|
Vulkan calls are simple *trampoline* functions that jump to the appropriate
|
|
dispatch table entry for the object they are given.
|
|
|
|
|
|
### Directly Linking to the Loader
|
|
|
|
#### Dynamic Linking
|
|
|
|
The loader is distributed as a dynamic library (.dll on Windows or .so on Linux
|
|
or .dylib on macOS) which gets installed to the system path for dynamic
|
|
libraries.
|
|
Furthermore, the dynamic library is generally installed to Windows
|
|
systems as part of driver installation and is generally provided on Linux
|
|
through the system package manager.
|
|
This means that applications can usually expect a copy of the loader to be
|
|
present on a system.
|
|
If applications want to be completely sure that a loader is present, they can
|
|
include a loader or runtime installer with their application.
|
|
|
|
#### Static Linking
|
|
|
|
In previous versions of the loader, it was possible to statically link the
|
|
loader.
|
|
**This was removed and is no longer possible.**
|
|
The decision to remove static linking was because of changes to the driver
|
|
which made older applications that statically linked unable to find newer
|
|
drivers.
|
|
|
|
Additionally, static linking posed several problems:
|
|
- The loader can never be updated without re-linking the application
|
|
- The possibility that two included libraries could contain different versions
|
|
of the loader
|
|
- Could cause conflicts between the different loader versions
|
|
|
|
The only exception to this is for macOS, but is not supported or tested.
|
|
|
|
### Indirectly Linking to the Loader
|
|
|
|
Applications are not required to link directly to the loader library, instead
|
|
they can use the appropriate platform-specific dynamic symbol lookup on the
|
|
loader library to initialize the application's own dispatch table.
|
|
This allows an application to fail gracefully if the loader cannot be found.
|
|
It also provides the fastest mechanism for the application to call Vulkan
|
|
functions.
|
|
An application only needs to query (via system calls such as `dlsym`) the
|
|
address of `vkGetInstanceProcAddr` from the loader library.
|
|
The application then uses `vkGetInstanceProcAddr` to load all functions
|
|
available, such as `vkCreateInstance`, `vkEnumerateInstanceExtensionProperties`
|
|
and `vkEnumerateInstanceLayerProperties` in a platform-independent way.
|
|
|
|
### Best Application Performance Setup
|
|
|
|
To get the best possible performance in a Vulkan application, the application
|
|
should set up its own dispatch table for every Vulkan API entry-point.
|
|
For every instance-level Vulkan command in the dispatch table, the function pointer
|
|
should be queried and filled in by using the results of `vkGetInstanceProcAddr`.
|
|
Additionally, for every device-level Vulkan command, the function pointer
|
|
should be queried and filled in using the results of `vkGetDeviceProcAddr`.
|
|
|
|
*Why do this?*
|
|
|
|
The answer comes in how the call chain of instance functions are implemented
|
|
versus the call chain of a device functions.
|
|
Remember, a [Vulkan instance is a high-level construct used to provide Vulkan
|
|
system-level information](LoaderInterfaceArchitecture.md#instance-specific).
|
|
Because of this, instance functions need to be broadcast to every available
|
|
driver on the system.
|
|
The following diagram shows an approximate view of an instance call chain with
|
|
three enabled layers:
|
|
|
|

|
|
|
|
This is also how a Vulkan device function call chain looks if queried
|
|
using `vkGetInstanceProcAddr`.
|
|
On the other hand, a device function doesn't need to worry about the broadcast
|
|
because it knows specifically which associated driver and which associated
|
|
physical device the call should terminate at.
|
|
Because of this, the loader doesn't need to get involved between any enabled
|
|
layers and the driver.
|
|
Thus, using a loader-exported Vulkan device function, the call chain
|
|
in the same scenario as above would look like:
|
|
|
|

|
|
|
|
An even better solution would be for an application to perform a
|
|
`vkGetDeviceProcAddr` call on all device functions.
|
|
This further optimizes the call chain by removing the loader all-together under
|
|
most scenarios:
|
|
|
|

|
|
|
|
Also, notice if no layers are enabled, the application function pointers point
|
|
**directly to the driver**.
|
|
With many function calls, the lack of indirection in each adds up to non-trivial
|
|
performance savings.
|
|
|
|
**NOTE:** There are some device functions which still require the loader to
|
|
intercept them with a *trampoline* and *terminator*.
|
|
There are very few of these, but they are typically functions which the loader
|
|
wraps with its own data.
|
|
In those cases, even the device call chain will continue to look like the
|
|
instance call chain.
|
|
One example of a device function requiring a *terminator* is
|
|
`vkCreateSwapchainKHR`.
|
|
For that function, the loader needs to potentially convert the KHR_surface
|
|
object into an driver-specific KHR_surface object prior to passing down the rest
|
|
of the function's information to the driver.
|
|
|
|
Remember:
|
|
* `vkGetInstanceProcAddr` is used to query instance and physical device
|
|
functions, but can query all functions.
|
|
* `vkGetDeviceProcAddr` is only used to query device functions.
|
|
|
|
|
|
### 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 and versioning of the Vulkan loader library is specified so
|
|
an app can link to the correct Vulkan ABI library version.
|
|
ABI backwards compatibility is guaranteed for all versions with the same major
|
|
number (e.g. 1.0 and 1.1).
|
|
|
|
#### Windows Dynamic Library Usage
|
|
|
|
On Windows, the loader library encodes the ABI version in its name such that
|
|
multiple ABI incompatible versions of the loader can peacefully coexist on a
|
|
given system.
|
|
The Vulkan loader library file name is `vulkan-<ABI version>.dll`.
|
|
For example, for Vulkan version 1.X on Windows the library filename is
|
|
`vulkan-1.dll`.
|
|
This library file can typically be found in the `windows\system32`
|
|
directory (on 64-bit Windows installs, the 32-bit version of the loader with
|
|
the same name can be found in the `windows\sysWOW64` directory).
|
|
|
|
#### Linux Dynamic Library Usage
|
|
|
|
For Linux, shared libraries are versioned based on a suffix.
|
|
Thus, the ABI number is not encoded in the base of the library filename as on
|
|
Windows.
|
|
|
|
On Linux, applications that have a hard dependency on Vulkan should request
|
|
linking to the unversioned name `libvulkan.so` in their build system.
|
|
For example by importing the CMake target `Vulkan::Vulkan` or by using the
|
|
output of `pkg-config --cflags --libs vulkan` as compiler flags.
|
|
As usual for Linux libraries, the compiler and linker will resolve this to
|
|
a dependency on the correct versioned SONAME, currently `libvulkan.so.1`.
|
|
Linux applications that load Vulkan-Loader dynamically at runtime do not
|
|
benefit from this mechanism, and should instead make sure to pass the
|
|
versioned name such as `libvulkan.so.1` to `dlopen()`, to ensure that they
|
|
load a compatible version.
|
|
|
|
#### MacOs Dynamic Library Usage
|
|
|
|
MacOs linking is similar to Linux, with the exception being that the standard
|
|
dynamic library is named `libvulkan.dylib` and the ABI versioned library is
|
|
currently named `libvulkan.1.dylib`.
|
|
|
|
|
|
### Bundling the Loader With An Application
|
|
|
|
The Khronos loader is typically installed on platforms either in a
|
|
platform-specific way (i.e. packages on Linux) or as part of a driver install
|
|
(i.e. using the Vulkan Runtime installer on Windows).
|
|
Applications or engines may desire to install the Vulkan loader locally to their
|
|
execution tree as part of their own installation process.
|
|
This may be because providing the specific loader:
|
|
|
|
1) Guarantees certain Vulkan API exports are available in the loader
|
|
2) Ensures certain loader behavior is well-known
|
|
3) Provides consistency across user installation
|
|
|
|
However, this is **strongly discouraged** because:
|
|
|
|
1) The packaged loader may not be compatible with future driver revisions
|
|
(this can be especially true on Windows where driver install locations can
|
|
change during updates to the OS)
|
|
2) It can prevent the application/engine from taking advantage of new Vulkan
|
|
API version/extension exports
|
|
3) The application/engine will miss out on important loader bug-fixes
|
|
4) The packaged loader will not contain useful feature updates (like
|
|
improved loader debugability)
|
|
|
|
Of course, even if an application/engine does initially release with a specific
|
|
version of the Khronos loader, it may chose to update or remove that loader at
|
|
some point in the future.
|
|
This could be due to the exposure of needed functionality in the loader as time
|
|
progresses.
|
|
But, that relies upon end-users correctly performing whatever update process is
|
|
necessary at that future time which may result in different behavior across
|
|
different user's systems.
|
|
|
|
One better alternative, at least on Windows, is to package the Vulkan Runtime
|
|
installer for the desired version of the Vulkan loader with your product.
|
|
Then, the installation process can use that to ensure the end-user's system
|
|
is up to date.
|
|
The Runtime installer will detect the version already installed and will only
|
|
install a newer runtime if necessary.
|
|
|
|
Another alternative is to write the application so it can fallback to earlier
|
|
versions of Vulkan yet display a warning indicating functionality is disabled
|
|
until the user updates their system to a specific runtime/driver.
|
|
|
|
|
|
## Application Layer Usage
|
|
|
|
Applications desiring Vulkan functionality beyond what Vulkan drivers
|
|
on their system already expose, may use various layers to augment the API.
|
|
A layer cannot add new Vulkan core API entry-points that are not exposed in
|
|
Vulkan.h.
|
|
However, layers may offer implementations of extensions that introduce
|
|
additional entry-points beyond what is available without those layers.
|
|
These additional extension entry-points can be queried through the Vulkan
|
|
extension interface.
|
|
|
|
A common use of layers is for API validation which can be enabled during
|
|
application development and left out when releasing the application.
|
|
This allows easy control of the overhead resulting from enabling validation of
|
|
the application's usage of the API, which wasn't always possible in previous
|
|
graphics APIs.
|
|
|
|
To find out what layers are available to an application, use
|
|
`vkEnumerateInstanceLayerProperties`.
|
|
This will report all layers that have been discovered by the loader.
|
|
The loader looks in various locations to find layers on the system.
|
|
For more information see the
|
|
[Layer discovery](LoaderLayerInterface.md#layer-discovery)
|
|
section in the
|
|
[LoaderLayerInterface.md document](LoaderLayerInterface.md) document.
|
|
|
|
To enable specific layers, simply pass the names of the layers to
|
|
enable in the `ppEnabledLayerNames` field of the `VkInstanceCreateInfo` during
|
|
a call to `vkCreateInstance`.
|
|
Once done, the layers that have been enabled will be active for all Vulkan functions
|
|
using the created `VkInstance`, and any of its child objects.
|
|
|
|
**NOTE:** Layer ordering is important in several cases since some layers
|
|
interact with each other.
|
|
Be careful when enabling layers as this may be the case.
|
|
See the [Overall Layer Ordering](#overall-layer-ordering) section for more
|
|
information.
|
|
|
|
The following code section shows how to go about enabling the
|
|
`VK_LAYER_KHRONOS_validation` layer.
|
|
|
|
```
|
|
char *instance_layers[] = {
|
|
"VK_LAYER_KHRONOS_validation"
|
|
};
|
|
const VkApplicationInfo app = {
|
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
.pNext = NULL,
|
|
.pApplicationName = "TEST_APP",
|
|
.applicationVersion = 0,
|
|
.pEngineName = "TEST_ENGINE",
|
|
.engineVersion = 0,
|
|
.apiVersion = VK_API_VERSION_1_0,
|
|
};
|
|
VkInstanceCreateInfo inst_info = {
|
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.pApplicationInfo = &app,
|
|
.enabledLayerCount = 1,
|
|
.ppEnabledLayerNames = (const char *const *)instance_layers,
|
|
.enabledExtensionCount = 0,
|
|
.ppEnabledExtensionNames = NULL,
|
|
};
|
|
err = vkCreateInstance(&inst_info, NULL, &demo->inst);
|
|
if (VK_ERROR_LAYER_NOT_PRESENT == err) {
|
|
// Couldn't find the validation layer
|
|
}
|
|
```
|
|
|
|
At `vkCreateInstance` and `vkCreateDevice`, the loader constructs call chains
|
|
that include the application specified (enabled) layers.
|
|
Order is important in the `ppEnabledLayerNames` array; array element 0 is the
|
|
topmost (closest to the application) layer inserted in the chain and the last
|
|
array element is closest to the driver.
|
|
See the [Overall Layer Ordering](#overall-layer-ordering) section for more
|
|
information on layer ordering.
|
|
|
|
**NOTE:** *Device Layers Are Now Deprecated*
|
|
> `vkCreateDevice` originally was able to select layers in a similar manner to
|
|
`vkCreateInstance`.
|
|
> This led to the concept of "instance layers" and "device layers".
|
|
> It was decided by Khronos to deprecate the "device layer" functionality and
|
|
> only consider "instance layers".
|
|
> Therefore, `vkCreateDevice` will use the layers specified at
|
|
`vkCreateInstance`.
|
|
> Because of this, the following items have been deprecated:
|
|
> * `VkDeviceCreateInfo` fields:
|
|
> * `ppEnabledLayerNames`
|
|
> * `enabledLayerCount`
|
|
> * The `vkEnumerateDeviceLayerProperties` function
|
|
|
|
|
|
### Meta-Layers
|
|
|
|
Meta-layers are layers which contain an ordered list of other layers to enable.
|
|
This is to allow grouping layers together in a specified order so that they can
|
|
interact properly.
|
|
Originally, this was used to group together the individual Vulkan Validation
|
|
layers in the proper order to avoid conflicts.
|
|
It was necessary because instead of a single Validation layer, validation was
|
|
split into multiple component layers.
|
|
The new `VK_LAYER_KHRONOS_validation` layer pulled everything into a single
|
|
layer, dropping the need for meta layers.
|
|
While not necessary for validation anymore, VkConfig does use meta layers to
|
|
group layers together based on user's preferences.
|
|
More can be found out about this functionality through both the
|
|
[VkConfig documentation](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/README.md)
|
|
and the section later on the [Override Layer](#override-layer).
|
|
|
|
Meta-layers are detailed more in the
|
|
[Meta-Layers](LoaderLayerInterface.md#meta-layers) section of the
|
|
[LoaderLayerInterface.md](LoaderLayerInterface.md) file in this folder.
|
|
|
|
|
|
### Implicit vs Explicit Layers
|
|
|
|

|
|
|
|
Explicit layers are layers which are enabled by an application (e.g. with the
|
|
vkCreateInstance function as mentioned previously).
|
|
|
|
Implicit layers are enabled automatically by their very existence, unless
|
|
requiring an additional manual enable step, unlike explicit layers that must be
|
|
enabled explicitly.
|
|
For example, certain application environments (e.g. Steam or an automotive
|
|
infotainment system) may have layers which they always want enabled for all
|
|
applications that they start.
|
|
Other implicit layers may be for all applications started on a given system
|
|
(e.g. layers that overlay frames-per-second).
|
|
|
|
Implicit layers have an additional requirement over explicit layers in that
|
|
they require being able to be disabled by an environmental variable.
|
|
This is due to the fact that they are not visible to the application and could
|
|
cause issues.
|
|
A good principle to keep in mind would be to define both an enable and disable
|
|
environment variable so the users can deterministically enable the
|
|
functionality.
|
|
On Desktop platforms (Windows, Linux, and macOS), these enable/disable settings
|
|
are defined in the layer's JSON file.
|
|
|
|
Discovery of system-installed implicit and explicit layers is described later
|
|
in the [Layer discovery](LoaderLayerInterface.md#layer-discovery)
|
|
section in the
|
|
[LoaderLayerInterface.md](LoaderLayerInterface.md) document.
|
|
|
|
Implicit and explicit layers may be found in different locations based on the
|
|
underlying operating system.
|
|
The table below details more information:
|
|
|
|
<table style="width:100%">
|
|
<tr>
|
|
<th>Operating System</th>
|
|
<th>Implicit Layer Identification</th>
|
|
</tr>
|
|
<tr>
|
|
<td>Windows</td>
|
|
<td>Implicit layers are located in a different Windows registry location
|
|
than explicit layers.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Linux</td>
|
|
<td>Implicit layers are located in a different directory location than
|
|
explicit layers.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Android</td>
|
|
<td>There is **No Support For Implicit Layers** on Android.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>macOS</td>
|
|
<td>Implicit layers are located in a different directory location than
|
|
explicit layers.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
|
|
#### Override Layer
|
|
|
|
The "Override Layer" is a special implicit meta-layer created by the
|
|
[VkConfig](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/README.md)
|
|
tool and available by default when the tool is running.
|
|
Once VkConfig exits, the override layer is removed, and the system should
|
|
return to standard Vulkan behavior.
|
|
Whenever the override layer is present in the layer search path, the loader will
|
|
pull it into the layer call stack with the standard implicit layers along with
|
|
all layers contained in the list of layers to load.
|
|
This allows an end-user or developer to easily force on any number of layers
|
|
and settings via VkConfig.
|
|
|
|
The override layer is discussed more in the
|
|
[Override Meta-Layer](LoaderLayerInterface.md#override-meta-layer) section of the
|
|
[LoaderLayerInterface.md](LoaderLayerInterface.md) file in this folder.
|
|
|
|
|
|
### Forcing Layer Source Folders
|
|
|
|
Developers may need to use special, pre-production layers, without modifying
|
|
the system-installed layers.
|
|
|
|
This can be accomplished in one of two ways:
|
|
|
|
1. Selecting specific layer paths using the
|
|
[VkConfig](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/README.md)
|
|
tool shipped with the Vulkan SDK.
|
|
2. Directing the loader to look for layers in specific files and/or folders by using the
|
|
`VK_LAYER_PATH` environment variable.
|
|
|
|
The `VK_LAYER_PATH` environment variable can contain multiple paths separated by
|
|
the operating-system specific path separator.
|
|
On Windows, this is a semicolon (`;`), while on Linux and macOS it is a colon
|
|
(`:`).
|
|
|
|
If `VK_LAYER_PATH` exists, the files and/or folders listed will be scanned for explicit
|
|
layer manifest files.
|
|
Implicit layer discovery is unaffected by this environment variable.
|
|
Each directory listed should be the full pathname of a folder containing layer
|
|
manifest files.
|
|
|
|
See the
|
|
[Table of Debug Environment Variables](LoaderInterfaceArchitecture.md#table-of-debug-environment-variables)
|
|
in the [LoaderInterfaceArchitecture.md document](LoaderInterfaceArchitecture.md)
|
|
for more details.
|
|
|
|
|
|
#### Exception for Elevated Privileges
|
|
|
|
For security reasons, `VK_LAYER_PATH` is ignored if running with elevated
|
|
privileges.
|
|
Because of this, `VK_LAYER_PATH` 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.
|
|
|
|
|
|
### Forcing Layers to be Enabled on Windows, Linux and macOS
|
|
|
|
Developers may want to enable layers that are not enabled by the given
|
|
application they are using.
|
|
|
|
This can be also be accomplished in one of two ways:
|
|
|
|
1. Selecting specific layers using the
|
|
[VkConfig](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/README.md)
|
|
tool shipped with the Vulkan SDK.
|
|
2. Directing the loader to look for additional layers by name using the
|
|
`VK_INSTANCE_LAYERS` environment variable.
|
|
|
|
Both can be used to enable additional layers which are not specified (enabled)
|
|
by the application at `vkCreateInstance`.
|
|
|
|
The `VK_INSTANCE_LAYERS` environment variable is a list of layer names to enable
|
|
separated by the operating-system specific path separator.
|
|
On Windows, this is a semicolon (`;`), while on Linux and macOS it is a colon
|
|
(`:`).
|
|
The order of the names is relevant with the first layer name in the list being
|
|
the top-most layer (closest to the application) and the last layer name in the
|
|
list being the bottom-most layer (closest to the driver).
|
|
See the [Overall Layer Ordering](#overall-layer-ordering) section for more
|
|
information.
|
|
|
|
Application specified layers and user specified layers (via environment
|
|
variables) are aggregated and duplicates removed by the loader when enabling
|
|
layers.
|
|
Layers specified via environment variable are top-most (closest to the
|
|
application) while layers specified by the application are bottom-most.
|
|
|
|
An example of using these environment variables to activate the validation
|
|
layer `VK_LAYER_KHRONOS_validation` on Linux or macOS is as follows:
|
|
|
|
```
|
|
> $ export VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation
|
|
```
|
|
|
|
See the
|
|
[Table of Debug Environment Variables](LoaderInterfaceArchitecture.md#table-of-debug-environment-variables)
|
|
in the [LoaderInterfaceArchitecture.md document](LoaderInterfaceArchitecture.md)
|
|
for more details.
|
|
|
|
|
|
### Overall Layer Ordering
|
|
|
|
The overall ordering of all layers by the loader based on the above looks
|
|
as follows:
|
|
|
|

|
|
|
|
Ordering may also be important internally to the list of explicit layers.
|
|
Some layers may be dependent on other behavior being implemented before
|
|
or after the loader calls it.
|
|
For example: An overlay layer may want to use `VK_LAYER_KHRONOS_validation`
|
|
to verify that the overlay layer is behaving appropriately.
|
|
This requires putting the overlay layer closer to the application so that the
|
|
validation layer can intercept any Vulkan API calls the overlay layer needs to
|
|
make to function.
|
|
|
|
|
|
### Debugging Possible Layer Issues
|
|
|
|
If it is possible that a layer is causing issues, there are several things that
|
|
can be tried which are documented in the
|
|
[Debugging Possible Layer Issues](LoaderDebugging.md#debugging-possible-layer-issues)
|
|
section of the [LoaderDebugging.mg](LoaderDebugging.md) document in the docs
|
|
folder.
|
|
|
|
|
|
## Application Usage of Extensions
|
|
|
|
Extensions are optional functionality provided by a layer, the loader, or a
|
|
driver.
|
|
Extensions can modify the behavior of the Vulkan API and need to be specified
|
|
and registered with Khronos.
|
|
These extensions can be implemented by a Vulkan driver, the loader, or a layer
|
|
to expose functionality not available in the core API.
|
|
Information about various extensions can be found in the Vulkan Spec, and
|
|
vulkan.h header file.
|
|
|
|
|
|
### Instance and Device Extensions
|
|
|
|
As hinted at in the
|
|
[Instance Versus Device](LoaderInterfaceArchitecture.md#instance-versus-device)
|
|
section of the main
|
|
[LoaderInterfaceArchitecture.md](LoaderInterfaceArchitecture.md) document,
|
|
there are two types of extensions:
|
|
* Instance Extensions
|
|
* Device Extensions
|
|
|
|
An instance extension modifies existing behavior or implements new behavior on
|
|
instance-level objects, such as `VkInstance` and `VkPhysicalDevice`.
|
|
A device extension does the same for device-level objects, such as `VkDevice`,
|
|
`VkQueue`, and `VkCommandBuffer` as well as any children of those objects.
|
|
|
|
It is **very** important to know what the type of an extension is because
|
|
instance extensions must be enabled with `vkCreateInstance` while device
|
|
extensions are enabled with `vkCreateDevice`.
|
|
|
|
When calling `vkEnumerateInstanceExtensionProperties` and
|
|
`vkEnumerateDeviceExtensionProperties`, the loader discovers and aggregates all
|
|
extensions of their respective type from layers (both explicit and implicit),
|
|
drivers, and the loader before reporting them to the application.
|
|
|
|
Looking at `vulkan.h`, both functions are very similar,
|
|
for example, the `vkEnumerateInstanceExtensionProperties` prototype looks as
|
|
follows:
|
|
|
|
```
|
|
VkResult
|
|
vkEnumerateInstanceExtensionProperties(
|
|
const char *pLayerName,
|
|
uint32_t *pPropertyCount,
|
|
VkExtensionProperties *pProperties);
|
|
```
|
|
|
|
While the `vkEnumerateDeviceExtensionProperties` prototype looks like:
|
|
|
|
```
|
|
VkResult
|
|
vkEnumerateDeviceExtensionProperties(
|
|
VkPhysicalDevice physicalDevice,
|
|
const char *pLayerName,
|
|
uint32_t *pPropertyCount,
|
|
VkExtensionProperties *pProperties);
|
|
```
|
|
|
|
The "pLayerName" parameter in these functions is used to select either a single
|
|
layer or the Vulkan platform implementation.
|
|
If "pLayerName" is NULL, extensions from Vulkan implementation components
|
|
(including loader, implicit layers, and drivers) are enumerated.
|
|
If "pLayerName" is equal to a discovered layer module name then only extensions
|
|
from that layer (which may be implicit or explicit) are enumerated.
|
|
|
|
**Note:** While device layers are deprecated, the instance enabled layers are
|
|
still present in the device call-chain.
|
|
|
|
Duplicate extensions (e.g. an implicit layer and driver might report support for
|
|
the same extension) are eliminated by the loader.
|
|
For duplicates, the driver version is reported and the layer version is culled.
|
|
|
|
Also, extensions **must be enabled** (in `vkCreateInstance` or `vkCreateDevice`)
|
|
before the functions associated with the extensions can be used.
|
|
If an extension function is queried using either `vkGetInstanceProcAddr` or
|
|
`vkGetDeviceProcAddr`, but the extension has not been enabled, undefined behavior
|
|
could result.
|
|
The Validation layers will catch this invalid API usage.
|
|
|
|
|
|
### WSI Extensions
|
|
|
|
Khronos-approved WSI extensions are available and provide Windows System
|
|
Integration support for various execution environments.
|
|
It is important to understand that some WSI extensions are valid for all
|
|
targets, but others are particular to a given execution environment (and
|
|
loader).
|
|
This Khronos loader (currently targeting Windows, Linux, macOS, Stadia, and
|
|
Fuchsia) only enables and directly exports those WSI extensions that are
|
|
appropriate to the current environment.
|
|
For the most part, the selection is done in the loader using compile-time
|
|
preprocessor flags.
|
|
All versions of the Khronos loader currently expose at least the following WSI
|
|
extension support:
|
|
- VK_KHR_surface
|
|
- VK_KHR_swapchain
|
|
- VK_KHR_display
|
|
|
|
In addition, each of the following OS targets for the loader support target-
|
|
specific extensions:
|
|
|
|
| Windowing System | Extensions available |
|
|
| ---------------- | ------------------------------------------ |
|
|
| Windows | VK_KHR_win32_surface |
|
|
| Linux (Wayland) | VK_KHR_wayland_surface |
|
|
| Linux (X11) | VK_KHR_xcb_surface and VK_KHR_xlib_surface |
|
|
| macOS (MoltenVK) | VK_MVK_macos_surface |
|
|
| QNX (Screen) | VK_QNX_screen_surface |
|
|
|
|
It is important to understand that while the loader may support the various
|
|
entry-points for these extensions, there is a handshake required to actually
|
|
use them:
|
|
* At least one physical device must support the extension(s)
|
|
* The application must use such a physical device when creating a logical
|
|
device
|
|
* The application must request the extension(s) be enabled while creating the
|
|
instance or logical device (this depends on whether or not the given extension
|
|
works with an instance or a device)
|
|
|
|
Only then can the WSI extension be properly used in a Vulkan program.
|
|
|
|
|
|
### Unknown Extensions
|
|
|
|
With the ability to expand Vulkan so easily, extensions will be created that
|
|
the loader knows nothing about.
|
|
If the extension is a device extension, the loader will pass the unknown
|
|
entry-point down the device call chain ending with the appropriate
|
|
driver entry-points.
|
|
The same thing will happen if the extension is an instance extension which
|
|
takes a physical device parameter as its first component.
|
|
However, for all other instance extensions the loader will fail to load it.
|
|
|
|
*But why doesn't the loader support unknown instance extensions?*
|
|
<br/>
|
|
Let's look again at the instance call chain:
|
|
|
|

|
|
|
|
Notice that for a normal instance function call, the loader has to handle
|
|
passing along the function call to the available drivers.
|
|
If the loader has no idea of the parameters or return value of the instance
|
|
call, it can't properly pass information along to the drivers.
|
|
There may be ways to do this, which will be explored in the future.
|
|
However, for now, the loader does not support instance extensions which don't
|
|
expose entry points that take a physical device as their first parameter.
|
|
|
|
Because the device call-chain does not normally pass through the loader
|
|
*terminator*, this is not a problem for device extensions.
|
|
Additionally, since a physical device is associated with one driver, the loader
|
|
can use a generic *terminator* pointing to one driver.
|
|
This is because both of these extensions terminate directly in the
|
|
driver they are associated with.
|
|
|
|
*Is this a big problem?*
|
|
<br/>
|
|
No!
|
|
Most extension functionality only affects either a physical or logical device
|
|
and not an instance.
|
|
Thus, the overwhelming majority of extensions should be supported with direct
|
|
loader support.
|
|
|
|
### Filtering Out Unknown Instance Extension Names
|
|
|
|
In some cases, a driver may support instance extensions that are not supported
|
|
by the loader.
|
|
For the above reasons, the loader will filter out the names of these unknown
|
|
instance extensions when an application calls
|
|
`vkEnumerateInstanceExtensionProperties`.
|
|
Additionally, this behavior will cause the loader to emit an error during
|
|
`vkCreateInstance` if the application still attempts to use one of these
|
|
extensions.
|
|
The intent is to protect applications so that they don't inadvertently use
|
|
functionality which could lead to a crash.
|
|
|
|
On the other hand, if the extension must be forced on, the filtering may be
|
|
disabled by defining the `VK_LOADER_DISABLE_INST_EXT_FILTER` environment
|
|
variable to a non-zero number.
|
|
This will effectively disable the loader's filtering of instance extension
|
|
names.
|
|
|
|
## Physical Device Ordering
|
|
|
|
Prior to the 1.3.204 loader, physical devices on Linux could be returned in an
|
|
inconsistent order.
|
|
To remedy this, the Vulkan loader will now sort devices once they have been
|
|
received from the drivers (before returning the information to any enabled
|
|
layers) in the following fashion:
|
|
* Sort based on device type (Discrete, Integrated, Virtual, all others)
|
|
* Sort internal to the types based on PCI information (Domain, Bus, Device, and
|
|
Function).
|
|
|
|
This allows for a consistent physical device order from run to run on the same
|
|
system, unless the actual underlying hardware changes.
|
|
|
|
A new environment variable is defined to give users the ability to force a
|
|
specific device, `VK_LOADER_DEVICE_SELECT`.
|
|
This environment variable should be set to the desired devices hex value for
|
|
Vendor Id and Device Id (as returned from `vkGetPhysicalDeviceProperties` in
|
|
the `VkPhysicalDeviceProperties` structure).
|
|
It should look like the following:
|
|
|
|
```
|
|
set VK_LOADER_DEVICE_SELECT=0x10de:0x1f91
|
|
```
|
|
|
|
This will force on the device with a vendor ID of "0x10de" and a device ID
|
|
of "0x1f91".
|
|
If that device is not found, this is simply ignored.
|
|
|
|
All device selection work done in the loader can be disabled by setting the
|
|
environment variable `VK_LOADER_DISABLE_SELECT` to a non-zero value.
|
|
This is intended for debug purposes to narrow down any issues with the loader
|
|
device selection mechanism, but can be used by others.
|
|
|
|
[Return to the top-level LoaderInterfaceArchitecture.md file.](LoaderInterfaceArchitecture.md)
|