| # Vulkan Loader Specification and Architecture Overview | |
| <br/> | |
| ## Goals of this document ## | |
| Specify necessary functions and expected behavior of interface between the | |
| loader library and ICDs and layers for Windows, Linux and Android based | |
| systems. Also describe the application visible behaviors of the loader. | |
| <br/> | |
| ## Audience ## | |
| This document is primarily targeted at Vulkan application, driver and layer developers. | |
| However, it can also be used by any developer interested in understanding more about | |
| how the Vulkan loader and layers interact. | |
| <br/> | |
| ## Loader goals ## | |
| - Support multiple ICDs (Installable Client Drivers) to co-exist on a system | |
| without interfering with each other. | |
| - Support optional modules (layers) that can be enabled by an application, | |
| developer or the system and have no impact when not enabled. | |
| - Negligible performance cost for an application calling through the loader | |
| to an ICD entry point. | |
| <br/> | |
| ## Architectural overview of layers and loader ## | |
| Vulkan is a layered architecture placing the Application on one end, the | |
| ICDs on the other, and the loader and some number of layers in between. | |
| Layers are implemented as libraries that can be enabled in different ways | |
| (including by application request) and loaded during CreateInstance. Each | |
| layer can chooses to hook (intercept) any Vulkan commands which in turn | |
| can be ignored, augmented, or simply passed along. A layer may also | |
| expose functionality not available in the loader or any ICD. Some examples | |
| of this include: the ability to perform Vulkan API tracing and debugging, | |
| validate API usage, or overlay additional content on the applications surfaces. | |
| The loader is responsible for working with the various layers as well as | |
| supporting multiple GPUs and their drivers. Any Vulkan command may | |
| wind up calling into a diverse set of modules: loader, layers, and ICDs. | |
| The loader is critical to managing the proper dispatching of Vulkan | |
| commands to the appropriate set of layers and ICDs. The Vulkan object | |
| model allows the loader to insert layers into a call chain so that the layers | |
| can process Vulkan commands prior to the ICD being called. | |
| Vulkan uses an object model to control the scope of a particular action / | |
| operation. The object to be acted on is always the first parameter of a Vulkan | |
| call and is a dispatchable object (see Vulkan specification section 2.3 Object | |
| Model). Under the covers, the dispatchable object handle is a pointer to a | |
| structure, which in turn, contains a pointer to a dispatch table maintained by | |
| the loader. This dispatch table contains pointers to the Vulkan functions appropriate to | |
| that object. | |
| There are two types of dispatch tables the loader maintains: | |
| - **Instance Dispatch Table** | |
| - Contains any function that takes a VkInstance or VkPhysicalDevice as their first parameter | |
| - vkEnumeratePhysicalDevices | |
| - vkDestroyInstance | |
| - vkCreateInstance | |
| - ... | |
| - **Device Dispatch Table** | |
| - Contains any function that takes a VkDevice, VkQueue or VkCommandBuffer as their first parameter | |
| These instance and device dispatch tables are constructed when the application | |
| calls vkCreateInstance and vkCreateDevice. At that time the application and/or | |
| system can specify optional layers to be included. The loader will initialize | |
| the specified layers to create a call chain for each Vulkan function and each | |
| entry of the dispatch table will point to the first element of that chain. | |
| Thus, the loader builds an instance call chain for each VkInstance that is | |
| created and a device call chain for each VkDevice that is created. | |
| For example, the diagram below represents what happens in the call chain for | |
| vkCreateInstance. After initializing the chain, the loader will call into the | |
| first layer's vkCreateInstance which will call the next finally terminating in | |
| the loader again where this function calls every ICD's vkCreateInstance and | |
| saves the results. This allows every enabled layer for this chain to set up | |
| what it needs based on the VkInstanceCreateInfo structure from the application. | |
|  | |
| This also highlights some of the complexity the loader must manage when using | |
| instance chains. As shown here, the loader must aggregate information from | |
| multiple devices when they are present. This means that the loader has to know | |
| about instance level extensions to aggregate them correctly. | |
| Device chains are created at vkCreateDevice and are generally simpler because | |
| they deal with only a single device and the ICD can always be the terminator of | |
| the chain. The below diagram also illustrates how layers (either device or | |
| instance) can skip intercepting any given Vulkan entry point. | |
|  | |
| <br/> | |
| ## Application interface to loader ## | |
| In this section we'll discuss how an application interacts with the loader. | |
| - Linking to loader library for core and WSI extension symbols. | |
| - Dynamic Vulkan command lookup & application dispatch table. | |
| - Loader library filenames for linking to different Vulkan ABI versions. | |
| - Layers | |
| - Extensions | |
| - vkGetInstanceProcAddr, vkGetDeviceProcAddr | |
| The loader library on Windows, Linux and Android will export all core Vulkan | |
| and all appropriate Window System Interface (WSI) extensions. This is done to | |
| make it simpler to get started with Vulkan development. When an application | |
| links directly to the loader library in this way, the Vulkan calls are simple | |
| trampoline functions that jump to the appropriate dispatch table entry for the | |
| object they are given. | |
| Applications are not required to link directly to the loader library, instead | |
| they can use the appropriate platform specific dynamic symbol lookup on the | |
| loader library to initialize the application's own dispatch table. This allows | |
| an application to fail gracefully if the loader cannot be found, and it | |
| provides the fastest mechanism for the application to call Vulkan functions. An | |
| application will only need to query (via system calls such as dlsym()) the | |
| address of vkGetInstanceProcAddr from the loader library. Using | |
| vkGetInstanceProcAddr the application can then discover the address of all | |
| instance and global functions and extensions, such as vkCreateInstance, | |
| vkEnumerateInstanceExtensionProperties and vkEnumerateInstanceLayerProperties | |
| in a platform independent way. | |
| The Vulkan loader library will be distributed in various ways including Vulkan | |
| SDKs, OS package distributions and IHV driver packages. These details are | |
| beyond the scope of this document. However, the name and versioning of the | |
| Vulkan loader library is specified so an app can link to the correct Vulkan ABI | |
| library version. Vulkan versioning is such that ABI backwards compatibility is | |
| guaranteed for all versions with the same major number (e.g. 1.0 and 1.1). On | |
| Windows, the loader library encodes the ABI version in its name such that | |
| multiple ABI incompatible versions of the loader can peacefully coexist on a | |
| given system. The Vulkan loader library file name is "vulkan-<ABI | |
| version>.dll". For example, for Vulkan version 1.X on Windows the library | |
| filename is vulkan-1.dll. And this library file can typically be found in the | |
| windows/system32 directory (on 64-bit Windows installs, the 32-bit version of | |
| the loader with the same name can be found in the windows/sysWOW64 directory). | |
| For Linux, shared libraries are versioned based on a suffix. Thus, the ABI | |
| number is not encoded in the base of the library filename as on Windows. On | |
| Linux an application wanting to link to the latest Vulkan ABI version would | |
| just link to the name vulkan (libvulkan.so). A specific Vulkan ABI version can | |
| also be linked to by applications (e.g. libvulkan.so.1). | |
| #### Layer Usage | |
| Applications desiring Vulkan functionality beyond what the core API offers may | |
| use various layers or extensions. A layer cannot introduce new Vulkan API | |
| entry-points not exposed in Vulkan.h, but may offer extensions that do. A | |
| common use of layers is for API validation which can be enabled by loading the | |
| layer during application development, but not loading the layer for application | |
| release. This eliminates the overhead of validating the application's | |
| usage of the API, something that wasn't available on some previous graphics | |
| APIs. | |
| Layers discovered by the loader are reported to the application via | |
| vkEnumerateInstanceLayerProperties. Layers are enabled at vkCreateInstance | |
| and are active for all Vulkan commands using the given VkInstance and any | |
| of it's child objects. For example, the ppEnabledLayerNames array in the | |
| VkInstanceCreateInfo structure is used by the application to list the layer | |
| names to be enabled at vkCreateInstance. At vkCreateInstance and | |
| vkCreateDevice, the loader will construct call chains that include the application | |
| specified (enabled) layers. Order is important in the | |
| ppEnabledLayerNames array; array element 0 is the topmost (closest to the | |
| application) layer inserted in the chain and the last array element is closest | |
| to the driver. | |
| **NOTE**: vkCreateDevice originally was able to select layers in a | |
| similar manner to vkCreateInstance. This lead to the concept of "instance | |
| layers" and "device layers". It was decided by Khronos to deprecate the | |
| "device layer" functionality and only consider "instance layers". | |
| Therefore, vkCreateDevice will use the layers specified at vkCreateInstance. | |
| Additionally, vkEnumerateDeviceLayerProperties has been deprecated. | |
| Developers may want to enable layers that are not enabled by the given | |
| application they are using. On Linux and Windows, the environment variable | |
| "VK\_INSTANCE\_LAYERS" can be used to enable | |
| additional layers which are not specified (enabled) by the application at | |
| vkCreateInstance. VK\_INSTANCE\_LAYERS is a colon | |
| (Linux)/semi-colon (Windows) separated list of layer names to enable. Order is | |
| relevant with the first layer in the list being the topmost layer (closest to | |
| the application) and the last layer in the list being the bottommost layer | |
| (closest to the driver). | |
| Application specified layers and user specified layers (via environment | |
| variables) are aggregated and duplicates removed by the loader when enabling | |
| layers. Layers specified via environment variable are topmost (closest to the | |
| application) while layers specified by the application are bottommost. | |
| An example of using these environment variables to activate the validation | |
| layer VK\_LAYER\_LUNARG\_parameter\_validation on Windows or Linux is as follows: | |
| ``` | |
| > $ export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_parameter_validation | |
| ``` | |
| #### Implicit vs Explicit Layers | |
| Some platforms, including Linux and Windows, support layers which are enabled | |
| automatically by the loader rather than explicitly by the application (or via | |
| environment variable). Explicit layers are those layers enabled by the | |
| application (or environment variable) by providing the layer name. Implicit | |
| layers are those layers enabled by the loader automatically. Any implicit | |
| layers the loader discovers on the system in the appropriate location will be | |
| enabled (subject to environment variable overrides described later). Discovery | |
| of properly installed implicit and explicit layers is described later. | |
| Explicitly enabling a layer that is implicitly enabled has no additional | |
| effect: the layer will still be enabled implicitly by the loader. | |
| Implicit layers have an additional requirement over explicit layers in that they | |
| require being able to be disabled by an environmental variable. This is due | |
| to the fact that they are not visible to the application and could cause issues. | |
| A good principle to keep in mind would be to define both an enable and disable | |
| environment variable so the users can deterministicly enable the functionality. | |
| On Desktop platforms (Windows and Linux), these enable/disable settings are | |
| defined in the layer's JSON file. | |
| Extensions are optional functionality provided by a layer, the loader or an | |
| ICD. Extensions can modify the behavior of the Vulkan API and need to be | |
| specified and registered with Khronos. | |
| #### Instance/Device Extensions | |
| Instance extensions can be discovered via | |
| vkEnumerateInstanceExtensionProperties. Device extensions can be discovered via | |
| vkEnumerateDeviceExtensionProperties. The loader discovers and aggregates all | |
| extensions from layers (both explicit and implicit), ICDs and the loader before | |
| reporting them to the application in vkEnumerate\*ExtensionProperties. The | |
| pLayerName parameter in these functions is used to select either a single layer | |
| or the Vulkan platform implementation. If pLayerName is NULL, extensions from | |
| Vulkan implementation components (including loader, implicit layers, and ICDs) | |
| are enumerated. If pLayerName is equal to a discovered layer module name then | |
| any extensions from that layer (which may be implicit or explicit) are | |
| enumerated. Duplicate extensions (e.g. an implicit layer and ICD might report | |
| support for the same extension) are eliminated by the loader. For duplicates, the | |
| ICD version is reported and the layer version is culled. Extensions must | |
| be enabled (in vkCreateInstance or vkCreateDevice) before they can be used. | |
| Extension command entry points should be queried via vkGetInstanceProcAddr or | |
| vkGetDeviceProcAddr. vkGetDeviceProcAddr can only be used to query for device | |
| extension or core device entry points. Device entry points include any command | |
| that uses a VkDevice as the first parameter or a dispatchable object that is a | |
| child of a VkDevice (currently this includes VkQueue and VkCommandBuffer). | |
| vkGetInstanceProcAddr can be used to query either device or instance extension | |
| entry points in addition to all core entry points. | |
| VkGetDeviceProcAddr is particularly interesting because it will provide the | |
| most efficient way to call into the ICD. For example, the diagram below shows | |
| what could happen if the application were to use vkGetDeviceProcAddr for the | |
| function "vkGetDeviceQueue" and "vkDestroyDevice" but not "vkAllocateMemory". | |
| The resulting function pointer (fpGetDeviceQueue) would be the ICD's entry | |
| point if the loader and any enabled layers do not need to see that call. Even | |
| if an enabled layer intercepts the call (e.g. vkDestroyDevice) the loader | |
| trampoline code is skipped for function pointers obtained via | |
| vkGetDeviceProcAddr. This also means that function pointers obtained via | |
| vkGetDeviceProcAddr will only work with the specific VkDevice it was created | |
| for, using it with another device has undefined results. For extensions, | |
| Get\*ProcAddr will often be the only way to access extension API features. | |
|  | |
| ##### WSI Extensions | |
| Khronos approved WSI extensions are available and provide Windows System Integration | |
| support for various execution environments. It is important to understand that some WSI | |
| extensions are valid for all targets, but others are particular to a given execution | |
| environment (and loader). This desktop loader (currently targeting Windows and Linux) | |
| only enables those WSI extensions that are appropriate to the current environment. | |
| For the most part, the selection is done in the loader using compile-time preprocessor | |
| flags. All versions of the desktop loader currently expose at least the following WSI | |
| extension support: | |
| - VK_KHR_surface | |
| - VK_KHR_swapchain | |
| - VK_KHR_display | |
| In addition, each of the following OS targets for the loader support target-specific extensions: | |
| - **Windows** : VK_KHR_win32_surface | |
| - **Linux (default)** : VK_KHR_xcb_surface and VK_KHR_xlib_surface | |
| - **Linux (Wayland build)** : VK_KHR_wayland_surface | |
| - **Linux (Mir build)** : VK_KHR_mir_surface | |
| **NOTE:** Wayland and Mir targets are not fully supported at this time and should be considered | |
| alpha quality. | |
| It is important to understand that while the loader may support the various entry-points | |
| for these extensions, there is a hand-shake required to actually use them: | |
| * At least one physical device must support the extension(s) | |
| * The application must select such a physical device | |
| * The application must request the extension(s) be enabled while creating the instance or logical device (This depends on whether or not the given extension works with an instance or a device). | |
| * The instance and/or logical device creation must succeed. | |
| Only then can you expect to properly use a WSI extension in your Vulkan program. | |
| ##### New Extensions | |
| With the ability to expand Vulkan so easily, extensions will be created that the loader knows | |
| nothing about. If the extension is a device extension, the loader will pass the unknown | |
| entry-point down the device call chain ending with the appropriate ICD entry-points. | |
| However, if the extension is an instance extension, the loader will fail to load it. | |
| *But why doesn't the loader support unknown instance extensions?* | |
| <br/> | |
| Let's look again at the Instance call chain: | |
|  | |
| Notice that for a normal instance function call, the loader has to handle passing along the | |
| function call to the available ICDs. If the loader has no idea of the parameters or return | |
| value of the instance call, it can't properly pass information along to the ICDs. | |
| There may be ways to do this, which will be explored in the future. However, for now, this | |
| loader does not support any unknown instance extensions. | |
| Because the device call-chain does not pass through the loader terminator, this is not | |
| a problem for device extensions. Instead, device extensions terminate directly in the | |
| ICD they are associated with. | |
| *Is this a big problem?* | |
| <br/> | |
| No! Most extension functionality only affects a device and not an instance or a physical | |
| device. Thus, the overwhelming majority of extensions will be device extensions rather than | |
| instance extensions. | |
| ## Vulkan Installable Client Driver interface with the loader ## | |
| ### ICD discovery | |
| Vulkan allows multiple drivers each with one or more devices (represented by a | |
| Vulkan VkPhysicalDevice object) to be used collectively. The loader is | |
| responsible for discovering available Vulkan ICDs on the system. Given a list | |
| of available ICDs, the loader can enumerate all the physical devices available | |
| for an application and return this information to the application. The process | |
| in which the loader discovers the available Installable Client Drivers (ICDs) | |
| on a system is platform dependent. Windows, Linux and Android ICD discovery | |
| details are listed below. | |
| #### Windows | |
| ##### Properly-Installed ICDs | |
| In order to find properly-installed ICDs, the Vulkan loader will scan the | |
| values in the following Windows registry key: | |
| HKEY\_LOCAL\_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\Drivers | |
| On 64-bit Windows, when a 32-bit application is triggered, the loader | |
| will scan for 32-bit drivers in a separate area of the registry: | |
| HKEY\_LOCAL\_MACHINE\\SOFTWARE\\WOW6432Node\\Khronos\\Vulkan\\Drivers | |
| For each value in this key which has DWORD data set to 0, the loader opens the | |
| JSON format text information file (a.k.a. "manifest file") specified by the | |
| name of the value. Each name must be a full pathname to the text manifest file. | |
| The Vulkan loader will open each manifest file to obtain the name or pathname | |
| of an ICD shared library (".dll") file. For example: | |
| ``` | |
| { | |
| "file_format_version": "1.0.0", | |
| "ICD": { | |
| "library_path": "path to ICD library", | |
| "api_version": "1.0.5" | |
| } | |
| } | |
| ``` | |
| The "library\_path" specifies either a filename, a relative pathname, or a full | |
| pathname to an ICD shared library file, which the loader will attempt to load | |
| using LoadLibrary(). If the ICD is specified via a filename, the shared library | |
| lives in the system's DLL search path (e.g. in the "C:\Windows\System32" | |
| folder). If the ICD is specified via a relative pathname, it is relative to the | |
| path of the manifest file. Relative pathnames are those that do not start with | |
| a drive specifier (e.g. "C:"), nor with a directory separator (i.e. the '\\' | |
| character), but do contain at least one directory separator. | |
| The "file\_format\_version" specifies a major.minor.patch version number in | |
| case the format of the text information file changes in the future. If the same | |
| ICD shared library supports multiple, incompatible versions of text manifest | |
| file format versions, it must have separate JSON files for each (all of which may | |
| point to the same shared library). | |
| The "api\_version" specifies the major.minor.patch version number of the Vulkan | |
| API that the shared library (referenced by "library\_path") was built with. | |
| There are no rules about the name of the text information files (except the | |
| .json suffix). | |
| There are no rules about the name of the ICD shared library files. For example, | |
| if the registry contains the following values, | |
| ``` | |
| [HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\Drivers\] | |
| "C:\vendor a\vk_vendora.json"=dword:00000000 | |
| "C:\windows\system32\vendorb_vk.json"=dword:00000000 | |
| "C:\windows\system32\vendorc_icd.json"=dword:00000000 | |
| ``` | |
| then the loader will open the following text information files, with the | |
| specified contents: | |
| | Text File Name | Text File Contents | | |
| |----------------|--------------------| | |
| |vk\_vendora.json | "ICD": { "library\_path": "C:\VENDOR A\vk_vendora.dll", "api_version": "1.0.5" } | | |
| | vendorb\_vk.json | "ICD": { "library\_path": "vendorb\_vk.dll", "api_version": "1.0.5" } | | |
| |vendorc\_icd.json | "ICD": { "library\_path": "vedorc\_icd.dll", "api_version": "1.0.5" }| | |
| Then the loader will open the three files mentioned in the "Text File Contents" | |
| column, and then try to load and use the three shared libraries indicated by | |
| the ICD.library\_path value. | |
| ##### Using Pre-Production ICDs | |
| IHV developers (and sometimes other developers) need to use special, | |
| pre-production ICDs. In some cases, a pre-production ICD may be in an | |
| installable package. In other cases, a pre-production ICD may simply be a | |
| shared library in the developer's build tree. In this latter case, we want to | |
| allow developers to point to such an ICD without modifying the | |
| properly-installed ICD(s) on their system. | |
| This need is met with the use of the "VK\_ICD\_FILENAMES" environment variable, | |
| which will override the mechanism used for finding properly-installed ICDs. In | |
| other words, only the ICDs listed in "VK\_ICD\_FILENAMES" will be used. The | |
| "VK\_ICD\_FILENAMES" environment variable is a semi-colon-separated list of ICD | |
| text information files (aka manifest files), containing the following: | |
| - A full pathname (e.g. "C:\\my\_build\\my\_icd.json") | |
| Typically, "VK\_ICD\_FILENAMES" will only contain a full pathname to one info | |
| file for a developer-built ICD. A semi-colon is only used if more than one ICD | |
| is listed. | |
| For example, if a developer wants to refer to one ICD that they built, they | |
| could set the "VK\_ICD\_FILENAMES" environment variable to: | |
| C:\\my\_build\\my\_icd.json | |
| If a developer wants to refer to two ICDs, one of which is a properly-installed | |
| ICD, they can use the full pathname of the text file: | |
| C:\\Windows\\System32\\vendorc\_icd.json;C:\\my\_build\\my\_icd.json | |
| Notice the semi-colon between "C:\\Windows\\System32\\vendorc\_icd.json" and | |
| "C:\\my\_build\\my\_icd.json". | |
| #### Linux | |
| ##### Properly-Installed ICDs | |
| In order to find properly-installed ICDs, the Vulkan loader will scan the files | |
| in the following Linux directories: | |
| /usr/share/vulkan/icd.d | |
| /etc/vulkan/icd.d | |
| $HOME/.local/share/vulkan/icd.d | |
| Where $HOME is the current home directory of the application's user id; this | |
| path will be ignored for suid programs. | |
| These directories will contain text information files (a.k.a. "manifest | |
| files"), that use a JSON format. | |
| The Vulkan loader will open each manifest file found to obtain the name or | |
| pathname of an ICD shared library (".so") file. For example: | |
| ``` | |
| { | |
| "file_format_version": "1.0.0", | |
| "ICD": { | |
| "library_path": "path to ICD library", | |
| "api_version": "1.0.5" | |
| } | |
| } | |
| ``` | |
| The "library\_path" specifies either a filename, a relative pathname, or a full | |
| pathname to an ICD shared library file. If the ICD is specified via a filename, | |
| the loader will attempt to open that file as a shared object using dlopen(), | |
| and the file must be in a directory that dlopen is configured to look in (Note: | |
| various distributions are configured differently). A distribution is free to | |
| create Vulkan-specific system directories (e.g. ".../vulkan/icd"), but is not | |
| required to do so. If the ICD is specified via a relative pathname, it is | |
| relative to the path of the info file. Relative pathnames are those that do not | |
| start with, but do contain at least one directory separator (i.e. the '/' | |
| character). For example, "lib/vendora.so" and "./vendora.so" are examples of | |
| relative pathnames. | |
| The "file\_format\_version" provides a major.minor.patch version number in case | |
| the format of the manifest file changes in the future. If the same ICD shared | |
| library supports multiple, incompatible versions of manifest file format | |
| versions, it must have multiple manifest files (all of which may point to the | |
| same shared library). | |
| The "api\_version" specifies the major.minor.patch version number of the Vulkan | |
| API that the shared library (referenced by "library\_path") was built with. | |
| The "/usr/share/vulkan/icd.d" directory is for ICDs that are installed from | |
| Linux-distribution-provided packages. The "/etc/vulkan/icd.d" directory is for | |
| ICDs that are installed from non-Linux-distribution-provided packages. | |
| There are no rules about the name of the text files (except the .json suffix). | |
| There are no rules about the name of the ICD shared library files. For example, | |
| if the "/usr/share/vulkan/icd.d" directory contain the following files, with | |
| the specified contents: | |
| | Text File Name | Text File Contents | | |
| |-------------------|------------------------| | |
| | vk\_vendora.json | "ICD": { "library\_path": "vendora.so", "api_version": "1.0.5" } | | |
| | vendorb\_vk.json | "ICD": { "library\_path": "vendorb\_vulkan\_icd.so", "api_version": "1.0.5" } | | |
| | vendorc\_icd.json | "ICD": { "library\_path": "/usr/lib/VENDORC/icd.so", "api_version": "1.0.5" } | | |
| then the loader will open the three files mentioned in the "Text File Contents" | |
| column, and then try to load and use the three shared libraries indicated by | |
| the ICD.library\_path value. | |
| ##### Using Pre-Production ICDs | |
| IHV developers (and sometimes other developers) need to use special, | |
| pre-production ICDs. In some cases, a pre-production ICD may be in an | |
| installable package. In other cases, a pre-production ICD may simply be a | |
| shared library in the developer's build tree. In this latter case, we want to | |
| allow developers to point to such an ICD without modifying the | |
| properly-installed ICD(s) on their system. | |
| This need is met with the use of the "VK\_ICD\_FILENAMES" environment variable, | |
| which will override the mechanism used for finding properly-installed ICDs. In | |
| other words, only the ICDs listed in "VK\_ICD\_FILENAMES" will be used. | |
| The "VK\_ICD\_FILENAMES" environment variable is a colon-separated list of ICD | |
| manifest files, containing the following: | |
| - A filename (e.g. "libvkicd.json") in the "/usr/share/vulkan/icd.d", "/etc/vulkan/icd.d" "$HOME/.local/share/vulkan/icd.d" directories | |
| - A full pathname (e.g. "/my\_build/my\_icd.json") | |
| Typically, "VK\_ICD\_FILENAMES" will only contain a full pathname to one info | |
| file for a developer-built ICD. A colon is only used if more than one ICD is | |
| listed. | |
| For example, if a developer wants to refer to one ICD that they built, they | |
| could set the "VK\_ICD\_FILENAMES" environment variable to: | |
| /my\_build/my\_icd.json | |
| If a developer wants to refer to two ICDs, one of which is a properly-installed | |
| ICD, they can use the name of the text file in the system directory: | |
| vendorc\_vulkan.json:/my\_build/my\_icd.json | |
| Notice the colon between "vendorc\_vulkan.json" and "/my\_build/my\_icd.json". | |
| NOTE: this environment variable will be ignored for suid programs. | |
| #### Android | |
| The Android loader lives in the system library folder. The location cannot be | |
| changed. The loader will load the driver/ICD via hw_get_module with the ID | |
| of "vulkan". Due to security policies in Android none of this can be modified | |
| under normal use. | |
| <br/> | |
| ## ICD interface requirements ## | |
| Generally, for all Vulkan commands issued by an application, the loader can be | |
| viewed as a pass through. That is, the loader generally doesn't modify the | |
| commands or their parameters, but simply calls the ICDs entry point for that | |
| command. There are specific additional interface requirements an ICD needs to comply with that | |
| are over and above any requirements from the Vulkan specification including WSI extension specification. | |
| These addtional requirements are versioned to allow flexibility in the future. | |
| These interface requirements will be set forth in the following sections: 1) describing | |
| which "loader-ICD" interface version is available, 2) detailing the most recent interface version; | |
| 3) the supported, older interface requirements will be described as differences | |
| from the most recent interface version. | |
| #### Windows and Linux | |
| ##### Version Negotiation Between Loader and ICDs | |
| All ICDs (supporting interface version 2 or higher) must export the following | |
| function that is used for determination of the interface version that will be used. | |
| This entry point is not a part of the Vulkan API itself, only a private interface | |
| between the loader and ICDs. | |
| VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion); | |
| This entry point reports the "loader-ICD" interface version supported by both the loader and the ICD. | |
| The loader informs the ICD of it's desired interface version (typically the latest) via the | |
| pSupportedVersion parameter. | |
| This call is the first call made by the loader into the ICD (prior to any calls to | |
| vk\_icdGetInstanceProcAddr). | |
| If a loader sees that an ICD does not export this symbol it knows that it's dealing | |
| with a legacy ICD supporting either interface version 0 or 1. | |
| Similarly, if an ICD sees a call to vk\_icdGetInstanceProcAddr before a call to | |
| vk_icdGetLoaderICDInterfaceVersion then it knows that it's dealing with a legacy loader | |
| supporting version 0 or 1. | |
| **Note** if the loader calls vk\_icdGetInstanceProcAddr first it supports at least version 1, | |
| otherwise the loader only supports version 0. | |
| The pSupportedVersion parameter is both an input and output parameter. | |
| It is filled in by the loader before the call with the desired latest interface version supported by the loader. | |
| If the ICD receiving the call no longer supports the interface version provided | |
| by the loader (due to deprecation) then it can report VK_ERROR_INCOMPATIBLE_DRIVER error, | |
| otherwise it sets the value pointed by pSupportedVersion to the latest interface | |
| version supported by both the ICD and the loader and returns VK_SUCCESS. | |
| The ICD should report VK_SUCCESS in case the loader provided interface version | |
| is newer than that supported by the ICD, as it's the loader's responsibility to | |
| determine whether it can support the older interface version supported by the ICD. | |
| The ICD should also report VK_SUCCESS in the case it's interface version is greater | |
| than the loader's, but return the loader's version. Thus, upon return of VK_SUCCESS | |
| the pSupportedVersion will contain the desired interface version to be used by the ICD. | |
| If the loader receives back an interface version from the ICD that the loader no longer | |
| supports (due to deprecation) or it receives a VK_ERROR_INCOMPATIBLE_DRIVER error | |
| instead of VK_SUCCESS then the loader will treat the ICD as incompatible | |
| and will not load it for use. In this case the application will not see the ICDs vkPhysicalDevice | |
| during enumeration. | |
| ##### Loader Version 3 Interface Changes | |
| The primary change occuring in version 3 of the loader/ICD interface is to allow an ICD to | |
| handle Creation/Destruction of their own KHR_surfaces. Up until this point, the loader created | |
| a surface object that was used by all ICDs. However, some ICDs may want to provide their | |
| own surface handles. If an ICD chooses to enable this support, they must export support for | |
| version 3 of the Loader/ICD interface as well as any Vulkan command that uses a KHR_surface handle, | |
| such as: | |
| - vkCreateXXXSurfaceKHR (where XXX is the platform specific identifier [i.e.CreateWin32SurfaceKHR for Windows]) | |
| - vkDestroySurfaceKHR | |
| - vkCreateSwapchainKHR | |
| - vkGetPhysicalDeviceSurfaceSupportKHR | |
| - vkGetPhysicalDeviceSurfaceCapabilitiesKHR | |
| - vkGetPhysicalDeviceSurfaceFormatsKHR | |
| - vkGetPhysicalDeviceSurfacePresentModesKHR | |
| An ICD can still choose to not take advantage of this functionality by simply not exposing the | |
| above the vkCreateXXXSurfaceKHR and vkDestroySurfaceKHR commands. | |
| ##### Loader Version 2 Interface Requirements | |
| Version 2 interface has requirements in three areas: | |
| 1. ICD Vulkan entry point discovery, | |
| 2. KHR_surface related requirements in the WSI extensions, | |
| 3. Vulkan dispatchable object creation requirements. | |
| ###### ICD Vulkan entry point discovery | |
| All ICDs must export the following function that is used for discovery of ICD Vulkan entry points. | |
| This entry point is not a part of the Vulkan API itself, only a private interface between the loader and ICDs for version 1 and higher interfaces. | |
| VKAPI\_ATTR PFN\_vkVoidFunction VKAPI\_CALL vk\_icdGetInstanceProcAddr(VkInstance instance, const char* pName); | |
| This function has very similar semantics to the Vulkan command vkGetInstanceProcAddr. | |
| vk\_icdGetInstanceProcAddr returns valid function pointers for all the global level | |
| and instance level Vulkan commands, and also for vkGetDeviceProcAddr. | |
| Global level commands are those | |
| which contain no dispatchable object as the first parameter, such as | |
| vkCreateInstance and vkEnumerateInstanceExtensionProperties. The ICD must | |
| support querying global level entry points by calling | |
| vk\_icdGetInstanceProcAddr with a NULL VkInstance parameter. Instance level | |
| commands are those that have either VkInstance, or VkPhysicalDevice as the | |
| first parameter dispatchable object. Both core entry points and any instance | |
| extension entry points the ICD supports should be available via | |
| vk\_icdGetInstanceProcAddr. Future Vulkan instance extensions may define and | |
| use new instance level dispatchable objects other than VkInstance and | |
| VkPhysicalDevice, in which case extension entry points using these newly | |
| defined dispatchable objects must be queryable via vk\_icdGetInstanceProcAddr. | |
| All other Vulkan entry points must either NOT be exported from the ICD | |
| library or else NOT use the official Vulkan function names if they are | |
| exported. This requirement is for ICD libraries that include other | |
| functionality (such as OpenGL library) and thus could be loaded by the | |
| application prior to when the Vulkan loader library is loaded by the | |
| application. In other words, the ICD library exported Vulkan symbols must not | |
| clash with the loader's exported Vulkan symbols. | |
| Beware of interposing by dynamic OS library loaders if the official Vulkan | |
| names are used. On Linux, if official names are used, the ICD library must be | |
| linked with -Bsymbolic. | |
| ###### Handling KHR_surface objects in the WSI extensions | |
| Normally, ICDs handle object creation and destruction for various Vulkan | |
| objects. The WSI surface extensions for Linux and Windows | |
| (VK\_KHR\_win32\_surface, VK\_KHR\_xcb\_surface, VK\_KHR\_xlib\_surface, | |
| VK\_KHR\_mir\_surface, VK\_KHR\_wayland\_surface, and VK\_KHR\_surface) are | |
| handled differently. For these extensions, the VkSurfaceKHR object creation and | |
| destruction is handled by the loader as follows: | |
| 1. Loader handles the vkCreate\*SurfaceKHR() and vkDestroySurfaceKHR() | |
| functions including creating/destroying the VkSurfaceKHR object. | |
| 2. VkSurfaceKHR objects have the underlying structure (VkIcdSurface\*) as | |
| defined in include/vulkan/vk\_icd.h. | |
| 3. ICDs can cast any VkSurfaceKHR object to a pointer to the appropriate | |
| VkIcdSurface\* structure. | |
| 4. VkIcdSurface\* structures include VkIcdSurfaceWin32, VkIcdSurfaceXcb, | |
| VkIcdSurfaceXlib, VkIcdSurfaceMir, and VkIcdSurfaceWayland. The first field | |
| in the structure is a VkIcdSurfaceBase enumerant that indicates whether the | |
| surface object is Win32, Xcb, Xlib, Mir, or Wayland. | |
| ###### ICD dispatchable object creation | |
| As previously covered, the loader requires dispatch tables to be accessible | |
| within Vulkan dispatchable objects, which include VkInstance, VkPhysicalDevice, | |
| VkDevice, VkQueue, and VkCommandBuffer. The specific requirements on all | |
| dispatchable objects created by ICDs are as follows: | |
| - All dispatchable objects created by an ICD can be cast to void \*\* | |
| - The loader will replace the first entry with a pointer to the dispatch table | |
| which is owned by the loader. This implies three things for ICD drivers: | |
| 1. The ICD must return a pointer for the opaque dispatchable object handle. | |
| 2. This pointer points to a regular C structure with the first entry being a | |
| pointer. Note: for any C\++ ICD's that implement VK objects directly as C\++ | |
| classes. The C\++ compiler may put a vtable at offset zero if your class is | |
| non-POD due to the use of a virtual function. In this case use a regular C | |
| structure (see below). | |
| 3. The loader checks for a magic value (ICD\_LOADER\_MAGIC) in all the created | |
| dispatchable objects, as follows (see include/vulkan/vk\_icd.h): | |
| ``` | |
| #include "vk_icd.h" | |
| union _VK_LOADER_DATA { | |
| uintptr loadermagic; | |
| void *loaderData; | |
| } VK_LOADER_DATA; | |
| vkObj alloc_icd_obj() | |
| { | |
| vkObj *newObj = alloc_obj(); | |
| ... | |
| // Initialize pointer to loader's dispatch table with ICD_LOADER_MAGIC | |
| set_loader_magic_value(newObj); | |
| ... | |
| return newObj; | |
| } | |
| ``` | |
| ##### Loader Version 0 and 1 Interface Differences | |
| Version 0 and 1 interfaces do not support version negotiation via vk\_icdNegotiateLoaderICDInterfaceVersion. | |
| ICDs can distinguish version 0 and version 1 interfaces as follows: | |
| if the loader calls vk\_icdGetInstanceProcAddr first it supports version 1, | |
| otherwise the loader only supports version 0. | |
| Version 0 interface does not support vk\_icdGetInstanceProcAddr. Version 0 interface requirements for | |
| obtaining ICD Vulkan entry points are as follows: | |
| - vkGetInstanceProcAddr exported in the ICD library and returns valid function | |
| pointers for all the Vulkan API entry points; | |
| - vkCreateInstance exported in the ICD library; | |
| - vkEnumerateInstanceExtensionProperties exported in the ICD library; | |
| Additional Notes: | |
| - The loader will filter out extensions requested in vkCreateInstance and | |
| vkCreateDevice before calling into the ICD; Filtering will be of extensions | |
| advertised by entities (e.g. layers) different from the ICD in question. | |
| - The loader will not call the ICD for vkEnumerate\*LayerProperties() as layer | |
| properties are obtained from the layer libraries and layer JSON files. | |
| - If an ICD library wants to implement a layer it can do so by having the | |
| appropriate layer JSON manifest file refer to the ICD library file. | |
| - The loader will not call the ICD for | |
| vkEnumerate\*ExtensionProperties(pLayerName != NULL). | |
| - ICDs creating new dispatchable objects via device extensions need to initialize | |
| the created dispatchable object. The loader has generic trampoline code for unknown | |
| device extensions. This generic trampoline code doesn't initialize the dispatch table within | |
| the newly created object. See the section for more information on how to initialize created | |
| dispatchable objects for extensions non known by the loader. [layer link](#creating-new-dispatchable-objects) | |
| #### Android | |
| The Android loader uses the same protocol for initializing the dispatch | |
| table as described above. The only difference is that the Android | |
| loader queries layer and extension information directly from the | |
| respective libraries and does not use the json manifest files used | |
| by the Windows and Linux loaders. | |
| <br/> | |
| ## Vulkan layer interface with the loader ## | |
| ### Layer discovery | |
| #### Windows | |
| <a name="ManifestFileExample"></a> | |
| ##### Properly-Installed Layers | |
| In order to find properly-installed layers, the Vulkan loader will use a | |
| similar mechanism as used for ICDs. Text information files (aka manifest | |
| files), that use a JSON format, are read in order 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. Layers and extensions have additional | |
| complexity, and so their manifest files contain more information than ICD info | |
| files. For example, a layer shared library file may contain multiple | |
| layers/extensions (perhaps even an ICD). | |
| In order to find properly-installed layers, the Vulkan loader will scan the | |
| values in the following Windows registry keys: | |
| HKEY\_LOCAL\_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers | |
| HKEY\_LOCAL\_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ImplicitLayers | |
| Explicit layers are those which are enabled by an application (e.g. with the | |
| vkCreateInstance function), or by an environment variable (as mentioned | |
| previously). | |
| Implicit layers are those which are enabled by their existence. For example, | |
| certain application environments (e.g. Steam or an automotive infotainment | |
| system) may have layers which they always want enabled for all applications | |
| that they start. Other implicit layers may be for all applications started on a | |
| given system (e.g. layers that overlay frames-per-second). Implicit layers are | |
| enabled automatically, whereas explicit layers must be enabled explicitly. What | |
| distinguishes a layer as implicit or explicit is by which registry key its | |
| layer information file is referenced by. | |
| 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 a | |
| full pathname to the manifest file. | |
| The Vulkan loader will open each info file to obtain information about the | |
| layer, including the name or pathname of a shared library (".dll") file. | |
| This manifest file is in the JSON format as shown in the following example. | |
| See the section [Layer Library Manifest File](#LayerLibraryManifestFile) for more information about each of the nodes in the JSON file. | |
| ``` | |
| { | |
| "file_format_version" : "1.0.0", | |
| "layer": { | |
| "name": "VK_LAYER_LUNARG_overlay", | |
| "type": "INSTANCE", | |
| "library_path": "vkOverlayLayer.dll" | |
| "api_version" : "1.0.5", | |
| "implementation_version" : "2", | |
| "description" : "LunarG HUD layer", | |
| "functions": { | |
| "vkGetInstanceProcAddr": "OverlayLayer_GetInstanceProcAddr", | |
| "vkGetDeviceProcAddr": "OverlayLayer_GetDeviceProcAddr" | |
| }, | |
| "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": "" | |
| } | |
| } | |
| } | |
| ``` | |
| The "library\_path" specifies either a filename, a relative pathname, or a full | |
| pathname to a layer shared library (".dll") file, which the loader will attempt | |
| to load using LoadLibrary(). If the layer is specified via a relative pathname, | |
| it is relative to the path of the info 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 the layer is specified via a filename, the shared | |
| library lives in the system's DLL search path (e.g. in the | |
| "C:\\Windows\\System32" folder). | |
| If defining multiple layers in a single JSON file prior to "file\_format\_version" | |
| 1.0.1, you would simply define multiple "layer" objects. However, this is not | |
| valid JSON syntax. Instead, you should now define "file\_format\_version" | |
| 1.0.1 (or newer) and use the new "layers" array object as seen in the | |
| following example: | |
| ``` | |
| { | |
| "file_format_version" : "1.0.1", | |
| "layers": [ | |
| { | |
| "name": "VK_LAYER_layer_name1", | |
| "type": "INSTANCE", | |
| ... | |
| }, | |
| { | |
| "name": "VK_LAYER_layer_name2", | |
| "type": "INSTANCE", | |
| ... | |
| } | |
| ] | |
| } | |
| ``` | |
| You could use the "layers" array object to define a single layer, as long as | |
| your "file\_format\_version" is defined to at least 1.0.1. It is functionally the | |
| same as using a single "layer" object. | |
| There are no rules about the name of the text files (except the .json suffix). | |
| There are no rules about the name of the layer shared library files. | |
| ##### Using Pre-Production Layers | |
| As with ICDs, developers may need to use special, pre-production layers, | |
| without modifying the properly-installed layers. This need is met with the use | |
| of the "VK\_LAYER\_PATH" environment variable, which will override the | |
| mechanism using for finding properly-installed layers. Because many layers may | |
| exist on a system, this environment variable is a semi-colon-separated list of | |
| folders that contain layer info files. Only the folder listed in | |
| "VK\_LAYER\_PATH" will be scanned for info files. Each semi-colon-separated | |
| entry is: | |
| - The full pathname of a folder containing layer info files | |
| #### Linux | |
| ##### Properly-Installed Layers | |
| In order to find properly-installed layers, the Vulkan loader will use a | |
| similar mechanism as used for ICDs. Text information files, that use a JSON | |
| format, are read in order to identify the names and attributes of layers and | |
| their extensions. The use of text info files allows the loader to avoid loading | |
| any shared library files when the application does not query nor request any | |
| extensions. Layers and extensions have additional complexity, and so their info | |
| files contain more information than ICD info files. For example, a layer shared | |
| library file may contain multiple layers/extensions (perhaps even an ICD). | |
| The Vulkan loader will scan the files in the following Linux directories: | |
| /usr/share/vulkan/explicit\_layer.d | |
| /usr/share/vulkan/implicit\_layer.d | |
| /etc/vulkan/explicit\_layer.d | |
| /etc/vulkan/implicit\_layer.d | |
| \$HOME/.local/share/vulkan/explicit\_layer.d | |
| \$HOME/.local/share/vulkan/implicit\_layer.d | |
| Where $HOME is the current home directory of the application's user id; this | |
| path will be ignored for suid programs. | |
| Explicit layers are those which are enabled by an application (e.g. with the | |
| vkCreateInstance function), or by an environment variable (as mentioned | |
| previously). Implicit layers are those which are enabled by their existence. | |
| For example, certain application environments (e.g. Steam or an automotive | |
| infotainment system) may have layers which they always want enabled for all | |
| applications that they start. Other implicit layers may be for all applications | |
| started on a given system (e.g. layers that overlay frames-per-second). | |
| Implicit layers are enabled automatically, whereas explicit layers must be | |
| enabled explicitly. What distinguishes a layer as implicit or explicit is by | |
| which directory its layer information file exists in. | |
| The "/usr/share/vulkan/\*\_layer.d" directories are for layers that are | |
| installed from Linux-distribution-provided packages. The | |
| "/etc/vulkan/\*\_layer.d" directories are for layers that are installed from | |
| non-Linux-distribution-provided packages. | |
| This manifest file is in the JSON format as shown in the following example. | |
| See the section [Layer Library Manifest File](#LayerLibraryManifestFile) for more information about each of the nodes in the JSON file. | |
| ``` | |
| { | |
| "file_format_version" : "1.0.0", | |
| "layer": { | |
| "name": "VK_LAYER_LUNARG_overlay", | |
| "type": "INSTANCE", | |
| "library_path": "libvkOverlayLayer.so" | |
| "api_version" : "1.0.5", | |
| "implementation_version" : "2", | |
| "description" : "LunarG HUD layer", | |
| "functions": { | |
| "vkGetInstanceProcAddr": "OverlayLayer_GetInstanceProcAddr", | |
| "vkGetDeviceProcAddr": "OverlayLayer_GetDeviceProcAddr" | |
| }, | |
| "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": "" | |
| } | |
| } | |
| } | |
| ``` | |
| The "library\_path" specifies either a filename, a relative pathname, or a full | |
| pathname to a layer shared library (".so") file, which the loader will attempt | |
| to load using dlopen(). If the layer is specified via a filename, the loader | |
| will attempt to open that file as a shared object using dlopen(), and the file | |
| must be in a directory that dlopen is configured to look in (Note: various | |
| distributions are configured differently). A distribution is free to create | |
| Vulkan-specific system directories (e.g. ".../vulkan/layers"), but is not | |
| required to do so. If the layer is specified via a relative pathname, it is | |
| relative to the path of the info file (e.g. for cases when an application | |
| provides a layer that is in the same directory hierarchy as the rest of the | |
| application files). | |
| There are no rules about the name of the text files (except the .json suffix). | |
| There are no rules about the name of the layer shared library files. | |
| ##### Using Pre-Production Layers | |
| As with ICDs, developers may need to use special, pre-production layers, | |
| without modifying the properly-installed layers. This need is met with the use | |
| of the "VK\_LAYER\_PATH" environment variable, which will override the | |
| mechanism using for finding properly-installed layers. Because many layers may | |
| exist on a system, this environment variable is a colon-separated list of | |
| directories that contain layer info files. Only the directories listed in | |
| "VK\_LAYER\_PATH" will be scanned for info files. Each colon-separated entry | |
| is: | |
| - The full pathname of a directory containing layer info files | |
| NOTE: these environment variables will be ignored for suid programs. | |
| #### Android | |
| The recommended way to enable layers is for applications | |
| to programatically enable them. The layers are provided by the application | |
| and must live in the application's library folder. The application | |
| enables the layers at vkCreateInstance as any Vulkan | |
| application would. | |
| An application enabled for debug has more options. It can enumerate and enable | |
| layers located in /data/local/vulkan/debug. | |
| <br/> | |
| ## Layer interface requirements ## | |
| #### Architectural interface overview | |
| There are two key architectural features that drive the loader to layer library | |
| interface: 1) separate and distinct instance and device call chains, and 2) | |
| distributed dispatch. First these architectural features will be described and | |
| then the detailed interface will be specified. | |
| Call chains are the links of calls for a given Vulkan command from layer module | |
| to layer module with the loader and or the ICD being the bottom most command. | |
| Call chains are constructed at both the instance level and the device level by | |
| the loader with cooperation from the layer libraries. Instance call chains are | |
| constructed by the loader when layers are enabled at vkCreateInstance. Device | |
| call chains are constructed by the loader when layers are enabled, by the loader, at | |
| vkCreateDevice. A layer can intercept Vulkan instance commands, device commands | |
| or both. For a layer to intercept instance commands, it must participate in the | |
| instance call chain. For a layer to intercept device commands, it must | |
| participate in the device chain. | |
| Normally, when a layer intercepts a given Vulkan command, it will call down the | |
| instance or device 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, since | |
| each layer is responsible for properly calling the next entity in the device or | |
| instance chain, a dispatch mechanism is required for all Vulkan commands a | |
| layer intercepts. For Vulkan commands that are not intercepted by a layer, or | |
| if the layer chooses to terminate a given Vulkan command by not calling down | |
| the chain, then no dispatch mechanism is needed for that particular Vulkan | |
| command. Only for those Vulkan commands, which may be a subset of all Vulkan | |
| commands, that a layer intercepts is a dispatching mechanism by the layer | |
| needed. The loader is responsible for dispatching all core and instance | |
| extension Vulkan commands to the first entity in the chain. | |
| Instance level Vulkan commands are those that have the dispatchable objects | |
| VkInstance, or VkPhysicalDevice as the first parameter and also includes | |
| vkCreateInstance. | |
| Device level Vulkan commands are those that use VkDevice, VkQueue or | |
| VkCommandBuffer as the first parameter and also include vkCreateDevice. Future | |
| extensions may introduce new instance or device level dispatchable objects, so | |
| the above lists may be extended in the future. | |
| #### Layer Library Interface | |
| A layer library is a container of layers. This section defines an extensible | |
| interface to discover layers contained in layer libraries. | |
| The extensible programming interface is used on Android only. For Windows and Linux, | |
| the layer manifest JSON files are used. | |
| It also specifies the minimal conventions | |
| and rules a layer must follow. Other sections might have other guidelines that layers should follow. | |
| ##### Layer Conventions and Rules | |
| A layer, when inserted into an otherwise compliant Vulkan implementation, must | |
| still result in a compliant Vulkan implementation[\*]. It must additionally | |
| follow some conventions and rules. | |
| 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 command, 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 | |
| command 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 | |
| should use memory allocators if the layer is intended to run in a production | |
| environment, such as an implicit layer that is always enabled. That will | |
| allow applications to include the layer's memory usage. | |
| `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. The | |
| behavior is undefined. | |
| `vkEnumerateDeviceExtensionProperties` must handle the case where `pLayerName` | |
| is itself. In other cases, it should normally 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 command by returning a local entry point, | |
| otherwise it returns the value obtained by calling down the instance chain. | |
| These commands must be intercepted | |
| - vkGetInstanceProcAddr | |
| - vkCreateInstance | |
| - vkCreateDevice (only required for any device-level chaining) | |
| For compatibility with older layer libraries, | |
| - when `pName` is `vkCreateDevice`, it ignores `instance`. | |
| `vkGetDeviceProcAddr` intercepts a Vulkan command by returning a local entry point, | |
| otherwise it returns the value obtained by calling down the device chain. | |
| The specification requires `NULL` to be returned from `vkGetInstanceProcAddr` and | |
| `vkGetDeviceProcAddr` for disabled commands. A layer may return `NULL` itself or | |
| rely on the following layers to do so. | |
| [\*]: The intention is for layers to have a well-defined baseline behavior. | |
| Some of the conventions or rules, for example, may be considered abuses of the | |
| specification. | |
| ##### Layer Library API Version 0 | |
| A layer library supporting interface version 0 must define and export these | |
| introspection functions, unrelated to any Vulkan command despite the names, | |
| signatures, and other similarities: | |
| - `vkEnumerateInstanceLayerProperties` enumerates all layers in a layer | |
| library. This function never fails. | |
| When a layer library contains only one layer, this function may be an alias | |
| to the layer's `vkEnumerateInstanceLayerProperties`. | |
| - `vkEnumerateInstanceExtensionProperties` enumerates instance extensions of | |
| layers in a layer library. `pLayerName` is always a valid layer name. | |
| This function never fails. | |
| When a layer library contains only one layer, this function may be an alias | |
| to the layer's `vkEnumerateInstanceExtensionProperties`. | |
| - `vkEnumerateDeviceLayerProperties` enumerates a subset (can be full, | |
| proper, or empty subset) of layers in a 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 command interception. | |
| - `vkEnumerateDeviceExtensionProperties` enumerates device extensions of | |
| layers in a layer library. `physicalDevice` is always `VK_NULL_HANDLE`. | |
| `pLayerName` is always a valid layer name. This function never fails. | |
| The introspection functions are not used by the desktop loader. | |
| It must also define and export these functions one for each layer in the library: | |
| - `<layerName>GetInstanceProcAddr(instance, pName)` behaves identically to a layer's vkGetInstanceProcAddr except it is exported. | |
| When a 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 a 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 commands that they do not intercept. They are recommended not to export | |
| any commands. | |
| <a name="LayerLibraryManifestFile"></a> | |
| ##### Layer Library Manifest File Version 0 | |
| On Windows and Linux (desktop), the loader uses manifest files to discover | |
| layer libraries and layers. The desktop loader doesn't directly query the | |
| layer library except during chaining. | |
| On Android, the loader queries the layer libraries via the introspection functions as outlined above. | |
| The layer libraries and the manifest files must be kept in sync. | |
| The following table associates the desktop JSON nodes with the layer library introspection queries. It also indicates requirements. | |
| | Property | JSON node | Introspection query | Notes | | |
| |----------|-----------|-----------------------|-------| | |
| | file version | file_format_version | N/A | one node required per JSON file | | |
| | layers in library | layer | vkEnumerateInstanceLayerProperties | one node required per layer | | |
| | layer name | name | vkEnumerateInstanceLayerProperties | one node is required | | |
| | layer type | type | vkEnumerate*LayerProperties | see Note 1 | | |
| | library location | library_path | N/A | one node is required | | |
| | vulkan spec version | api_version | vkEnumerateInstanceLayerProperties | one node is required | | |
| | layer implementation version | api_version | vkEnumerateInstanceLayerProperties | see Note 2 | | |
| | layer description | description | vkEnumerateInstanceLayerProperties | one node is required | | |
| | chaining functions | functions | vkGet*ProcAddr | see Note 3 | | |
| | instance extensions | instance_extensions | vkEnumerateInstanceExtensionProperties | see Note 4 | | |
| | device extensions | device_extensions | vkEnumerateDeviceExtensionProperties | see Note 5 | | |
| | enable implicit | enable_environment | N/A | See Note 6 | | |
| | disable implicit | enable_environment | N/A | See Note 7 | | |
| "file\_format\_version" is used to indicate the valid JSON syntax of the file. | |
| As nodes are added or deleted which would change the parsing of this file, | |
| the file_format_version should change. This version | |
| is NOT the same as the layer library interface version. The interface version is a superset | |
| of the "file_format_version" and includes the semantics of the nodes in the JSON file. | |
| For interface version 0 the file format version must be "1.0.0" | |
| Note 1: 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 layers. | |
| Allowable values for type (both before and after deprecation) are "INSTANCE", "GLOBAL" and, "DEVICE." | |
| "DEVICE" layers are skipped over by the loader as if they were not found. | |
| Thus, layers must have a type of "GLOBAL" or "INSTANCE" for the loader to include the layer in the enumerated instance layer list. | |
| "library\_path" is the filename, full path, or relative path to the library file. | |
| See [Manifest File Example](#ManifestFileExample) section for more details. | |
| Note 2: One "implementation\_version" node is required per layer. This node gives the layer version, a single number | |
| increasing with backward uncompatible changes. | |
| Note 3: The "functions" node is required if the layer is using alternative | |
| names for vkGetInstanceProcAddr or vkGetDeviceProcAddr. vkGetInstanceProcAddr and vkGetDeviceProcAddr | |
| are required for all layers. See further requirements in the Layer Library API section above. | |
| Note 4: One "instance_extensions" node with an array of one or more elements | |
| 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. | |
| Note 5: One "device_extensions" node with an array of one or more elements | |
| 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 commands, | |
| otherwise this node is not required. | |
| The "entrypoint" node is an array of the names of all entrypoints added by the | |
| supported extension. | |
| ``` | |
| "device_extensions": [ | |
| { | |
| "name": "VK_EXT_debug_marker", | |
| "spec_version": "1", | |
| "entrypoints": ["vkCmdDbgMarkerBegin", "vkCmdDbgMarkerEnd"] | |
| } | |
| ``` | |
| Note 6: The "enable\_environment" node is only for implicit layers only. It is optional for implicit layers. | |
| This node gives an environment variable and value required to enable an implicit layer. This | |
| environment variable (which should vary with each "version" 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). | |
| Note 7: The "disable\_environment" node is only for implicit layers only. It is required for implicit layers. | |
| This node gives an environment variable and value required to disable an implicit layer. In | |
| rare cases of an application not working with an implicit layer, the | |
| application can set this environment variable (before calling Vulkan commands) | |
| in order to "blacklist" the layer. This environment variable (which should vary | |
| with each "version" 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. | |
| #### Layer Dispatch Interface Version 0 | |
| ##### Layer intercept requirements | |
| - Layers intercept a Vulkan command by defining a C/C++ function with signature | |
| identical to the Vulkan API for that command. | |
| - A layer must intercept at least vkGetInstanceProcAddr and | |
| vkCreateInstance. Additionally, a layer would also intercept vkGetDeviceProcAddr and vkCreateDevice to participate in the device chain. | |
| - For any Vulkan command a layer intercepts which has a non-void return value, | |
| an appropriate value must be returned by the layer intercept function. | |
| - The layer intercept function must call down the chain to the corresponding | |
| Vulkan command in the next entity. Undefined results will occur if a layer | |
| doesn't propagate calls down the chain. The two exceptions to this requirement | |
| are vkGetInstanceProcAddr and vkGetDeviceProcAddr which only call down the | |
| chain for Vulkan commands that they do not intercept. | |
| - Layer intercept functions may insert extra calls to Vulkan commands 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. Any additional calls inserted by a layer must be on the same | |
| chain. They should call down the chain. | |
| ##### 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_layer.h). | |
| - A layer can use the VkLayerInstanceDispatchTable structure as a instance | |
| dispatch table (see include/vulkan/vk_layer.h). | |
| - Layers vkGetInstanceProcAddr function uses the next entity's | |
| vkGetInstanceProcAddr to call down the chain for unknown (i.e. non-intercepted) | |
| functions. | |
| - Layers vkGetDeviceProcAddr function uses the next entity's | |
| vkGetDeviceProcAddr to call down the chain for unknown (i.e. non-intercepted) | |
| functions. | |
| ##### 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(NULL, "vkCreateDevice"). | |
| - Advanced the linked list to the next node: pLayerInfo = pLayerInfo->pNext. | |
| - Call down the chain either CreateDevice or CreateInstance | |
| - Initialize your layer dispatch table by calling the next entity's | |
| Get*ProcAddr function once for each Vulkan command needed in your 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 | |
| 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) | |
| { | |
| 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(NULL, "vkCreateDevice"); | |
| if (fpCreateDevice == NULL) { | |
| return VK_ERROR_INITIALIZATION_FAILED; | |
| } | |
| // Advance the link info for the next element on the chain | |
| 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; | |
| } | |
| ``` | |
| #### Special Considerations | |
| ##### Associating private data with Vulkan objects within a layer | |
| A layer may want to associate it's 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 commands that return object handles, the layer saves the handle that is | |
| returned from a lower-level layer (possibly the ICD), and returns its own | |
| handle to the layer above it (possibly the application). For commands that are | |
| given previously-returned handles, the layer unwraps the handle; that is it | |
| looks up the saved handle and gives that to the layer below it. | |
| Layers which wrap objects must ensure they always unwrap objects before passing | |
| them down the chain. This means that the layer must intercept every Vulkan | |
| command which uses the object in question, and wrap or unwrap the object, as | |
| appropriate. This includes adding support for all extensions with commands | |
| using any object the layer wraps. | |
| 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). | |
| <u><b>Cautions</b></u> | |
| 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 commands. If a new extension is created which has | |
| commands that take VkImage objects as parameters, and if the layer does not | |
| support those new commands, an application that uses both the layer and the new | |
| extension will have undefined behavior when those new commands are called (e.g. | |
| the application may crash). This is becaues the lower-level layers and ICD | |
| 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 (e.g. disable layer functionality, stop wrapping objects, issue a | |
| 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 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 ICD) may create a | |
| dispatchable object without loader trampoline code is as follows: | |
| - object wrapping layers that wrap dispatchable objects | |
| - layers which add extensions that create dispatchable objects | |
| - layers which insert extra Vulkan commands in the stream of commands they | |
| intercept from the application | |
| - ICDs which add extensions that create dispatchable objects | |
| The Windows/Linux 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 VkInstanceCreateInfo and 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: | |
| - For CreateInstance the callback structure pointed to by "pNext" is VkLayerInstanceCreateInfo as defined in 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 CreateDevice 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. | |