third_party/dawn/third_party/vulkan-loader/src/docs/LoaderLayerInterface.md
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 file.
As mentioned in the Implicit versus Explicit, section of the LoaderApplicationInterface.md document, layers can be categorized into two categories:
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.
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.
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 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 table.
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.
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.
Additionally, the Vulkan loader will scan the system for well-known Windows AppX/MSIX packages. If a package is found, the loader will scan the root directory of this installed package for JSON manifest files. At this time, the only package that is known is Microsoft's OpenCL™, OpenGL®, and Vulkan® Compatibility Pack.
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.
If VK_IMPLICIT_LAYER_PATH is defined, then the loader will look at the paths
defined by that variable for implicit layer manifest files instead of using the
information provided by the implicit layer registry keys.
If VK_ADD_IMPLICIT_LAYER_PATH is defined, then the loader will look at the provided
paths for implicit layer manifest files in addition to using the information
provided by the implicit layer registry keys.
The paths provided by VK_ADD_IMPLICIT_LAYER_PATH are added before the standard list
of search folders and will therefore be searched first.
For security reasons, VK_LAYER_PATH, VK_ADD_LAYER_PATH, VK_IMPLICIT_LAYER_PATH,
and VK_ADD_IMPLICIT_LAYER_PATH are ignored if running with elevated privileges.
See Exception for Elevated Privileges
for more info.
See Forcing Layer Source Folders in the LoaderApplicationInterface.md document for more information on this.
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>. This is done because under these scenarios it is not safe to trust
that the environment variables are non-malicious.
</td>
This is done because under these scenarios it is not safe to trust
that the environment variables are non-malicious.
</td>
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:
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.
If VK_IMPLICIT_LAYER_PATH is defined, then the loader will look at the paths
defined by that variable for implicit layer manifest files instead of using the
information provided by the standard implicit layer paths mentioned above.
If VK_ADD_IMPLICIT_LAYER_PATH is defined, then the loader will look at the
provided paths for implicit layer manifest files in addition to using the
information provided by the standard implicit layer paths mentioned above.
The paths provided by VK_ADD_IMPLICIT_LAYER_PATH are added before the standard
list of search folders and will therefore be searched first.
If VK_IMPLICIT_LAYER_PATH is present, then VK_ADD_IMPLICIT_LAYER_PATH will
not be used by the loader and any values will be ignored.
For security reasons, VK_LAYER_PATH, VK_ADD_LAYER_PATH, VK_IMPLICIT_LAYER_PATH,
and VK_ADD_IMPLICIT_LAYER_PATH are ignored if running with elevated privileges.
See 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.
See Forcing Layer Source Folders in the LoaderApplicationInterface.md document for more information on this.
It is also important to note that while VK_LAYER_PATH, VK_ADD_LAYER_PATH,
VK_IMPLICIT_LAYER_PATH, and VK_ADD_IMPLICIT_LAYER_PATH will point the
loader at 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.
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
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. The only difference is that Fuchsia does not allow fallback values for $XDG_DATA_DIRS or $XDG_HOME_DIRS.
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/.
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
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 environment variables VK_LAYER_PATH, VK_ADD_LAYER_PATH,
VK_IMPLICIT_LAYER_PATH, and VK_ADD_IMPLICIT_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 section of the LoaderLayerInterface document.
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:
[Vulkan Loader] WARNING | LAYER: Layer "VK_LAYER_LUNARG_wrap_objects" force enabled due to env var 'VK_LOADER_LAYERS_ENABLE'
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:
[Vulkan Loader] WARNING | LAYER: Layer "VK_LAYER_LUNARG_wrap_objects" disabled because name matches filter of env var 'VK_LOADER_LAYERS_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).
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.
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_LAYERSThe original VK_INSTANCE_LAYERS can be viewed as a special case of
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.
For security reasons, VK_LAYER_PATH, VK_ADD_LAYER_PATH, VK_IMPLICIT_LAYER_PATH
and VK_ADD_IMPLICIT_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 in the top-level [LoaderInterfaceArchitecture.md][LoaderInterfaceArchitecture.md] document.
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:
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:
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.
There are two key architectural features that drive the loader to
Layer Library interface:
For further information, read the overview of dispatch tables and call chains above in the Dispatch Tables and Call Chains section of the LoaderInterfaceArchitecture.md document.
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.
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.
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:
vk_layerGetPhysicalDeviceProcAddr call.
vkCreateInstance, it is passed to a layer in the chain
information passed to a layer in the VkLayerInstanceCreateInfo structure.
get_chain_info() to get the pointer to the
VkLayerInstanceCreateInfo structure. Let's call it chain_info.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.
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:
GetPhysicalDeviceProcAddr
GetInstanceProcAddr
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.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.
vk_layerGetPhysicalDeviceProcAddrOriginally, if vkGetInstanceProcAddr was called in the loader, it would
result in the following behavior:
GetInstanceProcAddr
VkDevice.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.
vkGetInstanceProcAddr and
vkCreateInstance to participate in the instance call chain.vkGetDeviceProcAddr and vkCreateDevice
to participate in the device call chain.vkNegotiateLoaderLayerInterfaceVersionvkGetInstanceProcAddrvkGetDeviceProcAddrvk_layerGetPhysicalDeviceProcAddrvkQueueSubmit may want to add a call
to vkQueueWaitIdle after calling down the chain for vkQueueSubmit.vkQueueSubmit chain, followed by a call down the vkQueueWaitIdle chain.VkLayerDispatchTable structure as a device dispatch
table (see include/vulkan/vk_dispatch_table_helper.h).VkLayerInstanceDispatchTable structure as a instance
dispatch table (see include/vulkan/vk_dispatch_table_helper.h).vkGetInstanceProcAddr function uses the next entity's
vkGetInstanceProcAddr to call down the chain for unknown (i.e.
non-intercepted) functions.vkGetDeviceProcAddr function uses the next entity's
vkGetDeviceProcAddr to call down the chain for unknown (i.e. non-intercepted)
functions.vk_layerGetPhysicalDeviceProcAddr function uses the next entity's
vk_layerGetPhysicalDeviceProcAddr to call down the chain for unknown (i.e.
non-intercepted) functions.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:
VK_LAYER_ prefixExamples of valid layer names include:
More details on layer naming can be found in the Vulkan style-guide 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.
VK_ERROR_LAYER_NOT_PRESENT otherwise, including when
pLayerName is NULL.vkEnumerateDeviceLayerProperties is deprecated and may be omitted.
vkEnumerateDeviceExtensionProperties must handle the case where
pLayerName is itself.
vkCreateInstance must not generate an error for unrecognized layer
names and extension names.
vkGetInstanceProcAddr intercepts a Vulkan function by returning a local
entry-point
vkGetDeviceProcAddr intercepts a Vulkan function by returning a local
entry-point
vkGetDeviceProcAddrvkCreateDevice(only required for any device-level chaining)
vkGetInstanceProcAddr
ignore instance when pName is vkCreateDevice.NULL to be returned from
vkGetInstanceProcAddr and vkGetDeviceProcAddr for disabled functions.
NULL itself or rely on the following layers to do so.vkGetInstanceProcAddr should, when querying for
vkCreateInstance, return a valid function pointer regardless of the value of the
instance parameter.
instance parameter must be NULL.
However, older versions of the specification did not have this requirement, allowing
for non-NULL instance handles to be passed in and return a valid vkCreateInstance
function pointer. The Vulkan-Loader itself does this and will continue to do so to
maintain compatibility with layers which were released before this specification
change was made.vkCreateInstance
function.vkCreateDevice
function.VkInstanceCreateInfo and VkDeviceCreateInfo
structures for vkCreateInstance and VkCreateDevice respectively.VkLayerInstanceCreateInfo for
instance and VkLayerDeviceCreateInfo for device.
See file include/vulkan/vk_layer.h for details.VkLayerInstanceCreateInfo.VkLayerDeviceCreateInfo.VkLayer*CreateInfo.
The loader will set the "function" field to VK_LAYER_LINK_INFO.
This indicates "u" field should be VkLayerInstanceLink or
VkLayerDeviceLink.VkLayerInstanceLink and VkLayerDeviceLink structures are the list
nodes.VkLayerInstanceLink contains the next entity's vkGetInstanceProcAddr
used by a layer.VkLayerDeviceLink contains the next entity's vkGetInstanceProcAddr
and vkGetDeviceProcAddr used by a layer.VkLayerInstanceCreateInfo/VkLayerDeviceCreateInfo structure in
the VkInstanceCreateInfo/VkDeviceCreateInfo structure.vkCreateInstance by calling the
"pfnNextGetInstanceProcAddr":
pfnNextGetInstanceProcAddr(NULL, "vkCreateInstance").vkCreateDevice by calling the
"pfnNextGetInstanceProcAddr":
pfnNextGetInstanceProcAddr(instance, "vkCreateDevice"), passing the
already created instance handle.vkCreateDevice or vkCreateInstanceVkResult
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;
}
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 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:
Restrictions to defining and using a meta-layer are:
The ordering of a meta-layer's component layers in the instance or device call- chain is simple:
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 section.
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 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.
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 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:
pre_instance_functions JSON objectThe functions that may be intercepted in this way are:
vkEnumerateInstanceExtensionPropertiesvkEnumerateInstanceLayerPropertiesvkEnumerateInstanceVersionPre-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:
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:
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).
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:
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:
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.
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.
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:
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:
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).
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.
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.
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:
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):
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:
VkInstanceCreateInfo the callback structure pointed to by "pNext" is
VkLayerInstanceCreateInfo as defined in include/vulkan/vk_layer.h.VkInstanceCreateInfo parameter indicates a loader structure.VkLayerInstanceCreateInfo, the "function" field indicates how the
union field "u" should be interpreted.VkDeviceCreateInfo the callback structure pointed to by "pNext" is
VkLayerDeviceCreateInfo as defined in include/vulkan/vk_layer.h.VkDeviceCreateInfo parameter indicates a loader structure.VkLayerDeviceCreateInfo, the "function" field indicates how the union
field "u" should be interpreted.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.
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.
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:
{
"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:
{
"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:
{
"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"
]
}
}
<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>
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>
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>
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>
<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>
Allows the loader to quickly determine if the architecture of the layer
matches that of the running application.
The only valid values are "32" and "64".</td>
<td><small>N/A</small></td>
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>
<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>
The current highest supported Layer Manifest file format supported is 1.2.0. Information about each version is detailed in the following sub-sections:
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.
The ability to define the layer settings as defined by the layer manifest schema.
The ability to briefly document the layer thanks to the fields:
These changes were made to enable third-party layers to expose their features within Vulkan Configurator or other tools.
Version 1.1.2 introduced the ability of layers to intercept function calls that do not have an instance.
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 is tied to changes exposed by the Loader/Layer interface version 2.
The layer manifest file does not need to to be updated if the names of any listed functions has not changed.
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.
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:
It was also during this time that the value of "DEVICE" was deprecated from the "type" field.
The current loader/layer interface is at version 2. The following sections detail the differences between the various versions.
Introduced the concept of
loader and layer interface using the
vkNegotiateLoaderLayerInterfaceVersion function.
Additionally, it introduced the concept of
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.
A layer supporting interface version 1 had the following behavior:
vkGetInstanceProcAddr and vkGetDeviceProcAddr were directly exportedGetInstanceProcAddr and GetDeviceProcAddrfunctions.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.
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.
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.
VK_NULL_HANDLE.vkEnumerateDeviceExtensionProperties enumerates device extensions of
layers in the Layer Library.
VK_NULL_HANDLE.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.
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.
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:
LAYER_ as part of the policy number.LOADER_ as part of the policy
number.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>.
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>
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
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>
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>
<a href="#layer-conventions-and-rules">Layer Conventions and Rules</a>
</small>
</td>
A layer using interface 2 or newer <b>must</b> export this function.
</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>
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.
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
With the current loader/layer design, it is difficult for the loader
to diagnose this without adding additional overhead that could impact
performance.
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>
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.
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
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>
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>
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>
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>
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
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>
This is because the loader passes information in this pointer that is
necessary for the initialization code in the loader's terminator
function.
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>
This is because the loader passes information in this pointer that is
necessary for the initialization code in the loader's terminator
function.
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>
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>
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>
<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>
Return to the top-level LoaderInterfaceArchitecture.md file.