From 948313be7ed40d9c4953a2613e3cbf25357b0a21 Mon Sep 17 00:00:00 2001 From: Jon Ashburn Date: Wed, 18 May 2016 14:07:47 -0600 Subject: doc: update layer and loader doc for device lyaer deprecation Change-Id: I53ff750a25fd5ea390c22f5ded2247dfbedce2aa --- loader/LoaderAndLayerInterface.md | 102 ++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 54 deletions(-) (limited to 'loader/LoaderAndLayerInterface.md') diff --git a/loader/LoaderAndLayerInterface.md b/loader/LoaderAndLayerInterface.md index 91094a06..d43111b9 100644 --- a/loader/LoaderAndLayerInterface.md +++ b/loader/LoaderAndLayerInterface.md @@ -151,24 +151,26 @@ Vulkan commands, but may offer extensions that do. A common use of layers is for API validation. A developer can use validation layers during application development, but during production the layers can be disabled by the application. Thus, eliminating the overhead of validating the application's -usage of the API. Layers discovered by the loader can be reported to the -application via vkEnumerateInstanceLayerProperties and -vkEnumerateDeviceLayerProperties, for instance and device layers respectively. -Instance layers are enabled at vkCreateInstance; device layers are enabled at -vkCreateDevice. For example, the ppEnabledLayerNames array in the -VkDeviceCreateInfo structure is used by the application to list the device -layer names to be enabled at vkCreateDevice. At vkCreateInstance and +usage of the API. Layers discovered by the loader are reported to the +application via vkEnumerateInstanceLayerProperties. +Layers are enabled at vkCreateInstance and are active for all Vulkan commands +that using the given VkIstance 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 +application specified (enabled) layers. vkCreateDevice will use the layers +specified at vkCreateInstance. vkEnumerateDeviceLayerProperties and +device layers are deprecated. 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. Developers may want to enable layers that are not enabled by the given -application they are using. On Linux and Windows, the environment variables -“VK\_INSTANCE\_LAYERS” and “VK\_DEVICE\_LAYERS” can be used to enable +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/vkCreateDevice. VK\_INSTANCE\_LAYERS is a colon +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 @@ -180,20 +182,13 @@ 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\_param\_checker on Windows or Linux is as follows: +layer VK\_LAYER\_LUNARG\_parameter\_validation on Windows or Linux is as follows: ``` > $ export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_parameter_validation -> $ export VK_DEVICE_LAYERS=VK_LAYER_LUNARG_parameter_validation ``` -**Note**: Many layers, including all LunarG validation layers are “global” -(i.e. both instance and device) layers and *must* be enabled on both the -instance and device chains to function properly. This is required for “global” -layers regardless of which method is used to enable the layer (application or -environment variable). - 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 @@ -745,9 +740,11 @@ version can vary independently for ICDs and layers. - (required) "name" - layer name -- (required) "type" - which layer chains should the layer be activated on. -Allowable values are "INSTANCE", "DEVICE", "GLOBAL". Global means activate on -both device and instance chains. +- (required and deprecated) "type" - which layer chains should the layer be activated on. +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 it's discovery. - (required) "library\_path" - filename / full path / relative path to the library file @@ -793,7 +790,7 @@ implicit layer(s). - (required for implicit layers) "disable\_environment" requirement(s) - environment variable and value required to disable an implicit layer. Note: in rare cases of an application not working with an implicit layer, the -application can set this environment variable (before calling Vulkan functions) +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, as in "DISABLE\_LAYER\_FOO\_1") must be set (not particularly to any value). If both the "enable\_environment" and @@ -805,8 +802,8 @@ For example: { "file_format_version" : "1.0.0", "layer": { - "name": "VK_LAYER_LUNARG_OverlayLayer", - "type": "DEVICE", + "name": "VK_LAYER_LUNARG_overlay", + "type": "INSTANCE", "library_path": "vkOverlayLayer.dll" "api_version" : "1.0.5", "implementation_version" : "2", @@ -914,9 +911,11 @@ version can vary independently for ICDs and layers. - (required) "name" - layer name -- (required) "type" - which layer chains should the layer be activated on. -Allowable values are "INSTANCE", "DEVICE", "GLOBAL". Global means activate on -both device and instance chains. +- (required and deprecated) "type" - which layer chains should the layer be activated on. +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 it's discovery. - (required) "library\_path" - filename / full path / relative path to the text file @@ -960,7 +959,7 @@ implicit layer(s). - (required for implicit layers) "disable\_environment" requirement(s) - environment variable and value required to disable an implicit layer. Note: in rare cases of an application not working with an implicit layer, the -application can set this environment variable (before calling Vulkan functions) +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, as in "DISABLE\_LAYER\_FOO\_1") must be set (not particularly to any value). If both the "enable\_environment" and @@ -971,8 +970,8 @@ For example: { "file_format_version" : "1.0.0", "layer": { - "name": "VK_LAYER_LUNARG_OverlayLayer", - "type": "DEVICE", + "name": "VK_LAYER_LUNARG_overlay", + "type": "INSTANCE", "library_path": "vkOverlayLayer.dll" "api_version" : "1.0.5", "implementation_version" : "2", @@ -1040,7 +1039,7 @@ NOTE: these environment variables will be ignored for suid programs. 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 and vkCreateDevice as any Vulkan +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. @@ -1060,12 +1059,11 @@ 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 at +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. Layers which participate in intercepting calls -in both the instance and device chains are called global layers. +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 @@ -1204,21 +1202,20 @@ The following table associates the desktop JSON nodes with the Android layer lib | Property | JSON node | Android library query | Notes | |----------|-----------|-----------------------|-------| -| layers in library | layer | vkEnumerate*LayerProperties | one node required for each layer in the library | -|layer name | name | vkEnumerate*LayerProperties | one node is required | -| layer type | type | vkEnumerate*LayerProperties | one node is required | +| layers in library | layer | vkEnumerateInstanceLayerProperties | one node required for each layer in the library | +|layer name | name | vkEnumerateInstanceLayerProperties | one node is required | +| layer type | type | vkEnumerateInstanceLayerProperties | one node is required (deprecated) | | library location | library_path | N/A | one node is required | -| vulkan spec version | api_version | vkEnumerate*LayerProperties | one node is required | -| layer implementation version | api_version | vkEnumerate*LayerProperties | one node is required | -| layer description | description | vkEnumerate*LayerProperties | one node is required | +| vulkan spec version | api_version | vkEnumerateInstanceLayerProperties | one node is required | +| layer implementation version | api_version | vkEnumerateInstanceLayerProperties | one node is required | +| layer description | description | vkEnumerateInstanceLayerProperties | one node is required | | chaining functions | functions | vkGet*ProcAddr | see Note 1 | | instance extensions | instance_extensions | vkEnumerateInstanceExtensionProperties | see Note 2 | | device extensions | device_extensions | vkEnumerateDeviceExtensionProperties | see Note 3 | Note 1: The "functions" node is required if the layer is using alternative -names for vkGetInstanceProcAddr or vkGetDeviceProcAddr. vkGetInstanceProcAddr is -required for all layer types. vkGetDeviceProcAddr is required for -device or global (both instance and device) layers. See further requirements below. +names for vkGetInstanceProcAddr or vkGetDeviceProcAddr. vkGetInstanceProcAddr and vkGetDeviceProcAddr +are required for all layers. See further requirements below. Note 2: One "instance_extensions" node with an array of 1 or more elements required if any instance @@ -1252,9 +1249,8 @@ of the "file_format_version" and includes the semantics of the nodes in the JSON vkGetInstanceProcAddr requirements: -Irregardless of the name, this function must be implemented and exported in the library for all layers. --This function must return -the local entry points for all instance level Vulkan commands it intercepts. At -a minimum, this includes vkGetInstanceProcAddr and vkCreateInstance. +-This function must return the local entry points for all instance level Vulkan commands it intercepts. +At a minimum, this includes vkGetInstanceProcAddr and vkCreateInstance. Optionally, this function may return intercepted device level Vulkan commands. -Vulkan commands that a layer doesn't intercept must be passed to the next @@ -1263,10 +1259,8 @@ entity in the chain. That is, the next layer/ICD's GetInstanceProcAddr must be c to NULL for instance level commands it intercepts including vkCreateDevice. VkGetDeviceProcAddr requirements: --Irregardless of the name, a layer intercepting device level Vulkan commands -(aka a device level layer) must implement vkGetDeviceProcAddr type of function. --This vkGetDeviceProcAddr type function must be exported by the layer library. --This function must return the entry points for all device level Vulkan +-Irregardless of the name, this function must be implemented and exported in the library for all layers. +-This function must return the local entry points for all device level Vulkan commands it intercepts. At a minimum, this includes vkGetDeviceProcAddr and vkCreateDevice. -Vulkan commands that a layer doesn't intercept must be passed to the next entity in the chain. That is, the next layer/ICD's GetDeviceProcAddr must be called. @@ -1282,8 +1276,8 @@ All layers within a library must support [`vk_layer.h`][]. - Layers intercept a Vulkan command by defining a C/C++ function with signature identical to the Vulkan API for that command. -- An instance layer must intercept at least vkGetInstanceProcAddr and -vkCreateInstance. A device layer must intercept at least vkGetInstanceProcAddr, vkGetDeviceProcAddr and vkCreateDevice. +- A layer must intercept at least vkGetInstanceProcAddr and +vkCreateInstance. Additionally, a layer would also intercept vkGetDeviceProcAddr and vkCreateDevice to participate in the device chain. - Other than the two vkGet*ProcAddr, all other functions intercepted by a layer need NOT be exported by the layer. - For any Vulkan command a layer intercepts which has a non-void return value, @@ -1374,7 +1368,7 @@ VkResult vkCreateInstance( PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; PFN_vkCreateInstance fpCreateInstance = - (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); + (PFN_vkCreateInstance)fpGetInstanceProcAddr(*pInstance, "vkCreateInstance"); if (fpCreateInstance == NULL) { return VK_ERROR_INITIALIZATION_FAILED; } -- cgit v1.2.3 From cd0fc643d3ceb65af9021a4eb6aca54798bd5e72 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Thu, 19 May 2016 10:45:02 +0800 Subject: docs: update v0 languages for device layer deprecation Clarify that a layer's vkEnumerateInstanceLayerProperties vkEnumerateInstanceExtensionProperties - should enumerate the layer itself vkEnumerateDeviceLayerProperties - is deprecated vkEnumerateDeviceExtensionProperties - must handle all layers by chaining vkCreateInstance - `pNext` handling is covered by the spec vkCreateDevice - allow validation layers to validate layer and extension names Clarify that the layer library's vkEnumerateInstanceLayerProperties vkEnumerateInstanceExtensionProperties - are not used by the desktop loader - can be aliases to the layer's versions when the layer library contains only one layer vkEnumerateDeviceLayerProperties vkEnumerateDeviceExtensionProperties - are not used by the desktop loader vkGetInstanceProcAddr - mention that the special cases for vkCreateDevice and device commands are for compatibility --- loader/LoaderAndLayerInterface.md | 67 +++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 23 deletions(-) (limited to 'loader/LoaderAndLayerInterface.md') diff --git a/loader/LoaderAndLayerInterface.md b/loader/LoaderAndLayerInterface.md index d43111b9..4a986cd5 100644 --- a/loader/LoaderAndLayerInterface.md +++ b/loader/LoaderAndLayerInterface.md @@ -1119,8 +1119,22 @@ 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 `NULL`, usually by chaining to other layers. +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` can intercept a command by returning a function pointer different from what would be returned through chaining. @@ -1128,39 +1142,43 @@ pointer different from what would be returned through chaining. `vkGetDeviceProcAddr` can intercept a command by returning a function pointer different from what would be returned through chaining. -`vkCreateInstance` must not generate an error for unrecognized layer names, -extension names, and `pNext` structs. It may assume the layer names and -extension names have been validated. - -`vkCreateDevice` must not generate an error for unrecognized layer names, -extension names, and `pNext` structs. It may assume the layer names and -extension names have been validated. - [\*]: 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 Interface Version 0 (Android) -An Android layer library supporting interface version 0 must define and export these -functions, unrelated to any Vulkan command despite the names, signatures, and -other similarities: +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. - - `vkEnumerateInstanceLayerProperties` enumerates all instance 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 - instance layers in a layer library. `pLayerName` is always a valid - instance layer name. This function never fails. + layers in a layer library. `pLayerName` is always a valid layer name. + This function never fails. - - `vkEnumerateDeviceLayerProperties` enumerates all device layers in a layer - library. `physicalDevice` is always `VK_NULL_HANDLE`. 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 - device layers in a layer library. `physicalDevice` is always - `VK_NULL_HANDLE`. `pLayerName` is always a valid device layer name. This - function never fails. + 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: - `GetInstanceProcAddr` behaves as if ``'s `vkGetInstanceProcAddr` is called, except @@ -1169,9 +1187,12 @@ other similarities: `vkEnumerateInstanceExtensionProperties`, or `vkEnumerateDeviceLayerProperties` (but _not_ `vkEnumerateDeviceExtensionProperties`), it returns a function pointer to - the function of the same name defined by this interface. + the corresponding introspection function defined by this interface. - when `pName` is `vkGetInstanceProcAddr`, it returns a function pointer to itself. + + For compatibility with older layer libraries, + - when `pName` is `vkCreateDevice`, it ignores `instance`. - when `pName` is a device command defined by Vulkan 1.0 or `VK_KHR_swapchain` (but _not_ other device commands), it may chain to -- cgit v1.2.3 From 0f1cf71df325fb263e3ba192589c2d021e135d30 Mon Sep 17 00:00:00 2001 From: Jon Ashburn Date: Mon, 23 May 2016 13:05:21 -0600 Subject: loader: doc update for merge android and desktop layer interface Change-Id: Ibbffc0bf05bcbd1aa3b9272caa0b2c1c3a54037d --- loader/LoaderAndLayerInterface.md | 335 +++++++++++++------------------------- 1 file changed, 112 insertions(+), 223 deletions(-) (limited to 'loader/LoaderAndLayerInterface.md') diff --git a/loader/LoaderAndLayerInterface.md b/loader/LoaderAndLayerInterface.md index 4a986cd5..69ad7819 100644 --- a/loader/LoaderAndLayerInterface.md +++ b/loader/LoaderAndLayerInterface.md @@ -693,6 +693,7 @@ Vulkan layer interface with the loader #### Windows + ##### Properly-Installed Layers In order to find properly-installed layers, the Vulkan loader will use a @@ -732,71 +733,8 @@ 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 and contains the following -information: - -- (required) "file\_format\_version" - same as for ICDs, except that the format -version can vary independently for ICDs and layers. - -- (required) "name" - layer name - -- (required and deprecated) "type" - which layer chains should the layer be activated on. -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 it's discovery. - -- (required) "library\_path" - filename / full path / relative path to the -library file - -- (required) "api\_version" - same as for ICDs. - -- (required) "implementation\_version" - layer version, a single number -increasing with backward compatible changes. - -- (required) "description" - informative description of the layer. - -- (optional) "device\_extensions" or "instance\_extensions" - array of -extension information as follows - - - (required) extension "name" - Vulkan registered name - - - (required) extension "spec\_version" - extension specification version, a -single number, increasing with backward compatible changes. - - - (required for device\_extensions with entry points) extension -"entrypoints" - array of device extension entry points; not used for instance -extensions - -- (sometimes required) "functions" - mapping list of function entry points. If -multiple layers exist within the same shared library (or if a layer is in the -same shared library as an ICD), this must be specified to allow each layer to -have its own vkGet\*ProcAddr entry points that can be found by the loader. At -this time, only the following two functions are required: - - - "vkGetInstanceProcAddr" name - - - "vkGetDeviceProcAddr" name - -- (optional for implicit layers) "enable\_environment" requirement(s) - -environment variable and value required to enable an implicit layer. This -environment variable (which should vary with each "version" of the layer, as in -"ENABLE\_LAYER\_FOO\_1") 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). - -- (required for implicit layers) "disable\_environment" requirement(s) - -environment variable and value required to disable an implicit layer. Note: 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, as in "DISABLE\_LAYER\_FOO\_1") must be set -(not particularly to any value). If both the "enable\_environment" and -"disable\_environment" variables are set, the implicit layer is disabled. - -For example: +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. ``` { @@ -814,21 +752,24 @@ For example: }, "instance_extensions": [ { - "name": "VK_debug_report_EXT", + "name": "VK_EXT_debug_report", "spec_version": "1" }, { - "name": "VK_VENDOR_DEBUG_X", + "name": "VK_VENDOR_ext_x", "spec_version": "3" } ], "device_extensions": [ { - "name": "VK_DEBUG_MARKER_EXT", + "name": "VK_EXT_debug_marker", "spec_version": "1", "entrypoints": ["vkCmdDbgMarkerBegin", "vkCmdDbgMarkerEnd"] } ], + "enable_environment": { + "ENABLE_LAYER_OVERLAY_1": "1" + } "disable_environment": { "DISABLE_LAYER_OVERLAY_1": "" } @@ -903,76 +844,16 @@ installed from Linux-distribution-provided packages. The "/etc/vulkan/\*\_layer.d" directories are for layers that are installed from non-Linux-distribution-provided packages. -The information file is in the JSON format and contains the following -information: - -- (required) "file\_format\_version" – same as for ICDs, except that the format -version can vary independently for ICDs and layers. - -- (required) "name" - layer name - -- (required and deprecated) "type" - which layer chains should the layer be activated on. -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 it's discovery. - -- (required) "library\_path" - filename / full path / relative path to the text -file - -- (required) "api\_version" – same as for ICDs. - -- (required) "implementation\_version" – layer version, a single number -increasing with backward compatible changes. - -- (required) "description" – informative description of the layer. - -- (optional) "device\_extensions" or "instance\_extensions" - array of -extension information as follows - - - (required) extension "name" - Vulkan registered name +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. - - (required) extension "spec\_version" - extension specification version, a -single number, increasing with backward compatible changes. - - - (required for device extensions with entry points) extension -"entrypoints" - array of device extension entry points; not used for instance -extensions - -- (sometimes required) "functions" - mapping list of function entry points. If -multiple layers exist within the same shared library (or if a layer is in the -same shared library as an ICD), this must be specified to allow each layer to -have its own vkGet\*ProcAddr entry points that can be found by the loader. At -this time, only the following two functions are required: - - "vkGetInstanceProcAddr" name - - "vkGetDeviceProcAddr" name - -- (optional for implicit layers) "enable\_environment" requirement(s) - -environment variable and value required to enable an implicit layer. This -environment variable (which should vary with each "version" of the layer, as in -"ENABLE\_LAYER\_FOO\_1") 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). - -- (required for implicit layers) "disable\_environment" requirement(s) - -environment variable and value required to disable an implicit layer. Note: 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, as in "DISABLE\_LAYER\_FOO\_1") must be set -(not particularly to any value). If both the "enable\_environment" and -"disable\_environment" variables are set, the implicit layer is disabled. - -For example: ``` { "file_format_version" : "1.0.0", "layer": { "name": "VK_LAYER_LUNARG_overlay", "type": "INSTANCE", - "library_path": "vkOverlayLayer.dll" + "library_path": "libvkOverlayLayer.so" "api_version" : "1.0.5", "implementation_version" : "2", "description" : "LunarG HUD layer", @@ -982,21 +863,24 @@ For example: }, "instance_extensions": [ { - "name": "VK_debug_report_EXT", + "name": "VK_EXT_debug_report", "spec_version": "1" }, { - "name": "VK_VENDOR_DEBUG_X", + "name": "VK_VENDOR_ext_x", "spec_version": "3" } ], "device_extensions": [ { - "name": "VK_DEBUG_MARKER_EXT", + "name": "VK_EXT_debug_marker", "spec_version": "1", "entrypoints": ["vkCmdDbgMarkerBegin", "vkCmdDbgMarkerEnd"] } ], + "enable_environment": { + "ENABLE_LAYER_OVERLAY_1": "1" + }, "disable_environment": { "DISABLE_LAYER_OVERLAY_1": "" } @@ -1092,7 +976,7 @@ 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 -manifest file interface or programming interface to discover layers contained in layer libraries. +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. @@ -1136,17 +1020,28 @@ is itself. In other cases, it should normally chain to other layers. extension names. It may assume the layer names and extension names have been validated. -`vkGetInstanceProcAddr` can intercept a command by returning a function -pointer different from what would be returned through chaining. +`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. -`vkGetDeviceProcAddr` can intercept a command by returning a function pointer -different from what would be returned through chaining. +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 Interface Version 0 (Android) +##### 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, @@ -1178,74 +1073,81 @@ signatures, and other similarities: The introspection functions are not used by the desktop loader. -It must also define and export these functions: - - - `GetInstanceProcAddr` behaves as if ``'s - `vkGetInstanceProcAddr` is called, except +It must also define and export these functions one for each layer in the library: - - when `pName` is `vkEnumerateInstanceLayerProperties`, - `vkEnumerateInstanceExtensionProperties`, or - `vkEnumerateDeviceLayerProperties` (but _not_ - `vkEnumerateDeviceExtensionProperties`), it returns a function pointer to - the corresponding introspection function defined by this interface. - - when `pName` is `vkGetInstanceProcAddr`, it returns a function pointer - to itself. - - For compatibility with older layer libraries, - - - when `pName` is `vkCreateDevice`, it ignores `instance`. - - when `pName` is a device command defined by Vulkan 1.0 or - `VK_KHR_swapchain` (but _not_ other device commands), it may chain to - other layers without intercepting. A loader should avoid querying such - device commands. + - `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`. - - `GetDeviceProcAddr` behaves as if ``'s - `vkGetDeviceProcAddr` is called. + - `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 contained layers must support [`vk_layer.h`][]. They do not need to -implement commands that are not queryable. They are recommended not to export -any command. +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. -###### Layer Library Interface Version 0 (Windows and Linux) + +##### 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 directly as outlined above. +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 Android layer library queries. It also indicates requirements. +The following table associates the desktop JSON nodes with the layer library introspection queries. It also indicates requirements. -| Property | JSON node | Android library query | Notes | +| Property | JSON node | Introspection query | Notes | |----------|-----------|-----------------------|-------| -| layers in library | layer | vkEnumerateInstanceLayerProperties | one node required for each layer in the library | -|layer name | name | vkEnumerateInstanceLayerProperties | one node is required | -| layer type | type | vkEnumerateInstanceLayerProperties | one node is required (deprecated) | +| 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 | 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 1 | -| instance extensions | instance_extensions | vkEnumerateInstanceExtensionProperties | see Note 2 | -| device extensions | device_extensions | vkEnumerateDeviceExtensionProperties | see Note 3 | +| 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. -Note 1: The "functions" node is required if the layer is using alternative +"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 below. +are required for all layers. See further requirements in the Layer Library API section above. -Note 2: One "instance_extensions" node with an array of 1 or more elements +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 3: One "device_extensions" node with an array of 1 or more elements +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 @@ -1255,52 +1157,39 @@ must have the node "entrypoints" if the device extension adds Vulkan API command 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"] + } + ``` -The manifest file nodes "file_format_version", "disable_environment", and -"enable_environment" have no corresponding equivalent in the Vulkan API nor -in the Android layer library interface. +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). -"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 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" - -"disable_environment" (required) and "enable_evironment" (optional) are for implicit layers as previously described. - -vkGetInstanceProcAddr requirements: --Irregardless of the name, this function must be implemented and exported in the library for all layers. --This function must return the local entry points for all instance level Vulkan commands it intercepts. -At a minimum, this includes vkGetInstanceProcAddr and vkCreateInstance. -Optionally, this function may return intercepted device level -Vulkan commands. --Vulkan commands that a layer doesn't intercept must be passed to the next -entity in the chain. That is, the next layer/ICD's GetInstanceProcAddr must be called. --Currently this function must be able to handle a VkInstance parameter equal -to NULL for instance level commands it intercepts including vkCreateDevice. - -VkGetDeviceProcAddr requirements: --Irregardless of the name, this function must be implemented and exported in the library for all layers. --This function must return the local entry points for all device level Vulkan -commands it intercepts. At a minimum, this includes vkGetDeviceProcAddr and vkCreateDevice. --Vulkan commands that a layer doesn't intercept must be passed to the next -entity in the chain. That is, the next layer/ICD's GetDeviceProcAddr must be called. - -There are no requirements on the names of the intercepting functions a layer -implements except those listed above for vkGetInstanceProcAddr and -vkGetDeviceProcAddr. Layers do not need to implement commands that are not going to be intercepted. - -All layers within a library must support [`vk_layer.h`][]. -[`vk_layer.h`]: ../include/vulkan/vk_layer.h - -#### Layer intercept requirements +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. -- Other than the two vkGet*ProcAddr, all other functions intercepted by a layer -need NOT be exported by the layer. - 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 @@ -1314,7 +1203,7 @@ 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 +##### 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 @@ -1332,7 +1221,7 @@ functions. vkGetDeviceProcAddr to call down the chain for unknown (i.e. non-intercepted) functions. -#### Layer dispatch initialization +##### Layer dispatch initialization - A layer initializes its instance dispatch table within its vkCreateInstance function. @@ -1374,7 +1263,7 @@ the VkInstanceCreateInfo/VkDeviceCreateInfo structure. Get*ProcAddr function once for each Vulkan command needed in your dispatch table -#### Example code for CreateInstance +##### Example code for CreateInstance ```cpp VkResult vkCreateInstance( @@ -1389,7 +1278,7 @@ VkResult vkCreateInstance( PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; PFN_vkCreateInstance fpCreateInstance = - (PFN_vkCreateInstance)fpGetInstanceProcAddr(*pInstance, "vkCreateInstance"); + (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); if (fpCreateInstance == NULL) { return VK_ERROR_INITIALIZATION_FAILED; } @@ -1415,7 +1304,7 @@ VkResult vkCreateInstance( } ``` -#### Example code for CreateDevice +##### Example code for CreateDevice ```cpp VkResult -- cgit v1.2.3 From a3e077801c33c943553e9de9e7370f93169a0dc8 Mon Sep 17 00:00:00 2001 From: Mark Young Date: Mon, 13 Jun 2016 14:49:53 -0600 Subject: loader: Fix GH607 by adding proper array support JSON spec does not allow objects of the same name at the same level. But, that's what we used to allow with "layer" definitions. Update new file version to 1.0.1, add "layers" array object, and add multiple "layer" definition warning. Change-Id: I040f07897c689800364d243daf3c247f1b3cace7 --- loader/LoaderAndLayerInterface.md | 172 ++++++----- loader/loader.c | 596 ++++++++++++++++++++++---------------- 2 files changed, 445 insertions(+), 323 deletions(-) (limited to 'loader/LoaderAndLayerInterface.md') diff --git a/loader/LoaderAndLayerInterface.md b/loader/LoaderAndLayerInterface.md index 69ad7819..e11923a8 100644 --- a/loader/LoaderAndLayerInterface.md +++ b/loader/LoaderAndLayerInterface.md @@ -738,42 +738,42 @@ See the section [Layer Library Manifest File](#LayerLibraryManifestFile) for mor ``` { -"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": "" - } -} + "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": "" + } + } } ``` @@ -786,6 +786,34 @@ 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. @@ -849,42 +877,42 @@ See the section [Layer Library Manifest File](#LayerLibraryManifestFile) for mor ``` { -"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": "" - } -} + "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 diff --git a/loader/loader.c b/loader/loader.c index 151c7d73..1e74a6d9 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -1798,24 +1798,18 @@ static void loader_add_layer_property_meta( } -/** - * Given a cJSON struct (json) of the top level JSON object from layer manifest - * file, add entry to the layer_list. - * Fill out the layer_properties in this list entry from the input cJSON object. - * - * \returns - * void - * layer_list has a new entry and initialized accordingly. - * If the json input object does not have all the required fields no entry - * is added to the list. - */ -static void -loader_add_layer_properties(const struct loader_instance *inst, - struct loader_layer_list *layer_instance_list, - cJSON *json, bool is_implicit, char *filename) { - /* Fields in layer manifest file that are required: - * (required) “file_format_version” - * following are required in the "layer" object: +static void loader_read_json_layer( + const struct loader_instance *inst, + struct loader_layer_list *layer_instance_list, cJSON *layer_node, + cJSON *item, cJSON *disable_environment, bool is_implicit, char *filename) { + char *temp; + char *name, *type, *library_path, *api_version; + char *implementation_version, *description; + cJSON *ext_item; + VkExtensionProperties ext_prop; + + /* + * The following are required in the "layer" object: * (required) "name" * (required) "type" * (required) “library_path” @@ -1823,40 +1817,8 @@ loader_add_layer_properties(const struct loader_instance *inst, * (required) “implementation_version” * (required) “description” * (required for implicit layers) “disable_environment” - * - * First get all required items and if any missing abort */ - cJSON *item, *layer_node, *ext_item; - char *temp; - char *name, *type, *library_path, *api_version; - char *implementation_version, *description; - cJSON *disable_environment = NULL; - int i, j; - VkExtensionProperties ext_prop; - item = cJSON_GetObjectItem(json, "file_format_version"); - if (item == NULL) { - return; - } - char *file_vers = cJSON_PrintUnformatted(item); - loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, - "Found manifest file %s, version %s", filename, file_vers); - if (strcmp(file_vers, "\"1.0.0\"") != 0) - loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, - "Unexpected manifest file version (expected 1.0.0), may " - "cause errors"); - loader_tls_heap_free(file_vers); - - layer_node = cJSON_GetObjectItem(json, "layer"); - if (layer_node == NULL) { - loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, - "Can't find \"layer\" object in manifest JSON file, " - "skipping this file"); - return; - } - - // loop through all "layer" objects in the file - do { #define GET_JSON_OBJECT(node, var) \ { \ var = cJSON_GetObjectItem(node, #var); \ @@ -1866,7 +1828,7 @@ loader_add_layer_properties(const struct loader_instance *inst, "Didn't find required layer object %s in manifest " \ "JSON file, skipping this layer", \ #var); \ - continue; \ + return; \ } \ } #define GET_JSON_ITEM(node, var) \ @@ -1878,7 +1840,7 @@ loader_add_layer_properties(const struct loader_instance *inst, "Didn't find required layer value %s in manifest JSON " \ "file, skipping this layer", \ #var); \ - continue; \ + return; \ } \ temp = cJSON_Print(item); \ temp[strlen(temp) - 1] = '\0'; \ @@ -1886,94 +1848,91 @@ loader_add_layer_properties(const struct loader_instance *inst, strcpy(var, &temp[1]); \ loader_tls_heap_free(temp); \ } - GET_JSON_ITEM(layer_node, name) - GET_JSON_ITEM(layer_node, type) - GET_JSON_ITEM(layer_node, library_path) - GET_JSON_ITEM(layer_node, api_version) - GET_JSON_ITEM(layer_node, implementation_version) - GET_JSON_ITEM(layer_node, description) - if (is_implicit) { - GET_JSON_OBJECT(layer_node, disable_environment) - } + GET_JSON_ITEM(layer_node, name) + GET_JSON_ITEM(layer_node, type) + GET_JSON_ITEM(layer_node, library_path) + GET_JSON_ITEM(layer_node, api_version) + GET_JSON_ITEM(layer_node, implementation_version) + GET_JSON_ITEM(layer_node, description) + if (is_implicit) { + GET_JSON_OBJECT(layer_node, disable_environment) + } #undef GET_JSON_ITEM #undef GET_JSON_OBJECT - // add list entry - struct loader_layer_properties *props = NULL; - if (!strcmp(type, "DEVICE")) { - loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, - "Device layers are deprecated skipping this layer"); - layer_node = layer_node->next; - continue; - - } - // Allow either GLOBAL or INSTANCE type interchangeably to handle - // layers that must work with older loaders - if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) { - if (layer_instance_list == NULL) { - layer_node = layer_node->next; - continue; - } - props = loader_get_next_layer_property(inst, layer_instance_list); - props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT - : VK_LAYER_TYPE_INSTANCE_EXPLICIT; - } - - if (props == NULL) { + // add list entry + struct loader_layer_properties *props = NULL; + if (!strcmp(type, "DEVICE")) { + loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, + "Device layers are deprecated skipping this layer"); + layer_node = layer_node->next; + return; + } + // Allow either GLOBAL or INSTANCE type interchangeably to handle + // layers that must work with older loaders + if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) { + if (layer_instance_list == NULL) { layer_node = layer_node->next; - continue; + return; } + props = loader_get_next_layer_property(inst, layer_instance_list); + props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT + : VK_LAYER_TYPE_INSTANCE_EXPLICIT; + } - strncpy(props->info.layerName, name, sizeof(props->info.layerName)); - props->info.layerName[sizeof(props->info.layerName) - 1] = '\0'; + if (props == NULL) { + layer_node = layer_node->next; + return; + } - char *fullpath = props->lib_name; - char *rel_base; - if (loader_platform_is_path(library_path)) { - // a relative or absolute path - char *name_copy = loader_stack_alloc(strlen(filename) + 1); - strcpy(name_copy, filename); - rel_base = loader_platform_dirname(name_copy); - loader_expand_path(library_path, rel_base, MAX_STRING_SIZE, - fullpath); - } else { - // a filename which is assumed in a system directory - loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH, - MAX_STRING_SIZE, fullpath); - } - props->info.specVersion = loader_make_version(api_version); - props->info.implementationVersion = atoi(implementation_version); - strncpy((char *)props->info.description, description, - sizeof(props->info.description)); - props->info.description[sizeof(props->info.description) - 1] = '\0'; - if (is_implicit) { - if (!disable_environment || !disable_environment->child) { - loader_log( - inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, - "Didn't find required layer child value disable_environment" - "in manifest JSON file, skipping this layer"); - layer_node = layer_node->next; - continue; - } - strncpy(props->disable_env_var.name, - disable_environment->child->string, - sizeof(props->disable_env_var.name)); - props->disable_env_var - .name[sizeof(props->disable_env_var.name) - 1] = '\0'; - strncpy(props->disable_env_var.value, - disable_environment->child->valuestring, - sizeof(props->disable_env_var.value)); - props->disable_env_var - .value[sizeof(props->disable_env_var.value) - 1] = '\0'; + strncpy(props->info.layerName, name, sizeof(props->info.layerName)); + props->info.layerName[sizeof(props->info.layerName) - 1] = '\0'; + + char *fullpath = props->lib_name; + char *rel_base; + if (loader_platform_is_path(library_path)) { + // a relative or absolute path + char *name_copy = loader_stack_alloc(strlen(filename) + 1); + strcpy(name_copy, filename); + rel_base = loader_platform_dirname(name_copy); + loader_expand_path(library_path, rel_base, MAX_STRING_SIZE, fullpath); + } else { + // a filename which is assumed in a system directory + loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH, + MAX_STRING_SIZE, fullpath); + } + props->info.specVersion = loader_make_version(api_version); + props->info.implementationVersion = atoi(implementation_version); + strncpy((char *)props->info.description, description, + sizeof(props->info.description)); + props->info.description[sizeof(props->info.description) - 1] = '\0'; + if (is_implicit) { + if (!disable_environment || !disable_environment->child) { + loader_log( + inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, + "Didn't find required layer child value disable_environment" + "in manifest JSON file, skipping this layer"); + layer_node = layer_node->next; + return; } + strncpy(props->disable_env_var.name, disable_environment->child->string, + sizeof(props->disable_env_var.name)); + props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] = + '\0'; + strncpy(props->disable_env_var.value, + disable_environment->child->valuestring, + sizeof(props->disable_env_var.value)); + props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] = + '\0'; + } /** - * Now get all optional items and objects and put in list: - * functions - * instance_extensions - * device_extensions - * enable_environment (implicit layers only) - */ +* Now get all optional items and objects and put in list: +* functions +* instance_extensions +* device_extensions +* enable_environment (implicit layers only) +*/ #define GET_JSON_OBJECT(node, var) \ { var = cJSON_GetObjectItem(node, #var); } #define GET_JSON_ITEM(node, var) \ @@ -1988,133 +1947,251 @@ loader_add_layer_properties(const struct loader_instance *inst, } \ } - cJSON *instance_extensions, *device_extensions, *functions, - *enable_environment; - cJSON *entrypoints; - char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *spec_version; - char **entry_array; - vkGetInstanceProcAddr = NULL; - vkGetDeviceProcAddr = NULL; - spec_version = NULL; - entrypoints = NULL; - entry_array = NULL; - /** - * functions - * vkGetInstanceProcAddr - * vkGetDeviceProcAddr - */ - GET_JSON_OBJECT(layer_node, functions) - if (functions != NULL) { - GET_JSON_ITEM(functions, vkGetInstanceProcAddr) - GET_JSON_ITEM(functions, vkGetDeviceProcAddr) - if (vkGetInstanceProcAddr != NULL) - strncpy(props->functions.str_gipa, vkGetInstanceProcAddr, - sizeof(props->functions.str_gipa)); - props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = - '\0'; - if (vkGetDeviceProcAddr != NULL) - strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr, - sizeof(props->functions.str_gdpa)); - props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = - '\0'; - } - /** - * instance_extensions - * array of - * name - * spec_version - */ - GET_JSON_OBJECT(layer_node, instance_extensions) - if (instance_extensions != NULL) { - int count = cJSON_GetArraySize(instance_extensions); - for (i = 0; i < count; i++) { - ext_item = cJSON_GetArrayItem(instance_extensions, i); - GET_JSON_ITEM(ext_item, name) - GET_JSON_ITEM(ext_item, spec_version) - if (name != NULL) { - strncpy(ext_prop.extensionName, name, - sizeof(ext_prop.extensionName)); - ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = - '\0'; - } - ext_prop.specVersion = atoi(spec_version); - bool ext_unsupported = - wsi_unsupported_instance_extension(&ext_prop); - if (!ext_unsupported) { - loader_add_to_ext_list( - inst, &props->instance_extension_list, 1, &ext_prop); - } + cJSON *instance_extensions, *device_extensions, *functions, + *enable_environment; + cJSON *entrypoints; + char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *spec_version; + char **entry_array; + vkGetInstanceProcAddr = NULL; + vkGetDeviceProcAddr = NULL; + spec_version = NULL; + entrypoints = NULL; + entry_array = NULL; + int i, j; + + /** + * functions + * vkGetInstanceProcAddr + * vkGetDeviceProcAddr + */ + GET_JSON_OBJECT(layer_node, functions) + if (functions != NULL) { + GET_JSON_ITEM(functions, vkGetInstanceProcAddr) + GET_JSON_ITEM(functions, vkGetDeviceProcAddr) + if (vkGetInstanceProcAddr != NULL) + strncpy(props->functions.str_gipa, vkGetInstanceProcAddr, + sizeof(props->functions.str_gipa)); + props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0'; + if (vkGetDeviceProcAddr != NULL) + strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr, + sizeof(props->functions.str_gdpa)); + props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0'; + } + /** + * instance_extensions + * array of + * name + * spec_version + */ + GET_JSON_OBJECT(layer_node, instance_extensions) + if (instance_extensions != NULL) { + int count = cJSON_GetArraySize(instance_extensions); + for (i = 0; i < count; i++) { + ext_item = cJSON_GetArrayItem(instance_extensions, i); + GET_JSON_ITEM(ext_item, name) + GET_JSON_ITEM(ext_item, spec_version) + if (name != NULL) { + strncpy(ext_prop.extensionName, name, + sizeof(ext_prop.extensionName)); + ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = + '\0'; + } + ext_prop.specVersion = atoi(spec_version); + bool ext_unsupported = + wsi_unsupported_instance_extension(&ext_prop); + if (!ext_unsupported) { + loader_add_to_ext_list(inst, &props->instance_extension_list, 1, + &ext_prop); } } - /** - * device_extensions - * array of - * name - * spec_version - * entrypoints - */ - GET_JSON_OBJECT(layer_node, device_extensions) - if (device_extensions != NULL) { - int count = cJSON_GetArraySize(device_extensions); - for (i = 0; i < count; i++) { - ext_item = cJSON_GetArrayItem(device_extensions, i); - GET_JSON_ITEM(ext_item, name) - GET_JSON_ITEM(ext_item, spec_version) - if (name != NULL) { - strncpy(ext_prop.extensionName, name, - sizeof(ext_prop.extensionName)); - ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = - '\0'; - } - ext_prop.specVersion = atoi(spec_version); - // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints"); - GET_JSON_OBJECT(ext_item, entrypoints) - int entry_count; - if (entrypoints == NULL) { - loader_add_to_dev_ext_list(inst, - &props->device_extension_list, - &ext_prop, 0, NULL); - continue; - } - entry_count = cJSON_GetArraySize(entrypoints); - if (entry_count) - entry_array = (char **)loader_stack_alloc(sizeof(char *) * - entry_count); - for (j = 0; j < entry_count; j++) { - ext_item = cJSON_GetArrayItem(entrypoints, j); - if (ext_item != NULL) { - temp = cJSON_Print(ext_item); - temp[strlen(temp) - 1] = '\0'; - entry_array[j] = loader_stack_alloc(strlen(temp) + 1); - strcpy(entry_array[j], &temp[1]); - loader_tls_heap_free(temp); - } - } + } + /** + * device_extensions + * array of + * name + * spec_version + * entrypoints + */ + GET_JSON_OBJECT(layer_node, device_extensions) + if (device_extensions != NULL) { + int count = cJSON_GetArraySize(device_extensions); + for (i = 0; i < count; i++) { + ext_item = cJSON_GetArrayItem(device_extensions, i); + GET_JSON_ITEM(ext_item, name) + GET_JSON_ITEM(ext_item, spec_version) + if (name != NULL) { + strncpy(ext_prop.extensionName, name, + sizeof(ext_prop.extensionName)); + ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = + '\0'; + } + ext_prop.specVersion = atoi(spec_version); + // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints"); + GET_JSON_OBJECT(ext_item, entrypoints) + int entry_count; + if (entrypoints == NULL) { loader_add_to_dev_ext_list(inst, &props->device_extension_list, - &ext_prop, entry_count, entry_array); + &ext_prop, 0, NULL); + continue; } - } - if (is_implicit) { - GET_JSON_OBJECT(layer_node, enable_environment) - - // enable_environment is optional - if (enable_environment) { - strncpy(props->enable_env_var.name, - enable_environment->child->string, - sizeof(props->enable_env_var.name)); - props->enable_env_var - .name[sizeof(props->enable_env_var.name) - 1] = '\0'; - strncpy(props->enable_env_var.value, - enable_environment->child->valuestring, - sizeof(props->enable_env_var.value)); - props->enable_env_var - .value[sizeof(props->enable_env_var.value) - 1] = '\0'; + entry_count = cJSON_GetArraySize(entrypoints); + if (entry_count) + entry_array = + (char **)loader_stack_alloc(sizeof(char *) * entry_count); + for (j = 0; j < entry_count; j++) { + ext_item = cJSON_GetArrayItem(entrypoints, j); + if (ext_item != NULL) { + temp = cJSON_Print(ext_item); + temp[strlen(temp) - 1] = '\0'; + entry_array[j] = loader_stack_alloc(strlen(temp) + 1); + strcpy(entry_array[j], &temp[1]); + loader_tls_heap_free(temp); + } } + loader_add_to_dev_ext_list(inst, &props->device_extension_list, + &ext_prop, entry_count, entry_array); + } + } + if (is_implicit) { + GET_JSON_OBJECT(layer_node, enable_environment) + + // enable_environment is optional + if (enable_environment) { + strncpy(props->enable_env_var.name, + enable_environment->child->string, + sizeof(props->enable_env_var.name)); + props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] = + '\0'; + strncpy(props->enable_env_var.value, + enable_environment->child->valuestring, + sizeof(props->enable_env_var.value)); + props->enable_env_var + .value[sizeof(props->enable_env_var.value) - 1] = '\0'; } + } #undef GET_JSON_ITEM #undef GET_JSON_OBJECT - layer_node = layer_node->next; - } while (layer_node != NULL); +} + +/** + * Given a cJSON struct (json) of the top level JSON object from layer manifest + * file, add entry to the layer_list. Fill out the layer_properties in this list + * entry from the input cJSON object. + * + * \returns + * void + * layer_list has a new entry and initialized accordingly. + * If the json input object does not have all the required fields no entry + * is added to the list. + */ +static void +loader_add_layer_properties(const struct loader_instance *inst, + struct loader_layer_list *layer_instance_list, + cJSON *json, bool is_implicit, char *filename) { + /* Fields in layer manifest file that are required: + * (required) “file_format_version” + * + * If more than one "layer" object are to be used, use the "layers" array instead. + * + * First get all required items and if any missing abort + */ + + cJSON *item, *layers_node, *layer_node; + uint16_t file_major_vers = 0; + uint16_t file_minor_vers = 0; + uint16_t file_patch_vers = 0; + char *vers_tok; + cJSON *disable_environment = NULL; + item = cJSON_GetObjectItem(json, "file_format_version"); + if (item == NULL) { + return; + } + char *file_vers = cJSON_PrintUnformatted(item); + loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, + "Found manifest file %s, version %s", filename, file_vers); + // Get the major/minor/and patch as integers for easier comparison + vers_tok = strtok(file_vers, ".\"\n\r"); + if (NULL != vers_tok) { + file_major_vers = atoi(vers_tok); + vers_tok = strtok(NULL, ".\"\n\r"); + if (NULL != vers_tok) { + file_minor_vers = atoi(vers_tok); + vers_tok = strtok(NULL, ".\"\n\r"); + if (NULL != vers_tok) { + file_patch_vers = atoi(vers_tok); + } + } + } + if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) { + loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, + "%s Unexpected manifest file version (expected 1.0.0 or " + "1.0.1), may cause errors", + filename); + } + loader_tls_heap_free(file_vers); + // If "layers" is present, read in the array of layer objects + layers_node = cJSON_GetObjectItem(json, "layers"); + if (layers_node != NULL) { + int numItems = cJSON_GetArraySize(layers_node); + if (file_major_vers == 1 && file_minor_vers == 0 && + file_patch_vers == 0) { + loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, + "\"layers\" tag not officially added until file version " + "1.0.1, but %s is reporting version %s", + filename, file_vers); + } + for (int curLayer = 0; curLayer < numItems; curLayer++) { + layer_node = cJSON_GetArrayItem(layers_node, curLayer); + if (layer_node == NULL) { + loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, + "Can't find \"layers\" array element %d object in " + "manifest JSON file %s, skipping this file", + curLayer, filename); + return; + } + loader_read_json_layer(inst, layer_instance_list, layer_node, item, + disable_environment, is_implicit, filename); + } + } else { + // Otherwise, try to read in individual layers + layer_node = cJSON_GetObjectItem(json, "layer"); + if (layer_node == NULL) { + loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, + "Can't find \"layer\" object in manifest JSON file %s, " + "skipping this file", + filename); + return; + } + // Loop through all "layer" objects in the file to get a count of them + // first. + uint16_t layer_count = 0; + cJSON *tempNode = layer_node; + do { + tempNode = tempNode->next; + layer_count++; + } while (tempNode != NULL); + /* + * Throw a warning if we encounter multiple "layer" objects in file + * versions newer than 1.0.0. Having multiple objects with the same + * name at the same level is actually a JSON standard violation. + */ + if (layer_count > 1 && + (file_major_vers > 1 || + !(file_minor_vers == 0 && file_patch_vers == 0))) { + loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, + "Multiple \"layer\" nodes are deprecated starting in " + "file version \"1.0.1\". Please use \"layers\" : [] " + "array instead in %s.", + filename); + } else { + do { + loader_read_json_layer(inst, layer_instance_list, layer_node, + item, disable_environment, is_implicit, + filename); + layer_node = layer_node->next; + } while (layer_node != NULL); + } + } return; } @@ -2373,6 +2450,10 @@ void loader_destroy_icd_lib_list() {} void loader_icd_scan(const struct loader_instance *inst, struct loader_icd_libs *icds) { char *file_str; + uint16_t file_major_vers = 0; + uint16_t file_minor_vers = 0; + uint16_t file_patch_vers = 0; + char *vers_tok; struct loader_manifest_files manifest_files; loader_scanned_icd_init(inst, icds); @@ -2399,11 +2480,24 @@ void loader_icd_scan(const struct loader_instance *inst, return; } char *file_vers = cJSON_Print(item); + // Get the major/minor/and patch as integers for easier comparison + vers_tok = strtok(file_vers, ".\"\n\r"); + if (NULL != vers_tok) { + file_major_vers = atoi(vers_tok); + vers_tok = strtok(NULL, ".\"\n\r"); + if (NULL != vers_tok) { + file_minor_vers = atoi(vers_tok); + vers_tok = strtok(NULL, ".\"\n\r"); + if (NULL != vers_tok) { + file_patch_vers = atoi(vers_tok); + } + } + } loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Found manifest file %s, version %s", file_str, file_vers); - if (strcmp(file_vers, "\"1.0.0\"") != 0) + if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, - "Unexpected manifest file version (expected 1.0.0), may " + "Unexpected manifest file version (expected 1.0.0 or 1.0.1), may " "cause errors"); loader_tls_heap_free(file_vers); itemICD = cJSON_GetObjectItem(json, "ICD"); -- cgit v1.2.3