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
2700 lines
112 KiB
Markdown
2700 lines
112 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/
|
||
|
||
# Layer Interface to the 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)
|
||
- [Layer Discovery](#layer-discovery)
|
||
- [Layer Manifest File Usage](#layer-manifest-file-usage)
|
||
- [Android Layer Discovery](#android-layer-discovery)
|
||
- [Windows Layer Discovery](#windows-layer-discovery)
|
||
- [Linux Layer Discovery](#linux-layer-discovery)
|
||
- [Example Linux Explicit Layer Search Path](#example-linux-explicit-layer-search-path)
|
||
- [Fuchsia Layer Discovery](#fuchsia-layer-discovery)
|
||
- [macOS Layer Discovery](#macos-layer-discovery)
|
||
- [Example macOS Implicit Layer Search Path](#example-macos-implicit-layer-search-path)
|
||
- [Layer Filtering](#layer-filtering)
|
||
- [Layer Enable Filtering](#layer-enable-filtering)
|
||
- [Layer Disable Filtering](#layer-disable-filtering)
|
||
- [Layer Special Case Disable](#layer-special-case-disable)
|
||
- [Layer Disable Warning](#layer-disable-warning)
|
||
- [Allow certain Layers to ignore Layer Disabling](#allow-certain-layers-to-ignore-layer-disabling)
|
||
- [`VK_INSTANCE_LAYERS`](#vk_instance_layers)
|
||
- [Exception for Elevated Privileges](#exception-for-elevated-privileges)
|
||
- [Layer Version Negotiation](#layer-version-negotiation)
|
||
- [Layer Call Chains and Distributed Dispatch](#layer-call-chains-and-distributed-dispatch)
|
||
- [Layer Unknown Physical Device Extensions](#layer-unknown-physical-device-extensions)
|
||
- [Reason for adding `vk_layerGetPhysicalDeviceProcAddr`](#reason-for-adding-vk_layergetphysicaldeviceprocaddr)
|
||
- [Layer Intercept Requirements](#layer-intercept-requirements)
|
||
- [Distributed Dispatching Requirements](#distributed-dispatching-requirements)
|
||
- [Layer Conventions and Rules](#layer-conventions-and-rules)
|
||
- [Layer Dispatch Initialization](#layer-dispatch-initialization)
|
||
- [Example Code for CreateInstance](#example-code-for-createinstance)
|
||
- [Example Code for CreateDevice](#example-code-for-createdevice)
|
||
- [Meta-layers](#meta-layers)
|
||
- [Override Meta-Layer](#override-meta-layer)
|
||
- [Pre-Instance Functions](#pre-instance-functions)
|
||
- [Special Considerations](#special-considerations)
|
||
- [Associating Private Data with Vulkan Objects Within a Layer](#associating-private-data-with-vulkan-objects-within-a-layer)
|
||
- [Wrapping](#wrapping)
|
||
- [Cautions About Wrapping](#cautions-about-wrapping)
|
||
- [Hash Maps](#hash-maps)
|
||
- [Creating New Dispatchable Objects](#creating-new-dispatchable-objects)
|
||
- [Versioning and Activation Interactions](#versioning-and-activation-interactions)
|
||
- [Layer Manifest File Format](#layer-manifest-file-format)
|
||
- [Layer Manifest File Version History](#layer-manifest-file-version-history)
|
||
- [Layer Manifest File Version 1.2.1](#layer-manifest-file-version-121)
|
||
- [Layer Manifest File Version 1.2.0](#layer-manifest-file-version-120)
|
||
- [Layer Manifest File Version 1.1.2](#layer-manifest-file-version-112)
|
||
- [Layer Manifest File Version 1.1.1](#layer-manifest-file-version-111)
|
||
- [Layer Manifest File Version 1.1.0](#layer-manifest-file-version-110)
|
||
- [Layer Manifest File Version 1.0.1](#layer-manifest-file-version-101)
|
||
- [Layer Manifest File Version 1.0.0](#layer-manifest-file-version-100)
|
||
- [Layer Interface Versions](#layer-interface-versions)
|
||
- [Layer Interface Version 2](#layer-interface-version-2)
|
||
- [Layer Interface Version 1](#layer-interface-version-1)
|
||
- [Layer Interface Version 0](#layer-interface-version-0)
|
||
- [Loader and Layer Interface Policy](#loader-and-layer-interface-policy)
|
||
- [Number Format](#number-format)
|
||
- [Android Differences](#android-differences)
|
||
- [Requirements of Well-Behaved Layers](#requirements-of-well-behaved-layers)
|
||
- [Requirements of a Well-Behaved Loader](#requirements-of-a-well-behaved-loader)
|
||
|
||
|
||
## Overview
|
||
|
||
This is the Layer-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.
|
||
|
||
|
||
## Layer Discovery
|
||
|
||
As mentioned in the
|
||
[Implicit versus Explicit](LoaderApplicationInterface.md#implicit-vs-explicit-layers),
|
||
section of the
|
||
[LoaderApplicationInterface.md](LoaderApplicationInterface.md) document, layers
|
||
can be categorized into two categories:
|
||
* Implicit Layers
|
||
* Explicit Layers
|
||
|
||
The main difference between the two is that implicit layers are automatically
|
||
enabled, unless overridden, and explicit layers must be enabled.
|
||
Remember, implicit layers are not present on all Operating Systems (like
|
||
Android).
|
||
|
||
On any system, the loader looks in specific areas for information on the layers
|
||
that it can load at a user's request.
|
||
The process of finding the available layers on a system is known as Layer
|
||
Discovery.
|
||
During discovery, the loader determines what layers are available, the layer
|
||
name, the layer version, and any extensions supported by the layer.
|
||
This information is provided back to an application through
|
||
`vkEnumerateInstanceLayerProperties`.
|
||
|
||
The group of layers available to the loader is known as the `Layer Library`.
|
||
This section defines an extensible interface to discover what layers are
|
||
contained in the `Layer Library`.
|
||
|
||
This section also specifies the minimal conventions and rules a layer must
|
||
follow, especially with regards to interacting with the loader and other
|
||
layers.
|
||
|
||
When searching for a layer, the loader will look through the `Layer Library` in
|
||
the order it detected them and load the layer if the name matches.
|
||
If multiple instances of the same library exist in different locations
|
||
throughout the user's system, then the one appearing first in the search order
|
||
will be used.
|
||
Each OS has its own search order that is defined in its layer discovery
|
||
section below.
|
||
If multiple manifest files in the same directory define the same layer, but
|
||
point to different library files, the order which the layers is loaded is
|
||
[random due to the behavior of readdir](https://www.ibm.com/support/pages/order-directory-contents-returned-calls-readdir).
|
||
|
||
Additionally, any duplicate layer names in either the component layer list, or
|
||
globally among all enabled layers, during calls to `vkCreateInstance` or
|
||
`vkCreateDevice` will simply be ignored by the loader.
|
||
Only the first occurrence of any layer name will be used.
|
||
|
||
|
||
### Layer Manifest File Usage
|
||
|
||
On Windows, Linux, and macOS systems, JSON-formatted manifest files are used to
|
||
store layer information.
|
||
In order to find system-installed layers, the Vulkan loader will read the JSON
|
||
files to identify the names and attributes of layers and their extensions.
|
||
The use of manifest files allows the loader to avoid loading any shared library
|
||
files when the application does not query nor request any extensions.
|
||
The format of [Layer Manifest File](#layer-manifest-file-format) is detailed
|
||
below.
|
||
|
||
The Android loader does not use manifest files.
|
||
Instead, the loader queries the layer properties using special functions known
|
||
as "introspection" functions.
|
||
The intent of these functions is to determine the same required information
|
||
gathered from reading the manifest files.
|
||
These introspection functions are not used by the Khronos loader but should be
|
||
present in layers to maintain consistency.
|
||
The specific "introspection" functions are called out in the
|
||
[Layer Manifest File Format](#layer-manifest-file-format) table.
|
||
|
||
|
||
### Android Layer Discovery
|
||
|
||
On Android, the loader looks for layers to enumerate in the
|
||
`/data/local/debug/vulkan` folder.
|
||
An application enabled for debug has the ability to enumerate and enable any
|
||
layers in that location.
|
||
|
||
|
||
### Windows Layer Discovery
|
||
|
||
In order to find system-installed layers, the Vulkan loader will scan the
|
||
values in the following Windows registry keys:
|
||
|
||
```
|
||
HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\ExplicitLayers
|
||
HKEY_CURRENT_USER\SOFTWARE\Khronos\Vulkan\ExplicitLayers
|
||
HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\ImplicitLayers
|
||
HKEY_CURRENT_USER\SOFTWARE\Khronos\Vulkan\ImplicitLayers
|
||
```
|
||
|
||
Except when running a 32-bit application on 64-bit Windows, when the loader
|
||
will instead scan the 32-bit registry location:
|
||
|
||
```
|
||
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Khronos\Vulkan\ExplicitLayers
|
||
HKEY_CURRENT_USER\SOFTWARE\WOW6432Node\Khronos\Vulkan\ExplicitLayers
|
||
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Khronos\Vulkan\ImplicitLayers
|
||
HKEY_CURRENT_USER\SOFTWARE\WOW6432Node\Khronos\Vulkan\ImplicitLayers
|
||
```
|
||
|
||
For each value in these keys which has DWORD data set to 0, the loader opens
|
||
the JSON manifest file specified by the name of the value.
|
||
Each name must be an absolute path to the manifest file.
|
||
Additionally, the `HKEY_CURRENT_USER` locations will only be searched if an
|
||
application is not being executed with administrative privileges.
|
||
This is done to ensure that an application with administrative privileges does
|
||
not run layers that did not need administrator access to install.
|
||
|
||
Because some layers are installed alongside drivers, the loader will scan
|
||
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 Vulkan, OpenGL,
|
||
and Direct3D ICD location.
|
||
|
||
The Device Adapter and Software Component key paths should be obtained through
|
||
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\VulkanExplicitLayers
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{Adapter GUID}\000X\VulkanImplicitLayers
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{Software Component GUID}\000X\VulkanExplicitLayers
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{Software Component GUID}\000X\VulkanImplicitLayers
|
||
```
|
||
|
||
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\VulkanExplicitLayersWow
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{Adapter GUID}\000X\VulkanImplicitLayersWow
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{Software Component GUID}\000X\VulkanExplicitLayersWow
|
||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{Software Component GUID}\000X\VulkanImplicitLayersWow
|
||
```
|
||
|
||
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 an absolute path to a JSON manifest file.
|
||
A key value 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.
|
||
|
||
In general, applications should install layers into the
|
||
`SOFTWARE\Khronos\Vulkan` paths.
|
||
The PnP registry locations are intended specifically for layers that are
|
||
distributed as part of a driver installation.
|
||
An application installer should not modify the device-specific registries,
|
||
while a device driver should not modify the system registries.
|
||
|
||
The Vulkan loader will open each manifest file to obtain information about the
|
||
layer, including the name or pathname of a shared library (".dll") file.
|
||
|
||
If `VK_LAYER_PATH` is defined, then the loader will look at the paths defined by
|
||
that variable for explicit layer manifest files instead of using the information
|
||
provided by the explicit layer registry keys.
|
||
|
||
If `VK_ADD_LAYER_PATH` is defined, then the loader will look at the provided
|
||
paths for explicit layer manifest files in addition to using the information
|
||
provided by the explicit layer registry keys.
|
||
The paths provided by `VK_ADD_LAYER_PATH` are added before the standard list
|
||
of search folders and will therefore be searched first.
|
||
|
||
If `VK_LAYER_PATH` is present, then `VK_ADD_LAYER_PATH` will not be used by the
|
||
loader and any values will be ignored.
|
||
|
||
For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
|
||
if running with elevated privileges.
|
||
See [Exception for Elevated Privileges](#exception-for-elevated-privileges)
|
||
for more info.
|
||
|
||
See
|
||
[Forcing Layer Source Folders](LoaderApplicationInterface.md#forcing-layer-source-folders)
|
||
in the [LoaderApplicationInterface.md document](LoaderApplicationInterface.md)
|
||
for more information on this.
|
||
|
||
|
||
### Linux Layer Discovery
|
||
|
||
On Linux, the Vulkan loader will scan for 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.
|
||
</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 layers 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 layers 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.
|
||
</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 a suffix onto it for the specific
|
||
type of layer being searched for and looks in that specific folder for
|
||
manifest files:
|
||
|
||
* Implicit Layers: Suffix = /vulkan/implicit_layer.d
|
||
* Explicit Layers: Suffix = /vulkan/explicit_layer.d
|
||
|
||
If `VK_LAYER_PATH` is defined, then the loader will look at the paths defined by
|
||
that variable for explicit layer manifest files instead of using the information
|
||
provided by the standard explicit layer paths mentioned above.
|
||
|
||
If `VK_ADD_LAYER_PATH` is defined, then the loader will look at the provided
|
||
paths for explicit layer manifest files in addition to using the information
|
||
provided by the standard explicit layer paths mentioned above.
|
||
The paths provided by `VK_ADD_LAYER_PATH` are added before the standard list
|
||
of search folders and will therefore be searched first.
|
||
|
||
If `VK_LAYER_PATH` is present, then `VK_ADD_LAYER_PATH` will not be used by the
|
||
loader and any values will be ignored.
|
||
|
||
For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
|
||
if running with elevated privileges.
|
||
See [Exception for Elevated Privileges](#exception-for-elevated-privileges)
|
||
for more info.
|
||
|
||
**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
|
||
[Forcing Layer Source Folders](LoaderApplicationInterface.md#forcing-layer-source-folders)
|
||
in the [LoaderApplicationInterface.md document](LoaderApplicationInterface.md)
|
||
for more information on this.
|
||
|
||
It is also important to note that while both `VK_LAYER_PATH` and
|
||
`VK_ADD_LAYER_PATH` will point the loader paths to search for finding the
|
||
manifest files, it does not guarantee the library files mentioned by the
|
||
manifest will immediately be found.
|
||
Often, the layer 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.
|
||
If problems occur finding a library file associated with a layer, try updating
|
||
the `LD_LIBRARY_PATH` environment variable to point at the location of the
|
||
corresponding `.so` file.
|
||
|
||
|
||
#### Example Linux Explicit Layer Search Path
|
||
|
||
For a fictional user "me" the layer manifest search path might look like the
|
||
following:
|
||
|
||
```
|
||
/home/me/.config/vulkan/explicit_layer.d
|
||
/etc/xdg/vulkan/explicit_layer.d
|
||
/usr/local/etc/vulkan/explicit_layer.d
|
||
/etc/vulkan/explicit_layer.d
|
||
/home/me/.local/share/vulkan/explicit_layer.d
|
||
/usr/local/share/vulkan/explicit_layer.d
|
||
/usr/share/vulkan/explicit_layer.d
|
||
```
|
||
|
||
### Fuchsia Layer Discovery
|
||
|
||
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-layer-discovery).
|
||
The **only** difference is that Fuchsia does not allow fallback values for
|
||
*$XDG_DATA_DIRS* or *$XDG_HOME_DIRS*.
|
||
|
||
|
||
### macOS Layer Discovery
|
||
|
||
On macOS, the Vulkan loader will scan for 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/`.
|
||
|
||
#### Example macOS Implicit Layer Search Path
|
||
|
||
For a fictional user "Me" the layer manifest search path might look like the
|
||
following:
|
||
|
||
```
|
||
<bundle>/Contents/Resources/vulkan/implicit_layer.d
|
||
/Users/Me/.config/vulkan/implicit_layer.d
|
||
/etc/xdg/vulkan/implicit_layer.d
|
||
/usr/local/etc/vulkan/implicit_layer.d
|
||
/etc/vulkan/implicit_layer.d
|
||
/Users/Me/.local/share/vulkan/implicit_layer.d
|
||
/usr/local/share/vulkan/implicit_layer.d
|
||
/usr/share/vulkan/implicit_layer.d
|
||
```
|
||
|
||
### Layer 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 enable and
|
||
disable known layers.
|
||
Known layers are those that are already found by the loader taking into account
|
||
default search paths and other environment variables
|
||
(like `VK_LAYER_PATH` or `VK_ADD_LAYER_PATH`).
|
||
|
||
The filter variables will be compared against the layer name provided in the
|
||
layer's manifest file.
|
||
|
||
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.
|
||
|
||
#### Layer Enable Filtering
|
||
|
||
The layer enable environment variable `VK_LOADER_LAYERS_ENABLE` is a
|
||
comma-delimited list of globs to search for in known layers.
|
||
The layer names are compared against the globs listed in the environment
|
||
variable, and if they match, they will automatically be added to the enabled
|
||
layer list in the loader for each application.
|
||
These layers are enabled after implicit layers but before other explicit layers.
|
||
|
||
When a layer is enabled using the `VK_LOADER_LAYERS_ENABLE` filter, and
|
||
loader logging is set to emit either warnings or layer messages, then a message
|
||
will show for each layer that has been forced on.
|
||
This message will look like the following:
|
||
|
||
```
|
||
WARNING | LAYER: Layer "VK_LAYER_LUNARG_wrap_objects" force enabled due to env var 'VK_LOADER_LAYERS_ENABLE'
|
||
```
|
||
|
||
#### Layer Disable Filtering
|
||
|
||
The layer disable environment variable `VK_LOADER_LAYERS_DISABLE` is a
|
||
comma-delimited list of globs to search for in known layers.
|
||
The layer names are compared against the globs listed in the environment
|
||
variable, and if they match, they will automatically be disabled (whether or not
|
||
the layer is Implicit or Explicit).
|
||
This means that they will not be added to the enabled layer list in the loader
|
||
for each application.
|
||
This could mean that layers requested by an application are also not enabled
|
||
such as `VK_KHRONOS_LAYER_synchronization2` which could cause some applications
|
||
to misbehave.
|
||
|
||
When a layer is disabled using the `VK_LOADER_LAYERS_DISABLE` filter, and
|
||
loader logging is set to emit either warnings or layer messages, then a message
|
||
will show for each layer that has been forcibly disabled.
|
||
This message will look like the following:
|
||
|
||
```
|
||
WARNING | LAYER: Layer "VK_LAYER_LUNARG_wrap_objects" disabled because name matches filter of env var 'VK_LOADER_LAYERS_DISABLE'
|
||
```
|
||
|
||
#### Layer Special Case Disable
|
||
|
||
Because there are different types of layers, there are 3 additional special
|
||
disable options available when using the `VK_LOADER_LAYERS_DISABLE` environment
|
||
variable.
|
||
|
||
These are:
|
||
|
||
* `~all~`
|
||
* `~implicit~`
|
||
* `~explicit~`
|
||
|
||
`~all~` will effectively disable every layer.
|
||
This enables a developer to disable all layers on the system.
|
||
`~implicit~` will effectively disable every implicit layer (leaving explicit
|
||
layers still present in the application call chain).
|
||
`~explicit~` will effectively disable every explicit layer (leaving implicit
|
||
layers still present in the application call chain).
|
||
|
||
#### Layer Disable Warning
|
||
|
||
Disabling layers, whether just through normal usage of
|
||
`VK_LOADER_LAYERS_DISABLE` or by evoking one of the special disable options like
|
||
`~all~` or `~explicit~` could cause application breakage if the application is
|
||
relying on features provided by one or more explicit layers.
|
||
|
||
#### Allow certain Layers to ignore Layer Disabling
|
||
|
||
**NOTE:** VK_LOADER_LAYERS_DISABLE is only available with Loaders built with version
|
||
1.3.262 of the Vulkan headers and later.
|
||
|
||
The layer allow environment variable `VK_LOADER_LAYERS_ALLOW` is a
|
||
comma-delimited list of globs to search for in known layers.
|
||
The layer names are compared against the globs listed in the environment
|
||
variable, and if they match, they will not be able to be disabled by
|
||
`VK_LOADER_LAYERS_DISABLE`.
|
||
|
||
Implicit layers have the ability to only be enabled when a layer specified
|
||
environment variable is set, allow for context dependent enablement.
|
||
`VK_LOADER_LAYERS_ENABLE` ignores that context.
|
||
`VK_LOADER_LAYERS_ALLOW` behaves similar to `VK_LOADER_LAYERS_ENABLE` while
|
||
also respecting the context which is normally used to determine whether an
|
||
implicit layer should be enabled.
|
||
|
||
`VK_LOADER_LAYERS_ALLOW` effectively negates the behavior of
|
||
`VK_LOADER_LAYERS_DISABLE`.
|
||
Explicit layers listed by `VK_LOADER_LAYERS_ALLOW` will not be enabled.
|
||
Implicit layers listed by ``VK_LOADER_LAYERS_ALLOW` which are always active,
|
||
i.e. they do not require any external context to be enabled, will be enabled.
|
||
|
||
##### `VK_INSTANCE_LAYERS`
|
||
|
||
The original `VK_INSTANCE_LAYERS` can be viewed as a special case of the new
|
||
`VK_LOADER_LAYERS_ENABLE`.
|
||
Because of this, any layers enabled via `VK_INSTANCE_LAYERS` will be treated the
|
||
same as layers enabled with `VK_LOADER_LAYERS_ENABLE` and will therefore
|
||
override any disables supplied in `VK_LOADER_LAYERS_DISABLE`.
|
||
|
||
### Exception for Elevated Privileges
|
||
|
||
For security reasons, `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are 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.
|
||
|
||
## Layer Version Negotiation
|
||
|
||
Now that a layer has been discovered, an application can choose to load it, or
|
||
in the case of implicit layers, it can be loaded by default.
|
||
When the loader attempts to load the layer, the first thing it does is attempt
|
||
to negotiate the version of the loader to layer interface.
|
||
In order to negotiate the loader/layer interface version, the layer must
|
||
implement the `vkNegotiateLoaderLayerInterfaceVersion` function.
|
||
The following information is provided for this interface in
|
||
include/vulkan/vk_layer.h:
|
||
|
||
```cpp
|
||
typedef enum VkNegotiateLayerStructType {
|
||
LAYER_NEGOTIATE_INTERFACE_STRUCT = 1,
|
||
} VkNegotiateLayerStructType;
|
||
|
||
typedef struct VkNegotiateLayerInterface {
|
||
VkNegotiateLayerStructType sType;
|
||
void *pNext;
|
||
uint32_t loaderLayerInterfaceVersion;
|
||
PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
|
||
PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr;
|
||
PFN_GetPhysicalDeviceProcAddr pfnGetPhysicalDeviceProcAddr;
|
||
} VkNegotiateLayerInterface;
|
||
|
||
VkResult
|
||
vkNegotiateLoaderLayerInterfaceVersion(
|
||
VkNegotiateLayerInterface *pVersionStruct);
|
||
```
|
||
|
||
The `VkNegotiateLayerInterface` structure is similar to other Vulkan structures.
|
||
The "sType" field, in this case takes a new enum defined just for internal
|
||
loader/layer interfacing use.
|
||
The valid values for "sType" could grow in the future, but right now only
|
||
has the one value "LAYER_NEGOTIATE_INTERFACE_STRUCT".
|
||
|
||
This function (`vkNegotiateLoaderLayerInterfaceVersion`) should be exported by
|
||
the layer so that using "GetProcAddress" on Windows or "dlsym" on Linux or
|
||
macOS, should return a valid function pointer to it.
|
||
Once the loader has grabbed a valid address to the layers function, the loader
|
||
will create a variable of type `VkNegotiateLayerInterface` and initialize it
|
||
in the following ways:
|
||
1. Set the structure "sType" to "LAYER_NEGOTIATE_INTERFACE_STRUCT"
|
||
2. Set pNext to NULL.
|
||
- This is for future growth
|
||
3. Set "loaderLayerInterfaceVersion" to the current version the loader desires
|
||
to set the interface to.
|
||
- The minimum value sent by the loader will be 2 since it is the first
|
||
version supporting this function.
|
||
|
||
The loader will then individually call each layer’s
|
||
`vkNegotiateLoaderLayerInterfaceVersion` function with the filled out
|
||
“VkNegotiateLayerInterface”.
|
||
|
||
This function allows the loader and layer to agree on an interface version to
|
||
use.
|
||
The "loaderLayerInterfaceVersion" field is both an input and output parameter.
|
||
"loaderLayerInterfaceVersion" is filled in by the loader with the desired
|
||
latest interface version supported by the loader (typically the latest).
|
||
The layer 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 layer,
|
||
this should be the first call made by a loader to the layer (even prior to any
|
||
calls to `vkGetInstanceProcAddr`).
|
||
|
||
If the layer receiving the call no longer supports the interface version
|
||
provided by the loader (due to deprecation), then it should report a
|
||
`VK_ERROR_INITIALIZATION_FAILED` error.
|
||
Otherwise it sets the value pointed by "loaderLayerInterfaceVersion" to the
|
||
latest interface version supported by both the layer and the loader and returns
|
||
`VK_SUCCESS`.
|
||
|
||
The layer should report `VK_SUCCESS` in case the loader-provided interface
|
||
version is newer than that supported by the layer, as it's the loader's
|
||
responsibility to determine whether it can support the older interface version
|
||
supported by the layer.
|
||
The layer 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 "loaderLayerInterfaceVersion" will contain
|
||
the desired interface version to be used by the layer.
|
||
|
||
If the loader receives `VK_ERROR_INITIALIZATION_FAILED` instead of `VK_SUCCESS`,
|
||
then the loader will treat the layer as unusable and will not load it.
|
||
In this case, the application will not see the layer during enumeration.
|
||
*Note that the loader is currently backwards compatible with all layer
|
||
interface versions, so a layer should not be able to request a version
|
||
older than what the loader supports.*
|
||
|
||
This function **MUST NOT** call down the layer chain to the next layer.
|
||
The loader will work with each layer individually.
|
||
|
||
If the layer supports the new interface and reports version 2 or greater, then
|
||
The layer should fill in the function pointer values to its internal
|
||
functions:
|
||
- "pfnGetInstanceProcAddr" should be set to the layer’s internal
|
||
`GetInstanceProcAddr` function.
|
||
- "pfnGetDeviceProcAddr" should be set to the layer’s internal
|
||
`GetDeviceProcAddr` function.
|
||
- "pfnGetPhysicalDeviceProcAddr" should be set to the layer’s internal
|
||
`GetPhysicalDeviceProcAddr` function.
|
||
- If the layer supports no physical device extensions, it may set the
|
||
value to NULL.
|
||
- More on this function later
|
||
the loader will use the “fpGetInstanceProcAddr” and “fpGetDeviceProcAddr”
|
||
functions from the “VkNegotiateLayerInterface” structure.
|
||
Prior to these changes, the loader would query each of those functions using
|
||
"GetProcAddress" on Windows or "dlsym" on Linux or macOS.
|
||
|
||
|
||
## Layer Call Chains and Distributed Dispatch
|
||
|
||
There are two key architectural features that drive the loader to
|
||
`Layer Library` interface:
|
||
1. Separate and distinct instance and device call chains
|
||
2. Distributed dispatch.
|
||
|
||
For further information, read the overview of dispatch tables and call chains
|
||
above in the
|
||
[Dispatch Tables and Call Chains](LoaderInterfaceArchitecture.md#dispatch-tables-and-call-chains)
|
||
section of the
|
||
[LoaderInterfaceArchitecture.md document](LoaderInterfaceArchitecture.md).
|
||
|
||
What's important to note here is that a layer can intercept Vulkan instance
|
||
functions, device functions or both.
|
||
For a layer to intercept instance functions, it must participate in the
|
||
instance call chain.
|
||
For a layer to intercept device functions, it must participate in the device
|
||
call chain.
|
||
|
||
Remember, a layer does not need to intercept all instance or device functions,
|
||
instead, it can choose to intercept only a subset of those functions.
|
||
|
||
Normally, when a layer intercepts a given Vulkan function, it will call down
|
||
the instance or device call chain as needed.
|
||
The loader and all layer libraries that participate in a call chain cooperate
|
||
to ensure the correct sequencing of calls from one entity to the next.
|
||
This group effort for call chain sequencing is hereinafter referred to as
|
||
**distributed dispatch**.
|
||
|
||
In distributed dispatch each layer is responsible for properly calling the next
|
||
entity in the call chain.
|
||
This means that a dispatch mechanism is required for all Vulkan functions that
|
||
a layer intercepts.
|
||
If a Vulkan function is not intercepted by a layer, or if a layer chooses to
|
||
terminate the function by not calling down the chain, then no dispatch is
|
||
needed for that particular function.
|
||
|
||
For example, if the enabled layers intercepted only certain instance functions,
|
||
the call chain would look as follows:
|
||

|
||
|
||
Likewise, if the enabled layers intercepted only a few of the device functions,
|
||
the call chain could look this way:
|
||

|
||
|
||
The loader is responsible for dispatching all core and instance extension Vulkan
|
||
functions to the first entity in the call chain.
|
||
|
||
|
||
## Layer Unknown Physical Device Extensions
|
||
|
||
Layers that intercept entrypoints which take a `VkPhysicalDevice` as the first
|
||
parameter *should* support `vk_layerGetPhysicalDeviceProcAddr`. This function
|
||
is added to the Layer Interface Version 2 and allows 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.
|
||
|
||
```cpp
|
||
PFN_vkVoidFunction
|
||
vk_layerGetPhysicalDeviceProcAddr(
|
||
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 layer.
|
||
|
||
Implementations of the function should have the following behavior:
|
||
* If it is the name of a physical device function supported by the layer,
|
||
the pointer to the layer's corresponding function should be returned.
|
||
* If it is the name of a valid function which is **not** a physical device
|
||
function (i.e. an instance, device, or other function implemented by the
|
||
layer), then the value of NULL should be returned.
|
||
* The layer doesn't call down since the command is not a physical device
|
||
extension.
|
||
* If the layer has no idea what this function is, it should call down the
|
||
layer chain to the next `vk_layerGetPhysicalDeviceProcAddr` call.
|
||
* This can be retrieved in one of two ways:
|
||
* During `vkCreateInstance`, it is passed to a layer in the chain
|
||
information passed to a layer in the `VkLayerInstanceCreateInfo` structure.
|
||
* Use `get_chain_info()` to get the pointer to the
|
||
`VkLayerInstanceCreateInfo` structure. Let's call it chain_info.
|
||
* The address is then under
|
||
chain_info->u.pLayerInfo->pfnNextGetPhysicalDeviceProcAddr
|
||
* See
|
||
[Example Code for CreateInstance](#example-code-for-createinstance)
|
||
* Using the next layer’s `GetInstanceProcAddr` function to query for
|
||
`vk_layerGetPhysicalDeviceProcAddr`.
|
||
|
||
If a layer intends to support functions that take VkPhysicalDevice as the
|
||
dispatchable parameter, then layer should support
|
||
`vk_layerGetPhysicalDeviceProcAddr`.
|
||
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 layer does implement `vk_layerGetPhysicalDeviceProcAddr`, it should return
|
||
the address of its `vk_layerGetPhysicalDeviceProcAddr` function in the
|
||
"pfnGetPhysicalDeviceProcAddr" member of the `VkNegotiateLayerInterface`
|
||
structure during [Layer Version Negotiation](#layer-version-negotiation).
|
||
Additionally, the layer should also make sure `vkGetInstanceProcAddr` returns a
|
||
valid function pointer to a query of `vk_layerGetPhysicalDeviceProcAddr`.
|
||
|
||
Note: If a layer wraps the VkInstance handle, support for
|
||
`vk_layerGetPhysicalDeviceProcAddr` is *NOT* optional and must be implemented.
|
||
|
||
The behavior of the loader's `vkGetInstanceProcAddr` with support for the
|
||
`vk_layerGetPhysicalDeviceProcAddr` 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 corresponding trampoline function.
|
||
5. Return NULL
|
||
|
||
Then, if the command gets promoted to core later, it will no
|
||
longer be set up using `vk_layerGetPhysicalDeviceProcAddr`.
|
||
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 layer should continue to support the command query via
|
||
`vk_layerGetPhysicalDeviceProcAddr`, until at least a Vulkan version bump,
|
||
because an older loader may still be attempting to use the commands.
|
||
|
||
### Reason for adding `vk_layerGetPhysicalDeviceProcAddr`
|
||
|
||
Originally, if `vkGetInstanceProcAddr` was called in the loader, it would
|
||
result in the following behavior:
|
||
1. The loader would check if core function:
|
||
- If it was, it would return the function pointer
|
||
2. The loader would check if known extension function:
|
||
- If it was, 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 layer attempted to expose new physical device
|
||
extensions the loader knew nothing about, but an application did.
|
||
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.
|
||
|
||
|
||
## Layer Intercept Requirements
|
||
|
||
* Layers intercept a Vulkan function by defining a C/C++ function with
|
||
signature **identical** to the Vulkan API for that function.
|
||
* A layer **must intercept at least** `vkGetInstanceProcAddr` and
|
||
`vkCreateInstance` to participate in the instance call chain.
|
||
* A layer **may also intercept** `vkGetDeviceProcAddr` and `vkCreateDevice`
|
||
to participate in the device call chain.
|
||
* For any Vulkan function a layer intercepts which has a non-void return
|
||
value, **an appropriate value must be returned** by the layer intercept
|
||
function.
|
||
* Most functions a layer intercepts **should call down the chain** to the
|
||
corresponding Vulkan function in the next entity.
|
||
* The common behavior for a layer is to intercept a call, perform some
|
||
behavior, then pass it down to the next entity.
|
||
* If a layer doesn't pass the information down, undefined behavior may
|
||
occur.
|
||
* This is because the function will not be received by layers further
|
||
down the chain, or any drivers.
|
||
* One function that **must never call down the chain** is:
|
||
* `vkNegotiateLoaderLayerInterfaceVersion`
|
||
* Three common functions that **may not call down the chain** are:
|
||
* `vkGetInstanceProcAddr`
|
||
* `vkGetDeviceProcAddr`
|
||
* `vk_layerGetPhysicalDeviceProcAddr`
|
||
* These functions only call down the chain for Vulkan functions that they
|
||
do not intercept.
|
||
* Layer intercept functions **may insert extra calls** to Vulkan functions in
|
||
addition to the intercept.
|
||
* For example, a layer intercepting `vkQueueSubmit` may want to add a call
|
||
to `vkQueueWaitIdle` after calling down the chain for `vkQueueSubmit`.
|
||
* This would result in two calls down the chain: First a call down the
|
||
`vkQueueSubmit` chain, followed by a call down the `vkQueueWaitIdle` chain.
|
||
* Any additional calls inserted by a layer must be on the same chain
|
||
* If the function is a device function, only other device functions
|
||
should be added.
|
||
* Likewise, if the function is an instance function, only other instance
|
||
functions should be added.
|
||
|
||
|
||
## Distributed Dispatching Requirements
|
||
|
||
- For each entry-point a layer intercepts, it must keep track of the
|
||
entry-point residing in the next entity in the chain it will call down into.
|
||
* In other words, the layer must have a list of pointers to functions of the
|
||
appropriate type to call into the next entity.
|
||
* This can be implemented in various ways but
|
||
for clarity, will be referred to as a dispatch table.
|
||
- A layer can use the `VkLayerDispatchTable` structure as a device dispatch
|
||
table (see include/vulkan/vk_dispatch_table_helper.h).
|
||
- A layer can use the `VkLayerInstanceDispatchTable` structure as a instance
|
||
dispatch table (see include/vulkan/vk_dispatch_table_helper.h).
|
||
- A Layer's `vkGetInstanceProcAddr` function uses the next entity's
|
||
`vkGetInstanceProcAddr` to call down the chain for unknown (i.e.
|
||
non-intercepted) functions.
|
||
- A Layer's `vkGetDeviceProcAddr` function uses the next entity's
|
||
`vkGetDeviceProcAddr` to call down the chain for unknown (i.e. non-intercepted)
|
||
functions.
|
||
- A Layer's `vk_layerGetPhysicalDeviceProcAddr` function uses the next entity's
|
||
`vk_layerGetPhysicalDeviceProcAddr` to call down the chain for unknown (i.e.
|
||
non-intercepted) functions.
|
||
|
||
|
||
## Layer Conventions and Rules
|
||
|
||
A layer, when inserted into an otherwise compliant Vulkan driver, <b>must</b>
|
||
still result in a compliant Vulkan driver.
|
||
The intention is for layers to have a well-defined baseline behavior.
|
||
Therefore, it must follow some conventions and rules defined below.
|
||
|
||
In order for layers to have unique names, and reduce the chance of conflicts
|
||
that could occur when the loader attempts to load these layers, layers
|
||
<b>must</b> adhere to the following naming standard:
|
||
* Start with `VK_LAYER_` prefix
|
||
* Follow the prefix with either an organization or company name (LunarG),
|
||
a unique company identifier (NV for Nvidia) or a software product name
|
||
(RenderDoc) in ALL CAPS
|
||
* Follow that with the specific name of the layer (typically lower-case but not
|
||
required to be)
|
||
* NOTE: The specific name, if more than one word, <b>must</b> be underscore
|
||
delimited
|
||
|
||
Examples of valid layer names include:
|
||
* <b>VK_LAYER_KHRONOS_validation</b>
|
||
* Organization = "KHRONOS"
|
||
* Specific name = "validation"
|
||
* <b>VK_LAYER_RENDERDOC_Capture</b>
|
||
* Application = "RENDERDOC"
|
||
* Specific name = "Capture"
|
||
* <b>VK_LAYER_VALVE_steam_fossilize_32</b>
|
||
* Organization = "VALVE"
|
||
* Application = "steam"
|
||
* Specific name = "fossilize"
|
||
* OS-modifier = "32" (for 32-bit version)
|
||
* <b>VK_LAYER_NV_nsight</b>
|
||
* Organization Acronym = "NV" (for Nvidia)
|
||
* Specific name = "nsight"
|
||
|
||
More details on layer naming can be found in the
|
||
[Vulkan style-guide](https://www.khronos.org/registry/vulkan/specs/1.2/styleguide.html#extensions-naming-conventions)
|
||
under section 3.4 "Version, Extension, and Layer Naming Conventions".
|
||
|
||
A layer is always chained with other layers.
|
||
It must not make invalid calls to, or rely on undefined behaviors of, its lower
|
||
layers.
|
||
When it changes the behavior of a function, it must make sure its upper layers
|
||
do not make invalid calls to or rely on undefined behaviors of its lower layers
|
||
because of the changed behavior.
|
||
For example, when a layer intercepts an object creation function to wrap the
|
||
objects created by its lower layers, it must make sure its lower layers never
|
||
see the wrapping objects, directly from itself or indirectly from its upper
|
||
layers.
|
||
|
||
When a layer requires host memory, it may ignore the provided allocators.
|
||
It is preferred that the layer use any provided memory allocators if the layer
|
||
is intended to run in a production environment.
|
||
For example, this usually applies to implicit layers that are always enabled.
|
||
That will allow applications to include the layer's memory usage.
|
||
|
||
Additional rules include:
|
||
- `vkEnumerateInstanceLayerProperties` **must** enumerate and **only**
|
||
enumerate the layer itself.
|
||
- `vkEnumerateInstanceExtensionProperties` **must** handle the case where
|
||
`pLayerName` is itself.
|
||
- It **must** return `VK_ERROR_LAYER_NOT_PRESENT` otherwise, including when
|
||
`pLayerName` is `NULL`.
|
||
- `vkEnumerateDeviceLayerProperties` **is deprecated and may be omitted**.
|
||
- Using this will result in undefined behavior.
|
||
- `vkEnumerateDeviceExtensionProperties` **must** handle the case where
|
||
`pLayerName` is itself.
|
||
- In other cases, it should chain to other layers.
|
||
- `vkCreateInstance` **must not** generate an error for unrecognized layer
|
||
names and extension names.
|
||
- It may assume the layer names and extension names have been validated.
|
||
- `vkGetInstanceProcAddr` intercepts a Vulkan function by returning a local
|
||
entry-point
|
||
- Otherwise it returns the value obtained by calling down the instance call
|
||
chain.
|
||
- `vkGetDeviceProcAddr` intercepts a Vulkan function by returning a local
|
||
entry-point
|
||
- Otherwise it returns the value obtained by calling down the device call
|
||
chain.
|
||
- These additional functions must be intercepted if the layer implements
|
||
device-level call chaining:
|
||
- `vkGetDeviceProcAddr`
|
||
- `vkCreateDevice`(only required for any device-level chaining)
|
||
- **NOTE:** older layer libraries may expect that
|
||
`vkGetInstanceProcAddr`
|
||
ignore `instance` when `pName` is `vkCreateDevice`.
|
||
- The specification **requires** `NULL` to be returned from
|
||
`vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` for disabled functions.
|
||
- A layer may return `NULL` itself or rely on the following layers to do so.
|
||
|
||
|
||
## Layer Dispatch Initialization
|
||
|
||
- A layer initializes its instance dispatch table within its `vkCreateInstance`
|
||
function.
|
||
- A layer initializes its device dispatch table within its `vkCreateDevice`
|
||
function.
|
||
- The loader passes a linked list of initialization structures to layers via
|
||
the "pNext" field in the `VkInstanceCreateInfo` and `VkDeviceCreateInfo`
|
||
structures for `vkCreateInstance` and `VkCreateDevice` respectively.
|
||
- The head node in this linked list is of type `VkLayerInstanceCreateInfo` for
|
||
instance and VkLayerDeviceCreateInfo for device.
|
||
See file `include/vulkan/vk_layer.h` for details.
|
||
- A VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO is used by the loader for the
|
||
"sType" field in `VkLayerInstanceCreateInfo`.
|
||
- A VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO is used by the loader for the
|
||
"sType" field in `VkLayerDeviceCreateInfo`.
|
||
- The "function" field indicates how the union field "u" should be interpreted
|
||
within `VkLayer*CreateInfo`.
|
||
The loader will set the "function" field to VK_LAYER_LINK_INFO.
|
||
This indicates "u" field should be `VkLayerInstanceLink` or
|
||
`VkLayerDeviceLink`.
|
||
- The `VkLayerInstanceLink` and `VkLayerDeviceLink` structures are the list
|
||
nodes.
|
||
- The `VkLayerInstanceLink` contains the next entity's `vkGetInstanceProcAddr`
|
||
used by a layer.
|
||
- The `VkLayerDeviceLink` contains the next entity's `vkGetInstanceProcAddr`
|
||
and `vkGetDeviceProcAddr` used by a layer.
|
||
- Given the above structures set up by the loader, layer must initialize their
|
||
dispatch table as follows:
|
||
- Find the `VkLayerInstanceCreateInfo`/`VkLayerDeviceCreateInfo` structure in
|
||
the `VkInstanceCreateInfo`/`VkDeviceCreateInfo` structure.
|
||
- Get the next entity's vkGet*ProcAddr from the "pLayerInfo" field.
|
||
- For CreateInstance get the next entity's `vkCreateInstance` by calling the
|
||
"pfnNextGetInstanceProcAddr":
|
||
pfnNextGetInstanceProcAddr(NULL, "vkCreateInstance").
|
||
- For CreateDevice get the next entity's `vkCreateDevice` by calling the
|
||
"pfnNextGetInstanceProcAddr":
|
||
pfnNextGetInstanceProcAddr(instance, "vkCreateDevice"), passing the
|
||
already created instance handle.
|
||
- Advanced the linked list to the next node: pLayerInfo = pLayerInfo->pNext.
|
||
- Call down the chain either `vkCreateDevice` or `vkCreateInstance`
|
||
- Initialize the layer dispatch table by calling the next entity's
|
||
Get*ProcAddr function once for each Vulkan function needed in the dispatch
|
||
table
|
||
|
||
## Example Code for CreateInstance
|
||
|
||
```cpp
|
||
VkResult
|
||
vkCreateInstance(
|
||
const VkInstanceCreateInfo *pCreateInfo,
|
||
const VkAllocationCallbacks *pAllocator,
|
||
VkInstance *pInstance)
|
||
{
|
||
VkLayerInstanceCreateInfo *chain_info =
|
||
get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
|
||
|
||
assert(chain_info->u.pLayerInfo);
|
||
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =
|
||
chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
|
||
PFN_vkCreateInstance fpCreateInstance =
|
||
(PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
|
||
if (fpCreateInstance == NULL) {
|
||
return VK_ERROR_INITIALIZATION_FAILED;
|
||
}
|
||
|
||
// Advance the link info for the next element of the chain.
|
||
// This ensures that the next layer gets it's layer info and not
|
||
// the info for our current layer.
|
||
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
|
||
|
||
// Continue call down the chain
|
||
VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
|
||
if (result != VK_SUCCESS)
|
||
return result;
|
||
|
||
// Init layer's dispatch table using GetInstanceProcAddr of
|
||
// next layer in the chain.
|
||
instance_dispatch_table = new VkLayerInstanceDispatchTable;
|
||
layer_init_instance_dispatch_table(
|
||
*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
|
||
|
||
// Other layer initialization
|
||
...
|
||
|
||
return VK_SUCCESS;
|
||
}
|
||
```
|
||
|
||
## Example Code for CreateDevice
|
||
|
||
```cpp
|
||
VkResult
|
||
vkCreateDevice(
|
||
VkPhysicalDevice gpu,
|
||
const VkDeviceCreateInfo *pCreateInfo,
|
||
const VkAllocationCallbacks *pAllocator,
|
||
VkDevice *pDevice)
|
||
{
|
||
VkInstance instance = GetInstanceFromPhysicalDevice(gpu);
|
||
VkLayerDeviceCreateInfo *chain_info =
|
||
get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
|
||
|
||
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =
|
||
chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
|
||
PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr =
|
||
chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
|
||
PFN_vkCreateDevice fpCreateDevice =
|
||
(PFN_vkCreateDevice)fpGetInstanceProcAddr(instance, "vkCreateDevice");
|
||
if (fpCreateDevice == NULL) {
|
||
return VK_ERROR_INITIALIZATION_FAILED;
|
||
}
|
||
|
||
// Advance the link info for the next element on the chain.
|
||
// This ensures that the next layer gets it's layer info and not
|
||
// the info for our current layer.
|
||
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
|
||
|
||
VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
|
||
if (result != VK_SUCCESS) {
|
||
return result;
|
||
}
|
||
|
||
// initialize layer's dispatch table
|
||
device_dispatch_table = new VkLayerDispatchTable;
|
||
layer_init_device_dispatch_table(
|
||
*pDevice, device_dispatch_table, fpGetDeviceProcAddr);
|
||
|
||
// Other layer initialization
|
||
...
|
||
|
||
return VK_SUCCESS;
|
||
}
|
||
```
|
||
In this case the function `GetInstanceFromPhysicalDevice` is called to get the
|
||
instance handle.
|
||
In practice, this would be done by any method a layer chooses to get an
|
||
instance handle from the physical device.
|
||
|
||
|
||
## Meta-layers
|
||
|
||
Meta-layers are a special kind of layer which is only available through the
|
||
Khronos loader.
|
||
While normal layers are associated with one particular library, a meta-layer
|
||
is actually a collection layer which contains an ordered list of other layers
|
||
(called component layers).
|
||
|
||
The benefits of a meta-layer are:
|
||
1. More than one layer may be activated using a single layer name by simply
|
||
grouping multiple layers in a meta-layer.
|
||
2. The order of individual component layers is loaded can be defined within
|
||
the meta-layer.
|
||
3. Layer configurations (internal to the meta-layer manifest file) can easily
|
||
be shared with others.
|
||
4. The loader will automatically collate all instance and device extensions in
|
||
a meta-layer's component layers, and report them as the meta-layer's properties
|
||
to the application when queried.
|
||
|
||
Restrictions to defining and using a meta-layer are:
|
||
1. A Meta-layer Manifest file **must** be a properly formatted that contains
|
||
one or more component layers.
|
||
3. All component layers **must be** present on a system for the meta-layer to
|
||
be used.
|
||
4. All component layers **must be** at the same Vulkan API major and minor
|
||
version as the meta-layer for the meta-layer to be used.
|
||
|
||
The ordering of a meta-layer's component layers in the instance or device call-
|
||
chain is simple:
|
||
* The first layer listed will be the layer closest to the application.
|
||
* The last layer listed will be the layer closest to the drivers.
|
||
|
||
Inside the meta-layer Manifest file, each component layer is listed by its
|
||
layer name.
|
||
This is the "name" tag's value associated with each component layer's Manifest
|
||
file under the "layer" or "layers" tag.
|
||
This is also the name that would normally be used when activating a layer
|
||
during `vkCreateInstance`.
|
||
|
||
Any duplicate layer names in either the component layer list, or globally among
|
||
all enabled layers, will simply be ignored by the loader.
|
||
Only the first instance of any layer name will be used.
|
||
|
||
For example, if a layer is enabled using the environment variable
|
||
`VK_INSTANCE_LAYERS` and have that same layer listed in a meta-layer, then the
|
||
environment-variable-enabled layer will be used and the component layer will
|
||
be dropped.
|
||
Likewise, if a person were to enable a meta-layer and then separately enable
|
||
one of the component layers afterwards, the second instantiation of the layer
|
||
name would be ignored.
|
||
|
||
The Manifest file formatting necessary to define a meta-layer can be found in
|
||
the [Layer Manifest File Format](#layer-manifest-file-format) section.
|
||
|
||
### Override Meta-Layer
|
||
|
||
If an implicit meta-layer was found on the system with the name
|
||
`VK_LAYER_LUNARG_override`, the loader uses it as an 'override' layer.
|
||
This is used to selectively enable and disable other layers from being loaded.
|
||
It can be applied globally or to a specific application or applications.
|
||
The override meta layer can have the following additional keys:
|
||
* `blacklisted_layers` - List of explicit layer names that should not be
|
||
loaded even if requested by the application.
|
||
* `app_keys` - List of paths to executables that the override layer applies
|
||
to.
|
||
* `override_paths` - List of paths which will be used as the search location
|
||
for component layers.
|
||
|
||
When an application starts up and the override layer is present, the loader
|
||
first checks to see if the application is in the list.
|
||
If it isn't, the override layer is not applied.
|
||
If the list is empty or if `app_keys` doesn't exist, the loader makes the
|
||
override layer global and applies it to every application upon startup.
|
||
|
||
If the override layer contains `override_paths`, then it uses this list of
|
||
paths exclusively for component layers.
|
||
Thus, it ignores both the default explicit and implicit layer layer search
|
||
locations as well as paths set by environment variables like `VK_LAYER_PATH`.
|
||
If any component layer is not present in the provided override paths, the meta
|
||
layer is disabled.
|
||
|
||
The override meta-layer is primarily enabled when using the
|
||
[VkConfig](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/README.md)
|
||
tool included in the Vulkan SDK.
|
||
It is typically only available while the VkConfig tool is actually executing.
|
||
Please refer to that documentation for more information.
|
||
|
||
## Pre-Instance Functions
|
||
|
||
Vulkan includes a small number of functions which are called without any
|
||
dispatchable object.
|
||
<b>Most layers do not intercept these functions</b>, as layers are enabled when
|
||
an instance is created.
|
||
However, under certain conditions it is possible for a layer to intercept
|
||
these functions.
|
||
|
||
One reason why a layer may desire to intercept these pre-instance functions is
|
||
to filter out extensions that would normally be returned from Vulkan drivers to
|
||
the application.
|
||
[RenderDoc](https://renderdoc.org/) is one such layer which intercepts these
|
||
pre-instance functions so that it may disable extensions it doesn't support.
|
||
|
||
In order to intercept the pre-instance functions, several conditions must be
|
||
met:
|
||
* The layer must be implicit
|
||
* The layer manifest version must be 1.1.2 or later
|
||
* The layer must export the entry-point symbols for each intercepted function
|
||
* The layer manifest must specify the name of each intercepted function in a
|
||
`pre_instance_functions` JSON object
|
||
|
||
The functions that may be intercepted in this way are:
|
||
* `vkEnumerateInstanceExtensionProperties`
|
||
* `vkEnumerateInstanceLayerProperties`
|
||
* `vkEnumerateInstanceVersion`
|
||
|
||
Pre-instance functions work differently from all other layer intercept
|
||
functions.
|
||
Other intercept functions have a function prototype identical to that of the
|
||
function they are intercepting.
|
||
They then rely on data that was passed to the layer at instance or device
|
||
creation so that layers can call down the chain.
|
||
Because there is no need to create an instance before calling the pre-instance
|
||
functions, these functions must use a separate mechanism for constructing the
|
||
call chain.
|
||
This mechanism consists of an extra parameter that will be passed to the layer
|
||
intercept function when it is called.
|
||
This parameter will be a pointer to a struct, defined as follows:
|
||
|
||
```cpp
|
||
typedef struct Vk...Chain
|
||
{
|
||
struct {
|
||
VkChainType type;
|
||
uint32_t version;
|
||
uint32_t size;
|
||
} header;
|
||
PFN_vkVoidFunction pfnNextLayer;
|
||
const struct Vk...Chain* pNextLink;
|
||
} Vk...Chain;
|
||
```
|
||
|
||
These structs are defined in the `vk_layer.h` file so that it is not necessary
|
||
to redefine the chain structs in any external code.
|
||
The name of each struct is be similar to the name of the function it
|
||
corresponds to, but the leading "V" is capitalized, and the word "Chain" is
|
||
added to the end.
|
||
For example, the struct for `vkEnumerateInstanceExtensionProperties` is called
|
||
`VkEnumerateInstanceExtensionPropertiesChain`.
|
||
Furthermore, the `pfnNextLayer` struct member is not actually a void function
|
||
pointer — its type will be the actual type of each function in the call
|
||
chain.
|
||
|
||
Each layer intercept function must have a prototype that is the same as the
|
||
prototype of the function being intercepted, except that the first parameter
|
||
must be that function's chain struct (passed as a const pointer).
|
||
For example, a function that wishes to intercept
|
||
`vkEnumerateInstanceExtensionProperties` would have the prototype:
|
||
|
||
```cpp
|
||
VkResult
|
||
InterceptFunctionName(
|
||
const VkEnumerateInstanceExtensionPropertiesChain* pChain,
|
||
const char* pLayerName,
|
||
uint32_t* pPropertyCount,
|
||
VkExtensionProperties* pProperties);
|
||
```
|
||
|
||
The name of the function is arbitrary; it can be anything provided that it is
|
||
given in the layer manifest file (see
|
||
[Layer Manifest File Format](#layer-manifest-file-format)).
|
||
The implementation of each intercept function is responsible for calling the
|
||
next item in the call chain, using the chain parameter.
|
||
This is done by calling the `pfnNextLayer` member of the chain struct, passing
|
||
`pNextLink` as the first argument, and passing the remaining function arguments
|
||
after that.
|
||
For example, a simple implementation for
|
||
`vkEnumerateInstanceExtensionProperties` that does nothing but call down the
|
||
chain would look like:
|
||
|
||
```cpp
|
||
VkResult
|
||
InterceptFunctionName(
|
||
const VkEnumerateInstanceExtensionPropertiesChain* pChain,
|
||
const char* pLayerName,
|
||
uint32_t* pPropertyCount,
|
||
VkExtensionProperties* pProperties)
|
||
{
|
||
return pChain->pfnNextLayer(
|
||
pChain->pNextLink, pLayerName, pPropertyCount, pProperties);
|
||
}
|
||
```
|
||
|
||
When using a C++ compiler, each chain type also defines a function named
|
||
`CallDown` which can be used to automatically handle the first argument.
|
||
Implementing the above function using this method would look like:
|
||
|
||
```cpp
|
||
VkResult
|
||
InterceptFunctionName(
|
||
const VkEnumerateInstanceExtensionPropertiesChain* pChain,
|
||
const char* pLayerName,
|
||
uint32_t* pPropertyCount,
|
||
VkExtensionProperties* pProperties)
|
||
{
|
||
return pChain->CallDown(pLayerName, pPropertyCount, pProperties);
|
||
}
|
||
```
|
||
|
||
Unlike with other functions in layers, the layer may not save any global data
|
||
between these function calls.
|
||
Because Vulkan does not store any state until an instance has been created, all
|
||
layer libraries are released at the end of each pre-instance call.
|
||
This means that implicit layers can use pre-instance intercepts to modify data
|
||
that is returned by the functions, but they cannot be used to record that data.
|
||
|
||
## Special Considerations
|
||
|
||
|
||
### Associating Private Data with Vulkan Objects Within a Layer
|
||
|
||
A layer may want to associate its own private data with one or more Vulkan
|
||
objects.
|
||
Two common methods to do this are hash maps and object wrapping.
|
||
|
||
|
||
#### Wrapping
|
||
|
||
The loader supports layers wrapping any Vulkan object, including dispatchable
|
||
objects.
|
||
For functions that return object handles, each layer does not touch the value
|
||
passed down the call chain.
|
||
This is because lower items may need to use the original value.
|
||
However, when the value is returned from a lower-level layer (possibly the
|
||
driver), the layer saves the handle and returns its own handle to the
|
||
layer above it (possibly the application).
|
||
When a layer receives a Vulkan function using something that it previously
|
||
returned a handle for, the layer is required to unwrap the handle and pass
|
||
along the saved handle to the layer below it.
|
||
This means that the layer **must intercept every Vulkan function which uses**
|
||
**the object in question**, and wrap or unwrap the object, as appropriate.
|
||
This includes adding support for all extensions with functions using any
|
||
object the layer wraps as well as any loader-layer interface functions such as
|
||
`vk_layerGetPhysicalDeviceProcAddr`.
|
||
|
||
Layers above the object wrapping layer will see the wrapped object.
|
||
Layers which wrap dispatchable objects must ensure that the first field in the
|
||
wrapping structure is a pointer to a dispatch table as defined in `vk_layer.h`.
|
||
Specifically, an instance wrapped dispatchable object could be as follows:
|
||
|
||
```cpp
|
||
struct my_wrapped_instance_obj_ {
|
||
VkLayerInstanceDispatchTable *disp;
|
||
// whatever data layer wants to add to this object
|
||
};
|
||
```
|
||
A device wrapped dispatchable object could be as follows:
|
||
```cpp
|
||
struct my_wrapped_instance_obj_ {
|
||
VkLayerDispatchTable *disp;
|
||
// whatever data layer wants to add to this object
|
||
};
|
||
```
|
||
|
||
Layers that wrap dispatchable objects must follow the guidelines for creating
|
||
new dispatchable objects (below).
|
||
|
||
#### Cautions About Wrapping
|
||
|
||
Layers are generally discouraged from wrapping objects, because of the
|
||
potential for incompatibilities with new extensions.
|
||
For example, let's say that a layer wraps `VkImage` objects, and properly wraps
|
||
and unwraps `VkImage` object handles for all core functions.
|
||
If a new extension is created which has functions that take `VkImage` objects
|
||
as parameters, and if the layer does not support those new functions, an
|
||
application that uses both the layer and the new extension will have undefined
|
||
behavior when those new functions are called (e.g. the application may crash).
|
||
This is because the lower-level layers and drivers won't receive the handle that
|
||
they generated.
|
||
Instead, they will receive a handle that is only known by the layer that is
|
||
wrapping the object.
|
||
|
||
Because of the potential for incompatibilities with unsupported extensions,
|
||
layers that wrap objects must check which extensions are being used by the
|
||
application, and take appropriate action if the layer is used with unsupported
|
||
extensions such as issuing a warning/error message to the user.
|
||
|
||
The reason that the validation layers wrap objects is to track the proper use
|
||
and destruction of each object.
|
||
They issue a validation error if used with unsupported extensions, alerting the
|
||
user to the potential for undefined behavior.
|
||
|
||
|
||
#### Hash Maps
|
||
|
||
Alternatively, a layer may want to use a hash map to associate data with a
|
||
given object.
|
||
The key to the map could be the object. Alternatively, for dispatchable objects
|
||
at a given level (eg device or instance) the layer may want data associated
|
||
with the `VkDevice` or `VkInstance` objects.
|
||
Since there are multiple dispatchable objects for a given `VkInstance` or
|
||
`VkDevice`, the `VkDevice` or `VkInstance` object is not a great map key.
|
||
Instead the layer should use the dispatch table pointer within the `VkDevice`
|
||
or `VkInstance` since that will be unique for a given `VkInstance` or
|
||
`VkDevice`.
|
||
|
||
|
||
### Creating New Dispatchable Objects
|
||
|
||
Layers which create dispatchable objects must take special care.
|
||
Remember that loader *trampoline* code normally fills in the dispatch table
|
||
pointer in the newly created object.
|
||
Thus, the layer must fill in the dispatch table pointer if the loader
|
||
*trampoline* will not do so.
|
||
Common cases where a layer (or driver) may create a dispatchable object without
|
||
loader *trampoline* code is as follows:
|
||
- Layers that wrap dispatchable objects
|
||
- Layers which add extensions that create dispatchable objects
|
||
- Layers which insert extra Vulkan functions in the stream of functions they
|
||
intercept from the application
|
||
- Drivers which add extensions that create dispatchable objects
|
||
|
||
The Khronos loader provides a callback that can be used for initializing a
|
||
dispatchable object.
|
||
The callback is passed as an extension structure via the `pNext` field in the
|
||
create info structure when creating an instance (`VkInstanceCreateInfo`) or
|
||
device (`VkDeviceCreateInfo`).
|
||
The callback prototype is defined as follows for instance and device callbacks
|
||
respectively (see `vk_layer.h`):
|
||
|
||
```cpp
|
||
VKAPI_ATTR VkResult VKAPI_CALL
|
||
vkSetInstanceLoaderData(
|
||
VkInstance instance,
|
||
void *object);
|
||
|
||
VKAPI_ATTR VkResult VKAPI_CALL
|
||
vkSetDeviceLoaderData(
|
||
VkDevice device,
|
||
void *object);
|
||
```
|
||
|
||
To obtain these callbacks the layer must search through the list of structures
|
||
pointed to by the "pNext" field in the `VkInstanceCreateInfo` and
|
||
`VkDeviceCreateInfo` parameters to find any callback structures inserted by the
|
||
loader.
|
||
The salient details are as follows:
|
||
- For `VkInstanceCreateInfo` the callback structure pointed to by "pNext" is
|
||
`VkLayerInstanceCreateInfo` as defined in `include/vulkan/vk_layer.h`.
|
||
- A "sType" field in of VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO within
|
||
`VkInstanceCreateInfo` parameter indicates a loader structure.
|
||
- Within `VkLayerInstanceCreateInfo`, the "function" field indicates how the
|
||
union field "u" should be interpreted.
|
||
- A "function" equal to VK_LOADER_DATA_CALLBACK indicates the "u" field will
|
||
contain the callback in "pfnSetInstanceLoaderData".
|
||
- For `VkDeviceCreateInfo` the callback structure pointed to by "pNext" is
|
||
`VkLayerDeviceCreateInfo` as defined in `include/vulkan/vk_layer.h`.
|
||
- A "sType" field in of VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO within
|
||
`VkDeviceCreateInfo` parameter indicates a loader structure.
|
||
- Within `VkLayerDeviceCreateInfo`, the "function" field indicates how the union
|
||
field "u" should be interpreted.
|
||
- A "function" equal to VK_LOADER_DATA_CALLBACK indicates the "u" field will
|
||
contain the callback in "pfnSetDeviceLoaderData".
|
||
|
||
Alternatively, if an older loader is being used that doesn't provide these
|
||
callbacks, the layer may manually initialize the newly created dispatchable
|
||
object.
|
||
To fill in the dispatch table pointer in newly created dispatchable object, the
|
||
layer should copy the dispatch pointer, which is always the first entry in the
|
||
structure, from an existing parent object of the same level (instance versus
|
||
device).
|
||
|
||
For example, if there is a newly created `VkCommandBuffer` object, then the
|
||
dispatch pointer from the `VkDevice` object, which is the parent of the
|
||
`VkCommandBuffer` object, should be copied into the newly created object.
|
||
|
||
### Versioning and Activation Interactions
|
||
|
||
There are several interacting rules concerning the activation of layers with
|
||
non-obvious results.
|
||
This not an exhaustive list but should better clarify the behavior of the
|
||
loader in complex situations.
|
||
|
||
* The Vulkan Loader in versions 1.3.228 and above will enable implicit layers
|
||
regardless of the API version specified by the application in
|
||
`VkApplicationInfo::apiVersion`.
|
||
Previous loader versions (1.3.227 and below) used to have a requirement where
|
||
implicit layer's API version must be equal to or greater than the API version
|
||
of the application for the layer to be enabled.
|
||
The change relaxed the implicit layer loading requirements because it was
|
||
determined that the perceived protection of preventing older layers running
|
||
with newer applications wasn't enough to justify the friction it caused.
|
||
This was due to older layers no longer working with newer applications
|
||
for no apparent reason, as well as older layers having to update the manifest
|
||
to work with newer applications.
|
||
The layer didn't need to do anything else to get their layer working again,
|
||
which meant that a layer didn't need to prove that their layer worked with
|
||
newer API versions.
|
||
Thus, the disabling caused confusion for users but didn't protect them from
|
||
potentially badly behaving layers.
|
||
|
||
* An implicit layer will ignore its disable environment variable being set if
|
||
it is a component in an active meta layer.
|
||
|
||
* The environment `VK_LAYER_PATH` only affects explicit layer searching, not
|
||
implicit.
|
||
Layers found in this path are treated as explicit, even if they contain all the
|
||
requisite fields to be an implicit layer.
|
||
This means they will not be implicitly enabled.
|
||
|
||
* Meta layers do not have to be implicit - they can be explicit.
|
||
It cannot be assumed that because a meta layer is present that it will be active.
|
||
|
||
* The `blacklisted_layers` member of the override meta layer will prevent both
|
||
implicitly enabled and explicitely enabled layers from activating.
|
||
Any layers in an application's `VkInstanceCreateInfo::ppEnabledLayerNames` that
|
||
are in the blacklist will not be enabled.
|
||
|
||
* The `app_keys` member of the override meta layer will make a meta layer apply
|
||
to only applications found in this list.
|
||
If there are any items in the app keys list, the meta layer isn't enabled for
|
||
any application except those found in the list.
|
||
|
||
* The `override_paths` member of the override meta layer, if present, will
|
||
replace the search paths the loader uses to find component layers.
|
||
If any component layer isn't present in the override paths, the override meta
|
||
layer is not applied.
|
||
So if an override meta layer wants to mix default and custom layer locations,
|
||
the override paths must contain both custom and default layer locations.
|
||
|
||
* If the override layer is both present and contains `override_paths`, the
|
||
paths from the environment variable `VK_LAYER_PATH` are ignored when searching
|
||
for explicit layers.
|
||
For example, when both the meta layer override paths and `VK_LAYER_PATH` are
|
||
present, none of the layers in `VK_LAYER_PATH` are discoverable, and the
|
||
loader will not find them.
|
||
|
||
|
||
## Layer Manifest File Format
|
||
|
||
The Khronos loader uses manifest files to discover available layer libraries
|
||
and layers.
|
||
It doesn't directly query the layer's dynamic library except during chaining.
|
||
This is to reduce the likelihood of loading a malicious layer into memory.
|
||
Instead, details are read from the Manifest file, which are then provided
|
||
for applications to determine what layers should actually be loaded.
|
||
|
||
The following section discusses the details of the Layer 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 layer JSON Manifest file with a single layer:
|
||
|
||
```json
|
||
{
|
||
"file_format_version" : "1.2.1",
|
||
"layer": {
|
||
"name": "VK_LAYER_LUNARG_overlay",
|
||
"type": "INSTANCE",
|
||
"library_path": "vkOverlayLayer.dll",
|
||
"library_arch" : "64",
|
||
"api_version" : "1.0.5",
|
||
"implementation_version" : "2",
|
||
"description" : "LunarG HUD layer",
|
||
"functions": {
|
||
"vkNegotiateLoaderLayerInterfaceVersion":
|
||
"OverlayLayer_NegotiateLoaderLayerInterfaceVersion"
|
||
},
|
||
"instance_extensions": [
|
||
{
|
||
"name": "VK_EXT_debug_report",
|
||
"spec_version": "1"
|
||
},
|
||
{
|
||
"name": "VK_VENDOR_ext_x",
|
||
"spec_version": "3"
|
||
}
|
||
],
|
||
"device_extensions": [
|
||
{
|
||
"name": "VK_EXT_debug_marker",
|
||
"spec_version": "1",
|
||
"entrypoints": ["vkCmdDbgMarkerBegin", "vkCmdDbgMarkerEnd"]
|
||
}
|
||
],
|
||
"enable_environment": {
|
||
"ENABLE_LAYER_OVERLAY_1": "1"
|
||
},
|
||
"disable_environment": {
|
||
"DISABLE_LAYER_OVERLAY_1": ""
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Here's a snippet with the changes required to support multiple layers per
|
||
manifest file:
|
||
```json
|
||
{
|
||
"file_format_version" : "1.0.1",
|
||
"layers": [
|
||
{
|
||
"name": "VK_LAYER_layer_name1",
|
||
"type": "INSTANCE",
|
||
...
|
||
},
|
||
{
|
||
"name": "VK_LAYER_layer_name2",
|
||
"type": "INSTANCE",
|
||
...
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
Here's an example of a meta-layer manifest file:
|
||
```json
|
||
{
|
||
"file_format_version" : "1.1.1",
|
||
"layer": {
|
||
"name": "VK_LAYER_META_layer",
|
||
"type": "GLOBAL",
|
||
"api_version" : "1.0.40",
|
||
"implementation_version" : "1",
|
||
"description" : "LunarG Meta-layer example",
|
||
"component_layers": [
|
||
"VK_LAYER_KHRONOS_validation",
|
||
"VK_LAYER_LUNARG_api_dump"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
<table style="width:100%">
|
||
<tr>
|
||
<th>JSON Node</th>
|
||
<th>Description and Notes</th>
|
||
<th>Restrictions</th>
|
||
<th>Parent</th>
|
||
<th>Introspection Query</th>
|
||
</tr>
|
||
<tr>
|
||
<td>"api_version"</td>
|
||
<td>The major.minor.patch version number of the Vulkan API that the layer
|
||
supports.
|
||
It does not require the application to make use of that API version.
|
||
It simply is an indication that the layer can support Vulkan API
|
||
instance and device functions up to and including that API version.</br>
|
||
For example: 1.0.33.
|
||
</td>
|
||
<td>None</td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkEnumerateInstanceLayerProperties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"app_keys"</td>
|
||
<td>List of paths to executables that the meta-layer applies to.
|
||
</td>
|
||
<td><b>Meta-layers Only</b></td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"blacklisted_layers"</td>
|
||
<td>List of explicit layer names that should not be loaded even if
|
||
requested by the application.
|
||
</td>
|
||
<td><b>Meta-layers Only</b></td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"component_layers"</td>
|
||
<td>Indicates the component layer names that are
|
||
part of a meta-layer.
|
||
The names listed must be the "name" identified in each of the component
|
||
layer's Mainfest file "name" tag (this is the same as the name of the
|
||
layer that is passed to the `vkCreateInstance` command).
|
||
All component layers must be present on the system and found by the
|
||
loader in order for this meta-layer to be available and activated. <br/>
|
||
<b>This field must not be present if "library_path" is defined</b>.
|
||
</td>
|
||
<td><b>Meta-layers Only</b></td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"description"</td>
|
||
<td>A high-level description of the layer and its intended use.</td>
|
||
<td>None</td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkEnumerateInstanceLayerProperties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"device_extensions"</td>
|
||
<td><b>OPTIONAL:</b> Contains the list of device extension names supported
|
||
by this layer. One "device\_extensions" node with an array of one or
|
||
more elements is required if any device extensions are supported by a
|
||
layer; otherwise the node is optional.
|
||
Each element of the array must have the nodes "name" and "spec_version"
|
||
which correspond to `VkExtensionProperties` "extensionName" and
|
||
"specVersion" respectively.
|
||
Additionally, each element of the array of device extensions must have
|
||
the node "entrypoints" if the device extension adds Vulkan API
|
||
functions; otherwise this node is not required.
|
||
The "entrypoint" node is an array of the names of all entry-points added
|
||
by the supported extension.
|
||
</td>
|
||
<td>None</td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkEnumerateDeviceExtensionProperties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"disable_environment"</td>
|
||
<td><b>REQUIRED:</b> Indicates an environment variable used to disable the
|
||
Implicit Layer (when defined to any non-empty string value).<br/>
|
||
In rare cases of an application not working with an implicit layer, the
|
||
application can set this environment variable (before calling Vulkan
|
||
functions) in order to "blacklist" the layer.
|
||
This environment variable (which may vary with each variation of the
|
||
layer) must be set (not particularly to any value).
|
||
If both the "enable_environment" and "disable_environment" variables are
|
||
set, the implicit layer is disabled.
|
||
</td>
|
||
<td><b>Implicit Layers Only</b></td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"enable_environment"</td>
|
||
<td><b>OPTIONAL:</b> Indicates an environment variable used to enable the
|
||
Implicit Layer (when defined to any non-empty string value).<br/>
|
||
This environment variable (which may vary with each variation of the
|
||
layer) must be set to the given value or else the implicit layer is not
|
||
loaded.
|
||
This is for application environments (e.g. Steam) which want to enable a
|
||
layer(s) only for applications that they launch, and allows for
|
||
applications run outside of an application environment to not get that
|
||
implicit layer(s).
|
||
</td>
|
||
<td><b>Implicit Layers Only</b></td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"file_format_version"</td>
|
||
<td>Manifest format major.minor.patch version number.<br/>
|
||
Supported versions are: 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.1.2 and 1.2.0.
|
||
</td>
|
||
<td>None</td>
|
||
<td>None</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"functions"</td>
|
||
<td><b>OPTIONAL:</b> This section can be used to identify a different
|
||
function name for the loader to use in place of standard layer interface
|
||
functions.
|
||
The "functions" node is required if the layer is using an alternative
|
||
name for `vkNegotiateLoaderLayerInterfaceVersion`.
|
||
</td>
|
||
<td>None</td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkGet*ProcAddr</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"implementation_version"</td>
|
||
<td>The version of the layer implemented.
|
||
If the layer itself has any major changes, this number should change so
|
||
the loader and/or application can identify it properly.
|
||
</td>
|
||
<td>None</td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkEnumerateInstanceLayerProperties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"instance_extensions"</td>
|
||
<td><b>OPTIONAL:</b> Contains the list of instance extension names
|
||
supported by this layer.
|
||
One "instance_extensions" node with an array of one or more elements is
|
||
required if any instance extensions are supported by a layer; otherwise
|
||
the node is optional.
|
||
Each element of the array must have the nodes "name" and "spec_version"
|
||
which correspond to `VkExtensionProperties` "extensionName" and
|
||
"specVersion" respectively.
|
||
</td>
|
||
<td>None</td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkEnumerateInstanceExtensionProperties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"layer"</td>
|
||
<td>The identifier used to group a single layer's information together.
|
||
</td>
|
||
<td>None</td>
|
||
<td>None</td>
|
||
<td><small>vkEnumerateInstanceLayerProperties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"layers"</td>
|
||
<td>The identifier used to group multiple layers' information together.
|
||
This requires a minimum Manifest file format version of 1.0.1.
|
||
</td>
|
||
<td>None</td>
|
||
<td>None</td>
|
||
<td><small>vkEnumerateInstanceLayerProperties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"library_path"</td>
|
||
<td>Specifies either a filename, a relative pathname, or a full pathname to
|
||
a layer shared library file.
|
||
If "library_path" specifies a relative pathname, it is relative to the
|
||
path of the JSON manifest file (e.g. for cases when an application
|
||
provides a layer that is in the same folder hierarchy as the rest of the
|
||
application files).
|
||
If "library_path" specifies a filename, the library must live in the
|
||
system's shared object search path.
|
||
There are no rules about the name of the layer shared library files
|
||
other than it should end with the appropriate suffix (".DLL" on Windows,
|
||
".so" on Linux, and ".dylib" on macOS).<br/>
|
||
<b>This field must not be present if "component_layers" is defined</b>.
|
||
</td>
|
||
<td><b>Not Valid For Meta-layers</b></td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<td>"library_arch"</td>
|
||
<td>Optional field which specifies the architecture of the binary associated
|
||
with "library_path". <br />
|
||
Allows the loader to quickly determine if the architecture of the layer
|
||
matches that of the running application. <br />
|
||
The only valid values are "32" and "64".</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<tr>
|
||
<td>"name"</td>
|
||
<td>The string used to uniquely identify this layer to applications.</td>
|
||
<td>None</td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkEnumerateInstanceLayerProperties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"override_paths"</td>
|
||
<td>List of paths which will be used as the search location for component
|
||
layers.
|
||
</td>
|
||
<td><b>Meta-layers Only</b></td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"pre_instance_functions"</td>
|
||
<td><b>OPTIONAL:</b> Indicates which functions the layer wishes to
|
||
intercept, that do not require that an instance has been created.
|
||
This should be an object where each function to be intercepted is
|
||
defined as a string entry where the key is the Vulkan function name and
|
||
the value is the name of the intercept function in the layer's dynamic
|
||
library.
|
||
Available in layer manifest versions 1.1.2 and up. <br/>
|
||
See <a href="#pre-instance-functions">Pre-Instance Functions</a> for
|
||
more information.
|
||
</td>
|
||
<td><b>Implicit Layers Only</b></td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkEnumerateInstance*Properties</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td>"type"</td>
|
||
<td>This field indicates the type of layer. The values can be: GLOBAL, or
|
||
INSTANCE.<br/>
|
||
<b> NOTE: </b> Prior to deprecation, the "type" node was used to
|
||
indicate which layer chain(s) to activate the layer upon: instance,
|
||
device, or both.
|
||
Distinct instance and device layers are deprecated; there are now just
|
||
instance layers.
|
||
Originally, allowable values were "INSTANCE", "GLOBAL" and, "DEVICE."
|
||
But now "DEVICE" layers are skipped over by the loader as if they were
|
||
not found.
|
||
</td>
|
||
<td>None</td>
|
||
<td>"layer"/"layers"</td>
|
||
<td><small>vkEnumerate*LayerProperties</small></td>
|
||
</tr>
|
||
</table>
|
||
|
||
### Layer Manifest File Version History
|
||
|
||
The current highest supported Layer Manifest file format supported is 1.2.0.
|
||
Information about each version is detailed in the following sub-sections:
|
||
|
||
### Layer Manifest File Version 1.2.1
|
||
|
||
Added the "library\_arch" field to the layer manifest to allow the loader to
|
||
quickly determine if the layer matches the architecture of the current running
|
||
application.
|
||
|
||
#### Layer Manifest File Version 1.2.0
|
||
|
||
The ability to define the layer settings as defined by the
|
||
[layer manifest schema](https://github.com/LunarG/VulkanTools/blob/main/vkconfig_core/layers/layers_schema.json).
|
||
|
||
The ability to briefly document the layer thanks to the fields:
|
||
* "introduction": Presentation of the purpose of the layer in a paragraph.
|
||
* "url": A link the the layer home page.
|
||
* "platforms": The list of supported platforms of the layer
|
||
* "status": The life cycle of the layer: Alpha, Beta, Stable, or Deprecated
|
||
|
||
These changes were made to enable third-party layers to expose their features
|
||
within
|
||
[Vulkan Configurator](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/README.md)
|
||
or other tools.
|
||
|
||
#### Layer Manifest File Version 1.1.2
|
||
|
||
Version 1.1.2 introduced the ability of layers to intercept function calls that
|
||
do not have an instance.
|
||
|
||
#### Layer Manifest File Version 1.1.1
|
||
|
||
The ability to define custom metalayers was added.
|
||
To support metalayers, the "component_layers" section was added, and the
|
||
requirement for a "library_path" section to be present was removed when the
|
||
"component_layers" section is present.
|
||
|
||
#### Layer Manifest File Version 1.1.0
|
||
|
||
Layer Manifest File Version 1.1.0 is tied to changes exposed by the
|
||
Loader/Layer interface version 2.
|
||
1. Renaming "vkGetInstanceProcAddr" in the "functions" section is deprecated
|
||
since the loader no longer needs to query the layer about
|
||
"vkGetInstanceProcAddr" directly.
|
||
It is now returned during the layer negotiation, so this field will be
|
||
ignored.
|
||
2. Renaming "vkGetDeviceProcAddr" in the "functions" section is
|
||
deprecated since the loader no longer needs to query the layer about
|
||
"vkGetDeviceProcAddr" directly.
|
||
It too is now returned during the layer negotiation, so this field will be
|
||
ignored.
|
||
3. Renaming the "vkNegotiateLoaderLayerInterfaceVersion" function is being
|
||
added to the "functions" section, since this is now the only function the
|
||
loader needs to query using OS-specific calls.
|
||
- NOTE: This is an optional field and, as the two previous fields, only
|
||
needed if the layer requires changing the name of the function for some reason.
|
||
|
||
The layer manifest file does not need to to be updated if the names of any
|
||
listed functions has not changed.
|
||
|
||
#### Layer Manifest File Version 1.0.1
|
||
|
||
The ability to define multiple layers using the "layers" array was added.
|
||
This JSON array field can be used when defining a single layer or multiple
|
||
layers.
|
||
The "layer" field is still present and valid for a single layer definition.
|
||
|
||
#### Layer Manifest File Version 1.0.0
|
||
|
||
The initial version of the layer manifest file specified the basic format and
|
||
fields of a layer JSON file.
|
||
The fields of the 1.0.0 file format include:
|
||
* "file\_format\_version"
|
||
* "layer"
|
||
* "name"
|
||
* "type"
|
||
* "library\_path"
|
||
* "api\_version"
|
||
* "implementation\_version"
|
||
* "description"
|
||
* "functions"
|
||
* "instance\_extensions"
|
||
* "device\_extensions"
|
||
* "enable\_environment"
|
||
* "disable\_environment"
|
||
|
||
It was also during this time that the value of "DEVICE" was deprecated from
|
||
the "type" field.
|
||
|
||
|
||
## Layer Interface Versions
|
||
|
||
The current loader/layer interface is at version 2.
|
||
The following sections detail the differences between the various versions.
|
||
|
||
### Layer Interface Version 2
|
||
|
||
Introduced the concept of
|
||
[loader and layer interface](#layer-version-negotiation) using the
|
||
`vkNegotiateLoaderLayerInterfaceVersion` function.
|
||
Additionally, it introduced the concept of
|
||
[Layer Unknown Physical Device Extensions](#layer-unknown-physical-device-extensions)
|
||
and the associated `vk_layerGetPhysicalDeviceProcAddr` function.
|
||
Finally, it changed the manifest file definition to 1.1.0.
|
||
|
||
Note: If a layer wraps the VkInstance handle, support for
|
||
`vk_layerGetPhysicalDeviceProcAddr` is *NOT* optional and must be implemented.
|
||
|
||
### Layer Interface Version 1
|
||
|
||
A layer supporting interface version 1 had the following behavior:
|
||
1. `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` were directly exported
|
||
2. The layer manifest file was able to override the names of the
|
||
`GetInstanceProcAddr` and `GetDeviceProcAddr`functions.
|
||
|
||
### Layer Interface Version 0
|
||
|
||
A layer supporting interface version 0 must define and export these
|
||
introspection functions, unrelated to any Vulkan function despite the names,
|
||
signatures, and other similarities:
|
||
|
||
- `vkEnumerateInstanceLayerProperties` enumerates all layers in a
|
||
`Layer Library`.
|
||
- This function never fails.
|
||
- When the `Layer Library` contains only one layer, this function may be an
|
||
alias to that one layer's `vkEnumerateInstanceLayerProperties`.
|
||
- `vkEnumerateInstanceExtensionProperties` enumerates instance extensions of
|
||
layers in the `Layer Library`.
|
||
- "pLayerName" is always a valid layer name.
|
||
- This function never fails.
|
||
- When the `Layer Library` contains only one layer, this function may be an
|
||
alias to the one layer's `vkEnumerateInstanceExtensionProperties`.
|
||
- `vkEnumerateDeviceLayerProperties` enumerates a subset (can be full,
|
||
proper, or empty subset) of layers in the `Layer Library`.
|
||
- "physicalDevice" is always `VK_NULL_HANDLE`.
|
||
- This function never fails.
|
||
- If a layer is not enumerated by this function, it will not participate in
|
||
device function interception.
|
||
- `vkEnumerateDeviceExtensionProperties` enumerates device extensions of
|
||
layers in the `Layer Library`.
|
||
- "physicalDevice" is always `VK_NULL_HANDLE`.
|
||
- "pLayerName" is always a valid layer name.
|
||
- This function never fails.
|
||
|
||
It must also define and export these functions once for each layer in the
|
||
library:
|
||
|
||
- `<layerName>GetInstanceProcAddr(instance, pName)` behaves identically to a
|
||
layer's vkGetInstanceProcAddr except it is exported.
|
||
|
||
When the `Layer Library` contains only one layer, this function may
|
||
alternatively be named `vkGetInstanceProcAddr`.
|
||
|
||
- `<layerName>GetDeviceProcAddr` behaves identically to a layer's
|
||
vkGetDeviceProcAddr except it is exported.
|
||
|
||
When the `Layer Library` contains only one layer, this function may
|
||
alternatively be named `vkGetDeviceProcAddr`.
|
||
|
||
All layers contained within a library must support `vk_layer.h`.
|
||
They do not need to implement functions that they do not intercept.
|
||
They are recommended not to export any functions.
|
||
|
||
|
||
## Loader and Layer Interface Policy
|
||
|
||
This section is intended to define proper behavior expected between the loader
|
||
and layers.
|
||
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 layer 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 layer 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/Layer policy items start with the prefix `LLP_` (short for
|
||
Loader/Layer 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:
|
||
- Layers: which will have the string `LAYER_` 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 layers 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 Layers
|
||
|
||
<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>LLP_LAYER_1</b></small></td>
|
||
<td>A layer, when inserted into an otherwise compliant Vulkan
|
||
environment, <b>must</b> still result in a compliant Vulkan environment
|
||
unless it intends to mimic non-compliant behavior (such as a device
|
||
simulation layer).
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td>No<br/>
|
||
It is not a simple task for the loader to find the cause of failure
|
||
in a layer chain.</td>
|
||
<td><small>
|
||
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_2</b></small></td>
|
||
<td>A layer <b>must not</b> cause other layers or drivers to fail, crash, or
|
||
otherwise misbehave.<br/>
|
||
It <b>must not</b> make invalid calls to, or rely on undefined behaviors
|
||
of the layers or drivers below it.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td>No<br/>
|
||
It is not a simple task for the loader to find the cause of failure
|
||
in a layer chain.</td>
|
||
<td><small>
|
||
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_3</b></small></td>
|
||
<td>Any new layer developed <b>should</b> adhere to the naming rules defined
|
||
in the "Layer Conventions and Rules" section which also correspond to
|
||
the naming rules defined in the Vulkan Style Guide section 3.4 on
|
||
"Version, Extension, and Layer Naming Conventions".
|
||
</td>
|
||
<td>Layer developers could produce conflicting names causing unexpected
|
||
behavior if more than one layer with the same name is available on a
|
||
user's platform.
|
||
</td>
|
||
<td>Yes</td>
|
||
<td>Yes<br/>
|
||
Can not immediately enforce since it will cause some shipping layers
|
||
to stop working.</td>
|
||
<td><small>
|
||
<a href="https://www.khronos.org/registry/vulkan/specs/1.2/styleguide.html#extensions-naming-conventions">
|
||
Vulkan Style Guide section 3.4</a> <br/>
|
||
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_4</b></small></td>
|
||
<td>A layer <b>should</b> export the
|
||
<i>vkNegotiateLoaderLayerInterfaceVersion</i> entry-point to negotiate
|
||
an interface version.<br/>
|
||
A layer using interface 2 or newer <b>must</b> export this function.<br/>
|
||
</td>
|
||
<td>The layer will not be loaded.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#layer-version-negotiation">Layer Version Negotiation</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_5</b></small></td>
|
||
<td>A layer <b>must</b> be able to negotiate a supported version of the
|
||
loader/layer interface with the loader in accordance with the stated
|
||
negotiation process.
|
||
</td>
|
||
<td>The layer will not be loaded.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#loader-and-layer-interface-negotiation">
|
||
Interface Negotiation</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_6</b></small></td>
|
||
<td>A layer <b>must</b> have a valid JSON manifest file for the
|
||
loader to process that ends with the ".json" suffix.
|
||
It is recommended validating the layer manifest file against
|
||
<a href="https://github.com/LunarG/VulkanTools/blob/main/vkconfig_core/layers/layers_schema.json">
|
||
the layer schema</a> prior to publication.</br>
|
||
The <b>only</b> exception is on Android which determines layer
|
||
functionality through the introspection functions defined in
|
||
<a href="#layer-library-api-version-0">Layer Library API Version 0</a>
|
||
section and in the
|
||
<a href="#layer-manifest-file-format">Layer Manifest File Format</a>
|
||
table.
|
||
</td>
|
||
<td>The layer will not be loaded.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#layer-manifest-file-usage">Manifest File Usage</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_7</b></small></td>
|
||
<td>If a layer is a Meta-layer, each component layer in its manifest file
|
||
<b>must</b> be present on the system.
|
||
</td>
|
||
<td>The layer will not be loaded.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#meta-layers">Meta-Layers</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_8</b></small></td>
|
||
<td>If a layer is a Meta-layer, each component layer in its manifest file
|
||
<b>must</b> report the same or a newer Vulkan API major and minor
|
||
version than the meta-layer.
|
||
</td>
|
||
<td>The layer will not be loaded.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#meta-layers">Meta-Layers</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_9</b></small></td>
|
||
<td>A layer installed as an Implicit Layer <b>must</b> define a disable
|
||
environment variable so it can be disabled globally.
|
||
</td>
|
||
<td>The layer will not be loaded if it does not define the environment
|
||
variable.
|
||
</td>
|
||
<td>Yes</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#layer-manifest-file-format">Manifest File Format</a>, see
|
||
"disable_environment" variable</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_10</b></small></td>
|
||
<td>If a layer wraps individual object handles, it <b>must</b> unwrap those
|
||
handles when passing the handles down the chain to the next layer.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
</td>
|
||
<td>Yes</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#cautions-about-wrapping">Cautions About Wrapping</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_11</b></small></td>
|
||
<td>Any layer shipped with a driver <b>must</b> be validated against
|
||
conformance with the corresponding driver.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td>No</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>LLP_LAYER_12</b></small></td>
|
||
<td> During <i>vkCreateInstance</i>, a layer <b>must</b> process the
|
||
<i>VkLayerInstanceCreateInfo</i> chain links appropriately.<br/>
|
||
This includes getting the next layer's <i>vkGetInstanceProcAddr</i>
|
||
function for building a dispatch table as well as updating the
|
||
<i>VkLayerInstanceCreateInfo</i> chain link to point to the next
|
||
structure in the chain for the next layer prior to calling down to the
|
||
next layer's <i>vkCreateInstance</i> function. <br/>
|
||
An example of such usage is shown in detail in the
|
||
<a href=#example-code-for-createinstance>Example Code for
|
||
CreateInstance</a> section.
|
||
</td>
|
||
<td>The behavior will result in crashes or corruption as any following
|
||
layers will access incorrect content.</td>
|
||
<td>Yes</td>
|
||
<td>No<br/>
|
||
With the current loader/layer design, it is difficult for the loader
|
||
to diagnose this without adding additional overhead that could impact
|
||
performance.<br/>
|
||
This is because the loader calls all layers at once and has no data on
|
||
the intermediate state of the <i>pNext</i> chain contents.
|
||
This could be done in the future, but requires re-designing the layer
|
||
initialization process.
|
||
</td>
|
||
<td><small>
|
||
<a href=""#layer-dispatch-initialization">
|
||
Layer Dispatch Initialization</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<td><small><b>LLP_LAYER_13</b></small></td>
|
||
<td> During <i>vkCreateDevice</i>, a layer <b>must</b> process the
|
||
<i>VkLayerDeviceCreateInfo</i> chain links appropriately.<br/>
|
||
This includes updating the <i>VkLayerDeviceCreateInfo</i> chain link to
|
||
point to the next structure in the chain for the next layer prior to
|
||
calling down to the next layer's <i>vkCreateDevice</i> function. <br/>
|
||
An example of such usage is shown in detail in the
|
||
<a href="#example-code-for-createdevice">Example Code for
|
||
CreateDevice</a> section.
|
||
</td>
|
||
<td>The behavior will result in crashes or corruption as any following
|
||
layers will access incorrect content.</td>
|
||
<td>Yes</td>
|
||
<td>No<br/>
|
||
With the current loader/layer design, it is difficult for the loader
|
||
to diagnose this without adding additional overhead that could impact
|
||
performance.</td>
|
||
<td><small>
|
||
<a href="#layer-dispatch-initialization">
|
||
Layer Dispatch Initialization</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_14</b></small></td>
|
||
<td>A layer <b>should</b> use the application provided memory allocator
|
||
functions when they are provided so that applications can keep track of
|
||
allocated memory.
|
||
</td>
|
||
<td>The allocator functions may be provided for the purpose of limiting
|
||
or tracking the memory used by the Vulkan components.
|
||
Because of this, if a layer ignores these allocators, it may result in
|
||
undefined behavior possibly including crashes or corruption.
|
||
</td>
|
||
<td>Yes</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_15</b></small></td>
|
||
<td>A layer <b>must</b> enumerate only its own extension properties during a
|
||
call of <i>vkEnumerateInstanceExtensionProperties</i> when
|
||
<i>pLayerName</i> refers to itself.<br/>
|
||
Otherwise, it <b>must</b> return <i>VK_ERROR_LAYER_NOT_PRESENT</i>,
|
||
including when <i>pLayerName</i> is <b>NULL</b>.
|
||
</td>
|
||
<td>The loader could become confused on what support is present in a
|
||
specific layer which will result in undefined behavior possibly
|
||
including crashes or corruption.
|
||
</td>
|
||
<td>Yes</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_16</b></small></td>
|
||
<td>A layer <b>must</b> enumerate only its own extension properties during a
|
||
call of <i>vkEnumerateDeviceExtensionProperties</i> when
|
||
<i>pLayerName</i> refers to itself.<br/>
|
||
Otherwise, it <b>must</b> ignore the call other than passing it down
|
||
the standard call chain.
|
||
</td>
|
||
<td>The loader could become confused on what support is present in a
|
||
specific layer which will result in undefined behavior possibly
|
||
including crashes or corruption.
|
||
</td>
|
||
<td>Yes</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_17</b></small></td>
|
||
<td>A layer's <i>vkCreateInstance</i> <b>must not</b> generate an error for
|
||
unrecognized extension names as the extension could be implemented by
|
||
a lower layer or driver.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_18</b></small></td>
|
||
<td>A layer <b>must</b> return <b>NULL</b> from <i>vkGetInstanceProcAddr</i>
|
||
or <i>vkGetDeviceProcAddr</i> for entry-points that it does not support
|
||
or that have not been enabled properly (for example not enabling the
|
||
extension certain entry-points are associated with should result in
|
||
<i>vkGetInstanceProcAddr</i> returning <b>NULL</b> when requesting
|
||
them).
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td>No<br/>
|
||
With the current loader/layer design, it is difficult for the loader
|
||
to determine this without adding additional overhead that could impact
|
||
performance.</td>
|
||
<td><small>
|
||
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_19</b></small></td>
|
||
<td>If a layer creates dispatchable objects, either because it is
|
||
wrapping objects or implementing an extension not supported by
|
||
the loader or underlying drivers, it <b>must</b> create the dispatch
|
||
table appropriately for all created dispatchable objects.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#creating-new-dispatchable-objects">
|
||
Creating New Dispatchable Objects</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_20</b></small></td>
|
||
<td>A layer <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 layer files, the old files <b>must</b> be all
|
||
updated or removed.
|
||
</td>
|
||
<td>The loader ignores duplicate attempts to load the same manifest file,
|
||
but 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 layer files are new, old, or incorrect.
|
||
Any type of layer file verification would quickly become very complex
|
||
since it would require the loader to maintain an internal database
|
||
tracking badly behaving layers based on the layer name, version,
|
||
targeted platform(s), and possibly other criteria.
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_21</b></small></td>
|
||
<td>During <i>vkCreateInstance</i>, a layer <b>must not</b> modify the
|
||
<i>pInstance</i> pointer during prior to calling down to the lower
|
||
layers.<br/>
|
||
This is because the loader passes information in this pointer that is
|
||
necessary for the initialization code in the loader's terminator
|
||
function.<br/>
|
||
Instead, if the layer is overriding the <i>pInstance</i> pointer, it
|
||
<b>must</b> do so only after the call to the lower layers returns.
|
||
</td>
|
||
<td>The loader will likely crash.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LAYER_22</b></small></td>
|
||
<td>During <i>vkCreateDevice</i>, a layer <b>must not</b> modify the
|
||
<i>pDevice</i> pointer during prior to calling down to the lower
|
||
layers.<br/>
|
||
This is because the loader passes information in this pointer that is
|
||
necessary for the initialization code in the loader's terminator
|
||
function.<br/>
|
||
Instead, if the layer is overriding the <i>pDevice</i> pointer, it
|
||
<b>must</b> do so only after the call to the lower layers returns.
|
||
</td>
|
||
<td>The loader will likely crash.</td>
|
||
<td>No</td>
|
||
<td>Yes</td>
|
||
<td><small>N/A</small></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>LLP_LOADER_1</b></small></td>
|
||
<td>A loader <b>must</b> support Vulkan layers.</td>
|
||
<td>Users will not have access to critical parts of the Vulkan ecosystem
|
||
such as Validation Layers, GfxReconstruct, or RenderDoc.</td>
|
||
<td>Yes</td>
|
||
<td><small>N/A</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_2</b></small></td>
|
||
<td>A loader <b>must</b> support a mechanism to load layers in one or
|
||
more non-standard locations.<br/>
|
||
This is to allow application/engine-specific layers as well as
|
||
evaluating in-development layers without global installation.
|
||
</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="#layer-discovery">Layer Discovery</a></small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_3</b></small></td>
|
||
<td>A loader <b>must</b> filter out duplicate layer names in the various
|
||
enable lists, keeping only the first occurrence.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>Yes</td>
|
||
<td><small><a href="#layer-discovery">Layer Discovery</a></small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_4</b></small></td>
|
||
<td>A loader <b>must not</b> load a Vulkan layer 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="#layer-discovery">Layer Discovery</a></small></td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_5</b></small></td>
|
||
<td>A loader <b>must</b> ignore any layer for which a compatible interface
|
||
version can not be negotiated.
|
||
</td>
|
||
<td>The loader would load a layer improperly resulting in undefined behavior
|
||
which may include crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#loader-and-layer-interface-negotiation">
|
||
Interface Negotiation</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_6</b></small></td>
|
||
<td>If a layer is implicit, and it has an enable environment variable,
|
||
then a loader <b>must not</b> consider the layer enabled unless that
|
||
enable environment variable is defined.<br/>
|
||
If an implicit layer does not have an enable environment variable,
|
||
it will be considered enabled by default.
|
||
</td>
|
||
<td>Some layers may be used when not intended.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#layer-manifest-file-format">Manifest File Format</a>, see
|
||
"enable_environment" variable</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_7</b></small></td>
|
||
<td>If an implicit layer is enabled, but has been disabled by some other
|
||
mechanism (such as the defining of the layer's disable environment
|
||
variable or through the blacklisting mechanism of the Override Layer),
|
||
then a loader <b>must not</b> load that layer.
|
||
</td>
|
||
<td>Some layers may be used when not intended.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#layer-manifest-file-format">Manifest File Format</a>, see
|
||
"disable_environment" variable</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_8</b></small></td>
|
||
<td>A loader <b>must</b> pass a linked list of initialization structures
|
||
to each layer via the <i>VkLayerInstanceCreateInfo</i> structure in the
|
||
<i>pNext</i> field of the <i>VkInstanceCreateInfo</i> structure.
|
||
This contains necessary information for setting up the instance call
|
||
chain including providing a function pointer to the next links
|
||
<i>vkGetInstanceProcAddr</i>.
|
||
</td>
|
||
<td>Layers will crash as they attempt to load invalid data.</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#layer-dispatch-initialization">
|
||
Layer Dispatch Initialization</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_9</b></small></td>
|
||
<td>A loader <b>must</b> pass a linked list of initialization structures
|
||
to each layer via the <i>VkLayerDeviceCreateInfo</i> structure in the
|
||
<i>pNext</i> field of the <i>VkDeviceCreateInfo</i> structure.
|
||
This contains necessary information for setting up the device call chain
|
||
including providing a function pointer to the next links
|
||
<i>vkGetDeviceProcAddr</i>.
|
||
<td>Layers will crash as they attempt to load invalid data.</td>
|
||
<td>Yes</td>
|
||
<td><small>
|
||
<a href="#layer-dispatch-initialization">
|
||
Layer Dispatch Initialization</a>
|
||
</small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_10</b></small></td>
|
||
<td>A loader <b>must</b> verify that all meta-layers contain valid
|
||
component layers that the loader can find on the system and that also
|
||
report the same Vulkan API version as the meta-layer itself before it
|
||
loads the meta-layer.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#meta-layers">Meta-Layers</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_11</b></small></td>
|
||
<td>If the override meta-layer is present, a loader <b>must</b> load it
|
||
and corresponding component layers after all other implicit layers have
|
||
been added to the call chain.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#override-meta-layer">Override Meta-Layer</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_12</b></small></td>
|
||
<td>If the override meta-layer is present and has a blacklist of layers to
|
||
remove, a loader <b>must</b> disable all layers listed in the blacklist.
|
||
</td>
|
||
<td>The behavior is undefined and may result in crashes or corruption.</td>
|
||
<td>No</td>
|
||
<td><small>
|
||
<a href="#override-meta-layer">Override Meta-Layer</a></small>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><small><b>LLP_LOADER_13</b></small></td>
|
||
<td>A loader <b>must</b> not load from user-defined paths (including the
|
||
use of either <i>VK_LAYER_PATH</i> or <i>VK_ADD_LAYER_PATH</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="#layer-discovery">Layer Discovery</a></small></td>
|
||
</tr>
|
||
</table>
|
||
|
||
<br/>
|
||
|
||
[Return to the top-level LoaderInterfaceArchitecture.md file.](LoaderInterfaceArchitecture.md)
|